Discussion:
[PATCH weston-ivi-shell 00/15] a reference shell for In-Vehicle Infotainment system
nobuhiko_tanibata
2014-03-06 09:19:01 UTC
Permalink
Hi,

This patch series adds a reference implementation of a shell for
In-Vehicle Infotainment system; IVI, libraries on the shell to manage
layout of User interface; UI, and samples how to use them. Before
stepping in overview of patches, please let me explain background and
purpose of this contribution.

Background)
I am working for prototyping a shell for In-Vehicle Infotainment; IVI in
TIZEN IVI. This prototyping is being integrated to the TIZEN IVI.

https://review.tizen.org/git/?p=profile/ivi/weston-ivi-shell.git;a=summary

I am also working for GENIVI wayland-ivi-extension and several private
projects with several Car Makers to apply a shell to its use case. The
main use case on them is very similar with each other, which is based on
a concept of Layer Management.

http://projects.genivi.org/ivi-layer-management/node/13

Purpose)
I am contributing a reference for common use case of IVI mentioned in
Background to avoid implementing same one for each user. The main use
case is Layer Management to manage properties of surfaces and layer.
Layer is used for grouping surfaces. In this patch series, I am
contributing libweston-layout.so to support Layer management features
with a set of interfaces which are defined based on ivi-layer-management
from GENIVI. With libweston-layout.so, each shell developer of IVI can
easily implement own shell.

Overview)
This patch series are mainly applied to new folder ?ivi-shell? like
?desktop-shell?. This patch series consists of 5 major parts,

- ivi-shell.so : support ivi-application.xml protocol and initialization
of libweston-layout.so. The ivi-application.xml defines simple
interfaces; ?ivi_application::surface_create?. An interface
ivi_application::surface_create? is used to tie ID to wl_surface from
application. In IVI use case, such IDs are predefined at system design
phase to control surface with business logic. For example, TV
application shall be invisible in case of speed restriction.

- libweston-layout.so: this shall be linked to ivi-shell.so to support
layer management APIs internally. These APIs allows us to manage
surfaces and layer by e.g. setting properties; position, visibility,
opacity and rectangle of source to crop, and so on. This APIs internally
uses weston_view as abstraction layer of compositor.

- hmi-controller.so: a reference implementation how to use
libweston-layout.so. It implement several protocols defined by
ivi-hmi-controller.xml,

1/Requesting which surface is a part of User interfaces, e.g. a surface
draw an icon from PNG files. According to request, hmi-controller
layouts specified surfaces on a Screen by using libweston-layout.so.
2/Requesting layout change. There are 4 types of layout for a reference;
tiling, side by side, full screen, and random.
3/Requesting displaying launchers. There are several pages to group
icons which can be selected by motion of input.
4/Requesting animation moving from one page to another by motion of
input.
A reference how to use these protocols are implemented in
hmi-controller-homescreen. A pthread sets up parts of UI and triggers
layout change, showing launchers, and allowing hmi-controller to select
pages of launchers by using ivi-hmi-controller.xml. This can be
implemented in separated process, e.g. desktop-shell.c, as well.

- Supporting ivi-application protocol to example in ?clients? folder.
Add macro to compile ivi-application separately. Basically it uses the
same code. For example, add macro: ENABLE_IVI_CLIENT to simple-egl.c for
compiling weston-simple-egl-ivi at the same time.

- Add reference weston.ini.in for ivi-shell in ivi-shell folder as well.
It is referred by ivi-shell and hmi-controller.so to define several
configurations. E.g. setting cursor, ID of surfaces and layers to be
used by hmi-controller-homescreen, launchers; path to icons, binary, ID
which page they are located.


I am enclosing a pdf for overview of ivi-shell related parts. The pdf
also mentions ivi-controller.so maintained here to keep compatibility
with IVI layer manager.

http://git.projects.genivi.org/?p=wayland-ivi-extension.git;a=summary

It allow GENIVI graphic application to manage surfaces/layer outside of
Weston process. However it is not purpose to do animation. Ideally,
business logic shall be implemented inside of Weston process to reduce
dispatch of process as much as possible.


Best regards,
Nobuhiko
-------------- next part --------------
A non-text attachment was scrubbed...
Name: weston_ivi_shell_contribution.pdf
Type: application/pdf
Size: 103516 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20140306/f4f60a84/attachment-0001.pdf>
Nobuhiko Tanibata
2014-03-06 09:51:15 UTC
Permalink
From: Kristian H?gsberg <krh at bitplanet.net>

---
src/compositor.h | 3 +++
src/gl-renderer.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 57 insertions(+)

diff --git a/src/compositor.h b/src/compositor.h
index 22a485f..ace75da 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -540,6 +540,9 @@ struct weston_renderer {
pixman_format_code_t format, void *pixels,
uint32_t x, uint32_t y,
uint32_t width, uint32_t height);
+ int (*read_surface_pixels)(struct weston_surface *es,
+ pixman_format_code_t format, void *pixels,
+ int x, int y, int width, int height);
void (*repaint_output)(struct weston_output *output,
pixman_region32_t *output_damage);
void (*flush_damage)(struct weston_surface *surface);
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 0e5afbe..dca2e05 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -106,6 +106,8 @@ struct gl_renderer {
EGLContext egl_context;
EGLConfig egl_config;

+ GLuint fbo;
+
struct wl_array vertices;
struct wl_array vtxcnt;

@@ -585,6 +587,54 @@ out:
pixman_region32_fini(&repaint);
}

+static int
+gl_renderer_read_surface_pixels(struct weston_surface *es,
+ pixman_format_code_t format, void *pixels,
+ int x, int y, int width, int height)
+{
+ struct weston_buffer *buffer = es->buffer_ref.buffer;
+ struct weston_compositor *ec = es->compositor;
+ struct gl_renderer *gr = get_renderer(ec);
+ struct gl_surface_state *gs = get_surface_state(es);
+ GLenum gl_format;
+ int size;
+ struct wl_shm_buffer *shm_buffer = NULL;
+
+ switch (format) {
+ case PIXMAN_a8r8g8b8:
+ gl_format = GL_BGRA_EXT;
+ break;
+ case PIXMAN_a8b8g8r8:
+ gl_format = GL_RGBA;
+ break;
+ default:
+ return -1;
+ }
+
+ if (buffer) {
+ shm_buffer = wl_shm_buffer_get(buffer->resource);
+ }
+ if (shm_buffer) {
+ size = buffer->width * 4 * buffer->height;
+ memcpy(pixels, wl_shm_buffer_get_data(shm_buffer), size);
+ } else {
+ if (gr->fbo == 0)
+ glGenFramebuffers(1, &gr->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, gr->fbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ gs->textures[0], 0);
+
+ glReadPixels(x, y, width, height,
+ gl_format, GL_UNSIGNED_BYTE, pixels);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+
+ return 0;
+}
+
static void
repaint_views(struct weston_output *output, pixman_region32_t *damage)
{
@@ -1602,6 +1652,9 @@ gl_renderer_destroy(struct weston_compositor *ec)

wl_signal_emit(&gr->destroy_signal, gr);

+ if (gr->fbo)
+ glDeleteFramebuffers(1, &gr->fbo);
+
if (gr->has_bind_display)
gr->unbind_display(gr->egl_display, ec->wl_display);

@@ -1699,6 +1752,7 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
return -1;

gr->base.read_pixels = gl_renderer_read_pixels;
+ gr->base.read_surface_pixels = gl_renderer_read_surface_pixels;
gr->base.repaint_output = gl_renderer_repaint_output;
gr->base.flush_damage = gl_renderer_flush_damage;
gr->base.attach = gl_renderer_attach;
--
1.8.3.1
Pekka Paalanen
2014-03-10 08:10:22 UTC
Permalink
On Thu, 6 Mar 2014 18:51:15 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> From: Kristian H?gsberg <krh at bitplanet.net>
>
> ---
> src/compositor.h | 3 +++
> src/gl-renderer.c | 54
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files
> changed, 57 insertions(+)
>
> diff --git a/src/compositor.h b/src/compositor.h
> index 22a485f..ace75da 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -540,6 +540,9 @@ struct weston_renderer {
> pixman_format_code_t format, void
> *pixels, uint32_t x, uint32_t y,
> uint32_t width, uint32_t height);
> + int (*read_surface_pixels)(struct weston_surface *es,
> + pixman_format_code_t format, void
> *pixels,
> + int x, int y, int width, int
> height); void (*repaint_output)(struct weston_output *output,
> pixman_region32_t *output_damage);
> void (*flush_damage)(struct weston_surface *surface);
> diff --git a/src/gl-renderer.c b/src/gl-renderer.c
> index 0e5afbe..dca2e05 100644
> --- a/src/gl-renderer.c
> +++ b/src/gl-renderer.c
> @@ -106,6 +106,8 @@ struct gl_renderer {
> EGLContext egl_context;
> EGLConfig egl_config;
>
> + GLuint fbo;
> +
> struct wl_array vertices;
> struct wl_array vtxcnt;
>
> @@ -585,6 +587,54 @@ out:
> pixman_region32_fini(&repaint);
> }
>
> +static int
> +gl_renderer_read_surface_pixels(struct weston_surface *es,
> + pixman_format_code_t format, void
> *pixels,
> + int x, int y, int width, int height)
> +{
> + struct weston_buffer *buffer = es->buffer_ref.buffer;
> + struct weston_compositor *ec = es->compositor;
> + struct gl_renderer *gr = get_renderer(ec);
> + struct gl_surface_state *gs = get_surface_state(es);
> + GLenum gl_format;
> + int size;
> + struct wl_shm_buffer *shm_buffer = NULL;
> +
> + switch (format) {
> + case PIXMAN_a8r8g8b8:
> + gl_format = GL_BGRA_EXT;
> + break;
> + case PIXMAN_a8b8g8r8:
> + gl_format = GL_RGBA;
> + break;
> + default:
> + return -1;
> + }
> +
> + if (buffer) {
> + shm_buffer = wl_shm_buffer_get(buffer->resource);
> + }
> + if (shm_buffer) {
> + size = buffer->width * 4 * buffer->height;
> + memcpy(pixels, wl_shm_buffer_get_data(shm_buffer),
> size);

This branch completely ignores format, x, y, width, and height function
parameters, most likely corrupting random memory. This also assumes 4
bytes per pixel in the shm_buffer, which may not be true.


Thanks,
pq

> + } else {
> + if (gr->fbo == 0)
> + glGenFramebuffers(1, &gr->fbo);
> + glBindFramebuffer(GL_FRAMEBUFFER, gr->fbo);
> + glFramebufferTexture2D(GL_FRAMEBUFFER,
> + GL_COLOR_ATTACHMENT0,
> + GL_TEXTURE_2D,
> + gs->textures[0], 0);
> +
> + glReadPixels(x, y, width, height,
> + gl_format, GL_UNSIGNED_BYTE, pixels);
> +
> + glBindFramebuffer(GL_FRAMEBUFFER, 0);
> + }
> +
> + return 0;
> +}
> +
> static void
> repaint_views(struct weston_output *output, pixman_region32_t
> *damage) {
> @@ -1602,6 +1652,9 @@ gl_renderer_destroy(struct weston_compositor
> *ec)
> wl_signal_emit(&gr->destroy_signal, gr);
>
> + if (gr->fbo)
> + glDeleteFramebuffers(1, &gr->fbo);
> +
> if (gr->has_bind_display)
> gr->unbind_display(gr->egl_display, ec->wl_display);
>
> @@ -1699,6 +1752,7 @@ gl_renderer_create(struct weston_compositor
> *ec, EGLNativeDisplayType display, return -1;
>
> gr->base.read_pixels = gl_renderer_read_pixels;
> + gr->base.read_surface_pixels =
> gl_renderer_read_surface_pixels; gr->base.repaint_output =
> gl_renderer_repaint_output; gr->base.flush_damage =
> gl_renderer_flush_damage; gr->base.attach = gl_renderer_attach;
Nobuhiko Tanibata
2014-03-12 14:46:35 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- gl_renderer_read_shmbuffer_pixels to support different types of format of
shmbuffer.

src/compositor.h | 3 ++
src/gl-renderer.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 117 insertions(+)

diff --git a/src/compositor.h b/src/compositor.h
index 22a485f..ace75da 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -540,6 +540,9 @@ struct weston_renderer {
pixman_format_code_t format, void *pixels,
uint32_t x, uint32_t y,
uint32_t width, uint32_t height);
+ int (*read_surface_pixels)(struct weston_surface *es,
+ pixman_format_code_t format, void *pixels,
+ int x, int y, int width, int height);
void (*repaint_output)(struct weston_output *output,
pixman_region32_t *output_damage);
void (*flush_damage)(struct weston_surface *surface);
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 0e5afbe..7881fd8 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -106,6 +106,8 @@ struct gl_renderer {
EGLContext egl_context;
EGLConfig egl_config;

+ GLuint fbo;
+
struct wl_array vertices;
struct wl_array vtxcnt;

@@ -585,6 +587,114 @@ out:
pixman_region32_fini(&repaint);
}

+static int
+gl_renderer_read_shmbuffer_pixels(struct wl_shm_buffer *shm_buffer,
+ void *pixels, int x, int y, int width, int height)
+{
+ int i;
+ int pixel_size = 0;
+ uint8_t *ptr = NULL;
+ int32_t src_width, src_height, src_stride;
+ int32_t dst_stride;
+ int32_t offset;
+
+ /* Get some parameters of wl_shm_buffer. */
+ src_width = wl_shm_buffer_get_width(shm_buffer);
+ src_height = wl_shm_buffer_get_height(shm_buffer);
+ src_stride = wl_shm_buffer_get_stride(shm_buffer);
+
+ assert((src_width > 0) && (src_height > 0));
+ if ((src_width <= 0) || (src_height <= 0))
+ return -1;
+
+ /* the start of reading position has to be changed. */
+ ptr = wl_shm_buffer_get_data(shm_buffer);
+ ptr += y * src_stride;
+ if ((x == 0) && (width == src_width) && (height <= (src_height - y))) {
+ /* If x is 0 and widths are the same,
+ * whole pixel can be copied in only one time.
+ */
+ memcpy(pixels, ptr, src_stride * height);
+ } else {
+ /* If x is not 0,
+ * every line have to be copied one by one.
+ */
+ pixel_size = src_stride / src_width;
+ assert(pixel_size < 5);
+ if (pixel_size > 4) return -1;
+
+ dst_stride = width * pixel_size;
+ offset = x * pixel_size;
+
+ for (i = 0; i < height; i++, ptr += src_stride) {
+ memcpy(pixels, ptr + offset, dst_stride);
+ pixels = (uint8_t*)pixels + dst_stride;
+ }
+ }
+
+ return 0;
+}
+
+static int
+gl_renderer_read_glsurface_pixels(struct weston_surface *es,
+ pixman_format_code_t format, void *pixels,
+ int x, int y, int width, int height)
+{
+ struct weston_compositor *ec = es->compositor;
+ struct gl_renderer *gr = get_renderer(ec);
+ struct gl_surface_state *gs = get_surface_state(es);
+ GLenum gl_format;
+
+ switch (format) {
+ case PIXMAN_a8r8g8b8:
+ gl_format = GL_BGRA_EXT;
+ break;
+ case PIXMAN_a8b8g8r8:
+ gl_format = GL_RGBA;
+ break;
+ default:
+ return -1;
+ }
+
+ if (gr->fbo == 0)
+ glGenFramebuffers(1, &gr->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, gr->fbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ gs->textures[0], 0);
+
+ glReadPixels(x, y, width, height,
+ gl_format, GL_UNSIGNED_BYTE, pixels);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return 0;
+}
+
+static int
+gl_renderer_read_surface_pixels(struct weston_surface *es,
+ pixman_format_code_t format, void *pixels,
+ int x, int y, int width, int height)
+{
+ struct weston_buffer *buffer = es->buffer_ref.buffer;
+ struct wl_shm_buffer *shm_buffer = NULL;
+ int ret = 0;
+
+ if (buffer) {
+ shm_buffer = wl_shm_buffer_get(buffer->resource);
+ }
+ if (shm_buffer) {
+ ret = gl_renderer_read_shmbuffer_pixels(shm_buffer,
+ pixels, x, y, width, height);
+ } else {
+ ret = gl_renderer_read_glsurface_pixels(es,
+ format, pixels, x, y, width, height);
+ }
+
+ return ret;
+}
+
static void
repaint_views(struct weston_output *output, pixman_region32_t *damage)
{
@@ -1602,6 +1712,9 @@ gl_renderer_destroy(struct weston_compositor *ec)

wl_signal_emit(&gr->destroy_signal, gr);

+ if (gr->fbo)
+ glDeleteFramebuffers(1, &gr->fbo);
+
if (gr->has_bind_display)
gr->unbind_display(gr->egl_display, ec->wl_display);

@@ -1699,6 +1812,7 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
return -1;

gr->base.read_pixels = gl_renderer_read_pixels;
+ gr->base.read_surface_pixels = gl_renderer_read_surface_pixels;
gr->base.repaint_output = gl_renderer_repaint_output;
gr->base.flush_damage = gl_renderer_flush_damage;
gr->base.attach = gl_renderer_attach;
--
1.8.3.1
Pekka Paalanen
2014-03-13 08:47:03 UTC
Permalink
On Wed, 12 Mar 2014 23:46:35 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - gl_renderer_read_shmbuffer_pixels to support different types of format of
> shmbuffer.
>
> src/compositor.h | 3 ++
> src/gl-renderer.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 117 insertions(+)
>
> diff --git a/src/compositor.h b/src/compositor.h
> index 22a485f..ace75da 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -540,6 +540,9 @@ struct weston_renderer {
> pixman_format_code_t format, void *pixels,
> uint32_t x, uint32_t y,
> uint32_t width, uint32_t height);
> + int (*read_surface_pixels)(struct weston_surface *es,
> + pixman_format_code_t format, void *pixels,
> + int x, int y, int width, int height);
> void (*repaint_output)(struct weston_output *output,
> pixman_region32_t *output_damage);
> void (*flush_damage)(struct weston_surface *surface);
> diff --git a/src/gl-renderer.c b/src/gl-renderer.c
> index 0e5afbe..7881fd8 100644
> --- a/src/gl-renderer.c
> +++ b/src/gl-renderer.c
> @@ -106,6 +106,8 @@ struct gl_renderer {
> EGLContext egl_context;
> EGLConfig egl_config;
>
> + GLuint fbo;
> +
> struct wl_array vertices;
> struct wl_array vtxcnt;
>
> @@ -585,6 +587,114 @@ out:
> pixman_region32_fini(&repaint);
> }
>
> +static int
> +gl_renderer_read_shmbuffer_pixels(struct wl_shm_buffer *shm_buffer,
> + void *pixels, int x, int y, int width, int height)

How is 'pixels' allocated, what should we assume?

Is the size of the 'pixels' buffer as width*height*4 bytes, with
stride=width*4 bytes?

What do we assume about the 'pixels' color format?

What if the shm_buffer has color format RGB565?

What if shm_buffer stride is more than width*4 bytes?

But, see below.

> +{
> + int i;
> + int pixel_size = 0;
> + uint8_t *ptr = NULL;
> + int32_t src_width, src_height, src_stride;
> + int32_t dst_stride;
> + int32_t offset;
> +
> + /* Get some parameters of wl_shm_buffer. */
> + src_width = wl_shm_buffer_get_width(shm_buffer);
> + src_height = wl_shm_buffer_get_height(shm_buffer);
> + src_stride = wl_shm_buffer_get_stride(shm_buffer);
> +
> + assert((src_width > 0) && (src_height > 0));
> + if ((src_width <= 0) || (src_height <= 0))
> + return -1;
> +
> + /* the start of reading position has to be changed. */
> + ptr = wl_shm_buffer_get_data(shm_buffer);
> + ptr += y * src_stride;
> + if ((x == 0) && (width == src_width) && (height <= (src_height - y))) {
> + /* If x is 0 and widths are the same,
> + * whole pixel can be copied in only one time.
> + */
> + memcpy(pixels, ptr, src_stride * height);
> + } else {
> + /* If x is not 0,
> + * every line have to be copied one by one.
> + */
> + pixel_size = src_stride / src_width;
> + assert(pixel_size < 5);
> + if (pixel_size > 4) return -1;
> +
> + dst_stride = width * pixel_size;
> + offset = x * pixel_size;
> +
> + for (i = 0; i < height; i++, ptr += src_stride) {
> + memcpy(pixels, ptr + offset, dst_stride);
> + pixels = (uint8_t*)pixels + dst_stride;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int
> +gl_renderer_read_glsurface_pixels(struct weston_surface *es,
> + pixman_format_code_t format, void *pixels,
> + int x, int y, int width, int height)
> +{
> + struct weston_compositor *ec = es->compositor;
> + struct gl_renderer *gr = get_renderer(ec);
> + struct gl_surface_state *gs = get_surface_state(es);
> + GLenum gl_format;
> +
> + switch (format) {
> + case PIXMAN_a8r8g8b8:
> + gl_format = GL_BGRA_EXT;
> + break;
> + case PIXMAN_a8b8g8r8:
> + gl_format = GL_RGBA;
> + break;
> + default:
> + return -1;
> + }
> +
> + if (gr->fbo == 0)
> + glGenFramebuffers(1, &gr->fbo);
> + glBindFramebuffer(GL_FRAMEBUFFER, gr->fbo);
> + glFramebufferTexture2D(GL_FRAMEBUFFER,
> + GL_COLOR_ATTACHMENT0,
> + GL_TEXTURE_2D,
> + gs->textures[0], 0);
> +
> + glReadPixels(x, y, width, height,
> + gl_format, GL_UNSIGNED_BYTE, pixels);
> +
> + glBindFramebuffer(GL_FRAMEBUFFER, 0);
> +
> + return 0;
> +}
> +
> +static int
> +gl_renderer_read_surface_pixels(struct weston_surface *es,
> + pixman_format_code_t format, void *pixels,
> + int x, int y, int width, int height)
> +{
> + struct weston_buffer *buffer = es->buffer_ref.buffer;
> + struct wl_shm_buffer *shm_buffer = NULL;
> + int ret = 0;
> +
> + if (buffer) {
> + shm_buffer = wl_shm_buffer_get(buffer->resource);
> + }
> + if (shm_buffer) {
> + ret = gl_renderer_read_shmbuffer_pixels(shm_buffer,
> + pixels, x, y, width, height);
> + } else {
> + ret = gl_renderer_read_glsurface_pixels(es,
> + format, pixels, x, y, width, height);
> + }

I just realized that we are dealing with the GL-renderer only here.
That means that the surface will always have a GL texture, which you
can read back, regardless of if the original wl_buffer was wl_shm or
EGL based.

Therefore I think you could remove the whole shm path. I suppose
optimizing the shm read-back path is not too useful, right?

That is also the reason why you would probably never hit the shm case
to begin with. GL-renderer releases the wl_buffer as soon as it has
copied its content into a texture, so the buffer pointer is likely
always NULL.

Sorry for not realizing that earlier.

So just one more question: what about YUV color formats? That's why
gl_surface_state has an array of textures instead of just one. YUV data
can come in via EGL based buffers. You could at least return failure
for unhandled color formats, maybe?


Thanks,
pq

> +
> + return ret;
> +}
> +
> static void
> repaint_views(struct weston_output *output, pixman_region32_t *damage)
> {
> @@ -1602,6 +1712,9 @@ gl_renderer_destroy(struct weston_compositor *ec)
>
> wl_signal_emit(&gr->destroy_signal, gr);
>
> + if (gr->fbo)
> + glDeleteFramebuffers(1, &gr->fbo);
> +
> if (gr->has_bind_display)
> gr->unbind_display(gr->egl_display, ec->wl_display);
>
> @@ -1699,6 +1812,7 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
> return -1;
>
> gr->base.read_pixels = gl_renderer_read_pixels;
> + gr->base.read_surface_pixels = gl_renderer_read_surface_pixels;
> gr->base.repaint_output = gl_renderer_repaint_output;
> gr->base.flush_damage = gl_renderer_flush_damage;
> gr->base.attach = gl_renderer_attach;
Nobuhiko Tanibata
2014-03-14 12:29:36 UTC
Permalink
2014-03-13 17:47 ? Pekka Paalanen ????????:
> On Wed, 12 Mar 2014 23:46:35 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2:
>> - gl_renderer_read_shmbuffer_pixels to support different types of
>> format of
>> shmbuffer.
>>
>> src/compositor.h | 3 ++
>> src/gl-renderer.c | 114
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 117 insertions(+)
>>
>> diff --git a/src/compositor.h b/src/compositor.h
>> index 22a485f..ace75da 100644
>> --- a/src/compositor.h
>> +++ b/src/compositor.h
>> @@ -540,6 +540,9 @@ struct weston_renderer {
>> pixman_format_code_t format, void *pixels,
>> uint32_t x, uint32_t y,
>> uint32_t width, uint32_t height);
>> + int (*read_surface_pixels)(struct weston_surface *es,
>> + pixman_format_code_t format, void *pixels,
>> + int x, int y, int width, int height);
>> void (*repaint_output)(struct weston_output *output,
>> pixman_region32_t *output_damage);
>> void (*flush_damage)(struct weston_surface *surface);
>> diff --git a/src/gl-renderer.c b/src/gl-renderer.c
>> index 0e5afbe..7881fd8 100644
>> --- a/src/gl-renderer.c
>> +++ b/src/gl-renderer.c
>> @@ -106,6 +106,8 @@ struct gl_renderer {
>> EGLContext egl_context;
>> EGLConfig egl_config;
>>
>> + GLuint fbo;
>> +
>> struct wl_array vertices;
>> struct wl_array vtxcnt;
>>
>> @@ -585,6 +587,114 @@ out:
>> pixman_region32_fini(&repaint);
>> }
>>
>> +static int
>> +gl_renderer_read_shmbuffer_pixels(struct wl_shm_buffer *shm_buffer,
>> + void *pixels, int x, int y, int width, int height)
>
> How is 'pixels' allocated, what should we assume?
>
> Is the size of the 'pixels' buffer as width*height*4 bytes, with
> stride=width*4 bytes?
>
> What do we assume about the 'pixels' color format?
>
> What if the shm_buffer has color format RGB565?
>
> What if shm_buffer stride is more than width*4 bytes?
>
> But, see below.
>
>> +{
>> + int i;
>> + int pixel_size = 0;
>> + uint8_t *ptr = NULL;
>> + int32_t src_width, src_height, src_stride;
>> + int32_t dst_stride;
>> + int32_t offset;
>> +
>> + /* Get some parameters of wl_shm_buffer. */
>> + src_width = wl_shm_buffer_get_width(shm_buffer);
>> + src_height = wl_shm_buffer_get_height(shm_buffer);
>> + src_stride = wl_shm_buffer_get_stride(shm_buffer);
>> +
>> + assert((src_width > 0) && (src_height > 0));
>> + if ((src_width <= 0) || (src_height <= 0))
>> + return -1;
>> +
>> + /* the start of reading position has to be changed. */
>> + ptr = wl_shm_buffer_get_data(shm_buffer);
>> + ptr += y * src_stride;
>> + if ((x == 0) && (width == src_width) && (height <= (src_height -
>> y))) {
>> + /* If x is 0 and widths are the same,
>> + * whole pixel can be copied in only one time.
>> + */
>> + memcpy(pixels, ptr, src_stride * height);
>> + } else {
>> + /* If x is not 0,
>> + * every line have to be copied one by one.
>> + */
>> + pixel_size = src_stride / src_width;
>> + assert(pixel_size < 5);
>> + if (pixel_size > 4) return -1;
>> +
>> + dst_stride = width * pixel_size;
>> + offset = x * pixel_size;
>> +
>> + for (i = 0; i < height; i++, ptr += src_stride) {
>> + memcpy(pixels, ptr + offset, dst_stride);
>> + pixels = (uint8_t*)pixels + dst_stride;
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int
>> +gl_renderer_read_glsurface_pixels(struct weston_surface *es,
>> + pixman_format_code_t format, void *pixels,
>> + int x, int y, int width, int height)
>> +{
>> + struct weston_compositor *ec = es->compositor;
>> + struct gl_renderer *gr = get_renderer(ec);
>> + struct gl_surface_state *gs = get_surface_state(es);
>> + GLenum gl_format;
>> +
>> + switch (format) {
>> + case PIXMAN_a8r8g8b8:
>> + gl_format = GL_BGRA_EXT;
>> + break;
>> + case PIXMAN_a8b8g8r8:
>> + gl_format = GL_RGBA;
>> + break;
>> + default:
>> + return -1;
>> + }
>> +
>> + if (gr->fbo == 0)
>> + glGenFramebuffers(1, &gr->fbo);
>> + glBindFramebuffer(GL_FRAMEBUFFER, gr->fbo);
>> + glFramebufferTexture2D(GL_FRAMEBUFFER,
>> + GL_COLOR_ATTACHMENT0,
>> + GL_TEXTURE_2D,
>> + gs->textures[0], 0);
>> +
>> + glReadPixels(x, y, width, height,
>> + gl_format, GL_UNSIGNED_BYTE, pixels);
>> +
>> + glBindFramebuffer(GL_FRAMEBUFFER, 0);
>> +
>> + return 0;
>> +}
>> +
>> +static int
>> +gl_renderer_read_surface_pixels(struct weston_surface *es,
>> + pixman_format_code_t format, void *pixels,
>> + int x, int y, int width, int height)
>> +{
>> + struct weston_buffer *buffer = es->buffer_ref.buffer;
>> + struct wl_shm_buffer *shm_buffer = NULL;
>> + int ret = 0;
>> +
>> + if (buffer) {
>> + shm_buffer = wl_shm_buffer_get(buffer->resource);
>> + }
>> + if (shm_buffer) {
>> + ret = gl_renderer_read_shmbuffer_pixels(shm_buffer,
>> + pixels, x, y, width, height);
>> + } else {
>> + ret = gl_renderer_read_glsurface_pixels(es,
>> + format, pixels, x, y, width, height);
>> + }
>
> I just realized that we are dealing with the GL-renderer only here.
> That means that the surface will always have a GL texture, which you
> can read back, regardless of if the original wl_buffer was wl_shm or
> EGL based.
>

Hi pq,

Thanks, it is very useful comment.

Yes, you are right. I thought I try to remove wl_shm patch to release
this patch at once
according to your comment
However, as you mention below, I also think how to handle YUV format.
This
format, YUV, is a important in Automotive for handling capture of e.g.
Back
Guide monitor as well. So I need time to discuss more internally. So I
drop this patch
to rethink more.
And I will remove parts calling gl_renderer_read_surface_pixels in
westion_layout
to support capture snapshot per a surface. This is not mandatory to
support for the time being.

BR,
Nobuhiko

> Therefore I think you could remove the whole shm path. I suppose
> optimizing the shm read-back path is not too useful, right?
>
> That is also the reason why you would probably never hit the shm case
> to begin with. GL-renderer releases the wl_buffer as soon as it has
> copied its content into a texture, so the buffer pointer is likely
> always NULL.
>
> Sorry for not realizing that earlier.
>
> So just one more question: what about YUV color formats? That's why
> gl_surface_state has an array of textures instead of just one. YUV data
> can come in via EGL based buffers. You could at least return failure
> for unhandled color formats, maybe?
>
>
> Thanks,
> pq
>
>> +
>> + return ret;
>> +}
>> +
>> static void
>> repaint_views(struct weston_output *output, pixman_region32_t
>> *damage)
>> {
>> @@ -1602,6 +1712,9 @@ gl_renderer_destroy(struct weston_compositor
>> *ec)
>>
>> wl_signal_emit(&gr->destroy_signal, gr);
>>
>> + if (gr->fbo)
>> + glDeleteFramebuffers(1, &gr->fbo);
>> +
>> if (gr->has_bind_display)
>> gr->unbind_display(gr->egl_display, ec->wl_display);
>>
>> @@ -1699,6 +1812,7 @@ gl_renderer_create(struct weston_compositor *ec,
>> EGLNativeDisplayType display,
>> return -1;
>>
>> gr->base.read_pixels = gl_renderer_read_pixels;
>> + gr->base.read_surface_pixels = gl_renderer_read_surface_pixels;
>> gr->base.repaint_output = gl_renderer_repaint_output;
>> gr->base.flush_damage = gl_renderer_flush_damage;
>> gr->base.attach = gl_renderer_attach;
Nobuhiko Tanibata
2014-03-06 09:53:08 UTC
Permalink
Add interface ivi_application, which creates ivi_surface objects tied
to a given wl_surface with a given id. The given id can be used in a
shell to identify which application is assigned to a wl_surface and
layout the surface wherever the shell wants. ivi_surface objects can
be used to receive status of wl_surface in the scenegraph of the
compositor.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
protocol/ivi-application.xml | 88 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
create mode 100644 protocol/ivi-application.xml

diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml
new file mode 100644
index 0000000..e58ad26
--- /dev/null
+++ b/protocol/ivi-application.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ivi_application">
+
+ <copyright>
+ Copyright (C) 2013 DENSO CORPORATION
+ Copyright (c) 2013 BMW Car IT GmbH
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ </copyright>
+
+ <interface name="ivi_surface" version="1">
+ <description summary="application interface to surface in ivi compositor"/>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy ivi_surface"/>
+ </request>
+
+ <event name="visibility">
+ <description summary="visibility of surface in ivi compositor has changed">
+ The new visibility state is provided in argument visibility.
+ If visibility is 0, the surface has become invisible.
+ If visibility is not 0, the surface has become visible.
+ </description>
+ <arg name="visibility" type="int"/>
+ </event>
+
+ </interface>
+
+ <interface name="ivi_application" version="1">
+ <description summary="interface for ivi applications to use ivi compositor features"/>
+
+ <request name="surface_create">
+ <description summary="create surface in ivi compositor">
+ surface_create will create a new surface with surface_id in ivi compositor,
+ if it does not yet exists. If the surface with surface_id already exists in
+ ivi compositor, the application content provided in argument surface will
+ be used as surface content. If an other ivi application already registered
+ content for surface with surface_id, an error event will indicate the problem.
+ </description>
+ <arg name="id_surface" type="uint"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="id" type="new_id" interface="ivi_surface"/>
+ </request>
+
+ <enum name="error_code">
+ <description summary="possible error codes returned by ivi compositor">
+ These error codes define all possible error codes returned by ivi compositor
+ on server-side errors.
+ </description>
+ <entry name="unknown_error" value="1" summary="unknown error encountered"/>
+ <entry name="resource_in_use" value="2" summary="resource is in use and can not be shared"/>
+ </enum>
+
+ <event name="error">
+ <description summary="server-side error detected">
+ The ivi compositor encountered error while processing a request by this
+ application. The error is defined by argument error_code and optional
+ error_text.
+ If the application requires to associate this error event to a request,
+ it can
+ 1. send request
+ 2. force display roundtrip
+ 3. check, if error event was received
+ but this restricts the application to have only one open request at a time.
+ </description>
+ <arg name="error_code" type="int"/>
+ <arg name="error_text" type="string" allow-null="true"/>
+ </event>
+
+ </interface>
+
+</protocol>
--
1.8.3.1
Jason Ekstrand
2014-03-06 15:21:39 UTC
Permalink
On Mar 6, 2014 3:53 AM, "Nobuhiko Tanibata" <
NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
> Add interface ivi_application, which creates ivi_surface objects tied
> to a given wl_surface with a given id. The given id can be used in a
> shell to identify which application is assigned to a wl_surface and
> layout the surface wherever the shell wants. ivi_surface objects can
> be used to receive status of wl_surface in the scenegraph of the
> compositor.

In general, I think this looks pretty good. It's nice and simple and only
adds what's needed for clients. I do have a couple comments below.
--Jason Ekstrand

>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
> protocol/ivi-application.xml | 88
++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 88 insertions(+)
> create mode 100644 protocol/ivi-application.xml
>
> diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml
> new file mode 100644
> index 0000000..e58ad26
> --- /dev/null
> +++ b/protocol/ivi-application.xml
> @@ -0,0 +1,88 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<protocol name="ivi_application">
> +
> + <copyright>
> + Copyright (C) 2013 DENSO CORPORATION
> + Copyright (c) 2013 BMW Car IT GmbH
> +
> + Permission is hereby granted, free of charge, to any person
obtaining a copy
> + of this software and associated documentation files (the
"Software"), to deal
> + in the Software without restriction, including without limitation
the rights
> + to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
> + copies of the Software, and to permit persons to whom the Software is
> + furnished to do so, subject to the following conditions:
> +
> + The above copyright notice and this permission notice shall be
included in
> + all copies or substantial portions of the Software.
> +
> + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
> + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
> + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE
> + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER
> + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
> + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN
> + THE SOFTWARE.
> + </copyright>
> +
> + <interface name="ivi_surface" version="1">
> + <description summary="application interface to surface in ivi
compositor"/>
> +
> + <request name="destroy" type="destructor">
> + <description summary="destroy ivi_surface"/>
> + </request>
> +
> + <event name="visibility">
> + <description summary="visibility of surface in ivi
compositor has changed">
> + The new visibility state is provided in argument
visibility.
> + If visibility is 0, the surface has become invisible.
> + If visibility is not 0, the surface has become visible.
> + </description>
> + <arg name="visibility" type="int"/>
> + </event>
> +
> + </interface>
> +
> + <interface name="ivi_application" version="1">
> + <description summary="interface for ivi applications to use ivi
compositor features"/>
> +
> + <request name="surface_create">
> + <description summary="create surface in ivi compositor">
> + surface_create will create a new surface with surface_id
in ivi compositor,
> + if it does not yet exists. If the surface with
surface_id already exists in
> + ivi compositor, the application content provided in
argument surface will
> + be used as surface content. If an other ivi application
already registered
> + content for surface with surface_id, an error event will
indicate the problem.
> + </description>
> + <arg name="id_surface" type="uint"/>
> + <arg name="surface" type="object" interface="wl_surface"/>
> + <arg name="id" type="new_id" interface="ivi_surface"/>
> + </request>
> +
> + <enum name="error_code">
> + <description summary="possible error codes returned by ivi
compositor">
> + These error codes define all possible error codes
returned by ivi compositor
> + on server-side errors.
> + </description>
> + <entry name="unknown_error" value="1" summary="unknown
error encountered"/>

What kinds of things do you use "unknown error" for? I'm not sure how
that's useful to the client.

> + <entry name="resource_in_use" value="2" summary="resource is
in use and can not be shared"/>

What kind of resource does this refer to? It looks like you use it if
someone tries to call surface_create twice on the same surface, but you
don't specify.

> + </enum>
> +
> + <event name="error">
> + <description summary="server-side error detected">
> + The ivi compositor encountered error while processing a
request by this
> + application. The error is defined by argument error_code
and optional
> + error_text.
> + If the application requires to associate this error
event to a request,
> + it can
> + 1. send request
> + 2. force display roundtrip
> + 3. check, if error event was received
> + but this restricts the application to have only one
open request at a time.
> + </description>
> + <arg name="error_code" type="int"/>
> + <arg name="error_text" type="string" allow-null="true"/>
> + </event>

Why are you using this rather than the built-in wl_display.error? The
built-in wl_display.error also terminates the client when an error is
sent. Under what error conditions would you want the client to continue?

> +
> + </interface>
> +
> +</protocol>
> --
> 1.8.3.1
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20140306/e203a008/attachment.html>
Nobuhiko Tanibata
2014-03-07 01:07:35 UTC
Permalink
2014-03-07 00:21 ? Jason Ekstrand ????????:
> On Mar 6, 2014 3:53 AM, "Nobuhiko Tanibata"
> <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
> >
> > Add interface ivi_application, which creates ivi_surface objects
> tied
> > to a given wl_surface with a given id. The given id can be used in
> a
> > shell to identify which application is assigned to a wl_surface and
> > layout the surface wherever the shell wants. ivi_surface objects
> can
> > be used to receive status of wl_surface in the scenegraph of the
> > compositor.
>
> In general, I think this looks pretty good.? It's nice and simple and
> only adds what's needed for clients.? I do have a couple comments
> below.
> --Jason Ekstrand
>
>>
> > Signed-off-by: Nobuhiko Tanibata
> <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> > ---
> > ?protocol/ivi-application.xml | 88
> ++++++++++++++++++++++++++++++++++++++++++++
> > ?1 file changed, 88 insertions(+)
> > ?create mode 100644 protocol/ivi-application.xml
> >
> > diff --git a/protocol/ivi-application.xml
> b/protocol/ivi-application.xml
> > new file mode 100644
> > index 0000000..e58ad26
> > --- /dev/null
> > +++ b/protocol/ivi-application.xml
> > @@ -0,0 +1,88 @@
> > +<?xml version="1.0" encoding="UTF-8"?>
> > +<protocol name="ivi_application">
> > +
> > + ? ?<copyright>
> > + ? ?Copyright (C) 2013 DENSO CORPORATION
> > + ? ?Copyright (c) 2013 BMW Car IT GmbH
> > +
> > + ? ?Permission is hereby granted, free of charge, to any person
> obtaining a copy
> > + ? ?of this software and associated documentation files (the
> "Software"), to deal
> > + ? ?in the Software without restriction, including without
> limitation the rights
> > + ? ?to use, copy, modify, merge, publish, distribute,
> sublicense, and/or sell
> > + ? ?copies of the Software, and to permit persons to whom the
> Software is
> > + ? ?furnished to do so, subject to the following conditions:
> > +
> > + ? ?The above copyright notice and this permission notice shall
> be included in
> > + ? ?all copies or substantial portions of the Software.
> > +
> > + ? ?THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
> KIND, EXPRESS OR
> > + ? ?IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> > + ? ?FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> EVENT SHALL THE
> > + ? ?AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> DAMAGES OR OTHER
> > + ? ?LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> OTHERWISE, ARISING FROM,
> > + ? ?OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER DEALINGS IN
> > + ? ?THE SOFTWARE.
> > + ? ?</copyright>
> > +
> > + ? ?<interface name="ivi_surface" version="1">
> > + ? ? ? ?<description summary="application interface to surface
> in ivi compositor"/>
> > +
> > + ? ? ? ?<request name="destroy" type="destructor">
> > + ? ? ? ? ? ?<description summary="destroy ivi_surface"/>
> > + ? ? ? ?</request>
> > +
> > + ? ? ? ?<event name="visibility">
> > + ? ? ? ? ? ?<description summary="visibility of surface in
> ivi compositor has changed">
> > + ? ? ? ? ? ? ? ?The new visibility state is provided in
> argument visibility.
> > + ? ? ? ? ? ? ? ?If visibility is 0, the surface has become
> invisible.
> > + ? ? ? ? ? ? ? ?If visibility is not 0, the surface has
> become visible.
> > + ? ? ? ? ? ?</description>
> > + ? ? ? ? ? ?<arg name="visibility" type="int"/>
> > + ? ? ? ?</event>
> > +
> > + ? ?</interface>
> > +
> > + ? ?<interface name="ivi_application" version="1">
> > + ? ? ? ?<description summary="interface for ivi applications
> to use ivi compositor features"/>
> > +
> > + ? ? ? ?<request name="surface_create">
> > + ? ? ? ? ? ?<description summary="create surface in ivi
> compositor">
> > + ? ? ? ? ? ? ? ?surface_create will create a new surface
> with surface_id in ivi compositor,
> > + ? ? ? ? ? ? ? ?if it does not yet exists. If the surface
> with surface_id already exists in
> > + ? ? ? ? ? ? ? ?ivi compositor, the application content
> provided in argument surface will
> > + ? ? ? ? ? ? ? ?be used as surface content. If an other
> ivi application already registered
> > + ? ? ? ? ? ? ? ?content for surface with surface_id, an
> error event will indicate the problem.
> > + ? ? ? ? ? ?</description>
> > + ? ? ? ? ? ?<arg name="id_surface" type="uint"/>
> > + ? ? ? ? ? ?<arg name="surface" type="object"
> interface="wl_surface"/>
> > + ? ? ? ? ? ?<arg name="id" type="new_id"
> interface="ivi_surface"/>
> > + ? ? ? ?</request>
> > +
> > + ? ? ? ?<enum name="error_code">
> > + ? ? ? ? ? ?<description summary="possible error codes
> returned by ivi compositor">
> > + ? ? ? ? ? ? ? ?These error codes define all possible
> error codes returned by ivi compositor
> > + ? ? ? ? ? ? ? ?on server-side errors.
> > + ? ? ? ? ? ?</description>
> > + ? ? ? ? ? ?<entry name="unknown_error" ? value="1"
> summary="unknown error encountered"/>
>
> What kinds of things do you use "unknown error" for?? I'm not sure
> how that's useful to the client.
>

Hi Jason,

Thank you for reviewing.

I see. From this review point, it shall not return no useful value to
the client.
I break down more here.
- id in use: specified ID for ivi_surface is already used by itself or
other client.
- resource in use: specified ID of wl_surface is already tie to another
ID of ivi_surface.
- invalid resource: specified ID of wl_surface is not valid in server.

I think these three is sufficient for client.

>> + ? ? ? ? ? ?<entry name="resource_in_use" value="2"
> summary="resource is in use and can not be shared"/>
>
> What kind of resource does this refer to?? It looks like you use it
> if someone tries to call surface_create twice on the same surface, but
> you don't specify.
>
>> + ? ? ? ?</enum>
> > +
> > + ? ? ? ?<event name="error">
> > + ? ? ? ? ? ?<description summary="server-side error
> detected">
> > + ? ? ? ? ? ? ? ?The ivi compositor encountered error while
> processing a request by this
> > + ? ? ? ? ? ? ? ?application. The error is defined by
> argument error_code and optional
> > + ? ? ? ? ? ? ? ?error_text.
> > + ? ? ? ? ? ? ? ?If the application requires to associate
> this error event to a request,
> > + ? ? ? ? ? ? ? ?it can
> > + ? ? ? ? ? ? ? ? ? ?1. send request
> > + ? ? ? ? ? ? ? ? ? ?2. force display roundtrip
> > + ? ? ? ? ? ? ? ? ? ?3. check, if error event was
> received
> > + ? ? ? ? ? ? ? ? but this restricts the application to
> have only one open request at a time.
> > + ? ? ? ? ? ?</description>
> > + ? ? ? ? ? ?<arg name="error_code" type="int"/>
> > + ? ? ? ? ? ?<arg name="error_text" type="string"
> allow-null="true"/>
> > + ? ? ? ?</event>
>
> Why are you using this rather than the built-in wl_display.error??
> The built-in wl_display.error also terminates the client when an error
> is sent.? Under what error conditions would you want the client to
> continue?
>

Good suggestion!
According to wayland.xml, error code from 0 to 2 is reserved for global.
Please teach me there is any manner which number I can use for the above
object? In the feature, if wayland.xml updated to add new global error
code to 3, the local number may need to be incremented.

BR,
Nobuhiko
>> +
> > + ? ?</interface>
> > +
> > +</protocol>
> > --
> > 1.8.3.1
> >
> > _______________________________________________
> > wayland-devel mailing list
> > wayland-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/wayland-devel [1]
>
>
> Links:
> ------
> [1] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Jason Ekstrand
2014-03-07 02:37:07 UTC
Permalink
On Mar 6, 2014 7:08 PM, "Nobuhiko Tanibata" <
nobuhiko_tanibata at xddp.denso.co.jp> wrote:
>
> 2014-03-07 00:21 ? Jason Ekstrand ????????:
>
>> On Mar 6, 2014 3:53 AM, "Nobuhiko Tanibata"
>> <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>> >
>> > Add interface ivi_application, which creates ivi_surface objects
>> tied
>> > to a given wl_surface with a given id. The given id can be used in
>> a
>> > shell to identify which application is assigned to a wl_surface and
>> > layout the surface wherever the shell wants. ivi_surface objects
>> can
>> > be used to receive status of wl_surface in the scenegraph of the
>> > compositor.
>>
>> In general, I think this looks pretty good. It's nice and simple and
>> only adds what's needed for clients. I do have a couple comments
>> below.
>> --Jason Ekstrand
>>
>>>
>> > Signed-off-by: Nobuhiko Tanibata
>> <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> > ---
>> > protocol/ivi-application.xml | 88
>> ++++++++++++++++++++++++++++++++++++++++++++
>> > 1 file changed, 88 insertions(+)
>> > create mode 100644 protocol/ivi-application.xml
>> >
>> > diff --git a/protocol/ivi-application.xml
>> b/protocol/ivi-application.xml
>> > new file mode 100644
>> > index 0000000..e58ad26
>> > --- /dev/null
>> > +++ b/protocol/ivi-application.xml
>> > @@ -0,0 +1,88 @@
>> > +<?xml version="1.0" encoding="UTF-8"?>
>> > +<protocol name="ivi_application">
>> > +
>> > + <copyright>
>> > + Copyright (C) 2013 DENSO CORPORATION
>> > + Copyright (c) 2013 BMW Car IT GmbH
>> > +
>> > + Permission is hereby granted, free of charge, to any person
>> obtaining a copy
>> > + of this software and associated documentation files (the
>> "Software"), to deal
>> > + in the Software without restriction, including without
>> limitation the rights
>> > + to use, copy, modify, merge, publish, distribute,
>> sublicense, and/or sell
>> > + copies of the Software, and to permit persons to whom the
>> Software is
>> > + furnished to do so, subject to the following conditions:
>> > +
>> > + The above copyright notice and this permission notice shall
>> be included in
>> > + all copies or substantial portions of the Software.
>> > +
>> > + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
>> KIND, EXPRESS OR
>> > + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> MERCHANTABILITY,
>> > + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
>> EVENT SHALL THE
>> > + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
>> DAMAGES OR OTHER
>> > + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
>> OTHERWISE, ARISING FROM,
>> > + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> OTHER DEALINGS IN
>> > + THE SOFTWARE.
>> > + </copyright>
>> > +
>> > + <interface name="ivi_surface" version="1">
>> > + <description summary="application interface to surface
>> in ivi compositor"/>
>> > +
>> > + <request name="destroy" type="destructor">
>> > + <description summary="destroy ivi_surface"/>
>> > + </request>
>> > +
>> > + <event name="visibility">
>> > + <description summary="visibility of surface in
>> ivi compositor has changed">
>> > + The new visibility state is provided in
>> argument visibility.
>> > + If visibility is 0, the surface has become
>> invisible.
>> > + If visibility is not 0, the surface has
>> become visible.
>> > + </description>
>> > + <arg name="visibility" type="int"/>
>> > + </event>
>> > +
>> > + </interface>
>> > +
>> > + <interface name="ivi_application" version="1">
>> > + <description summary="interface for ivi applications
>> to use ivi compositor features"/>
>> > +
>> > + <request name="surface_create">
>> > + <description summary="create surface in ivi
>> compositor">
>> > + surface_create will create a new surface
>> with surface_id in ivi compositor,
>> > + if it does not yet exists. If the surface
>> with surface_id already exists in
>> > + ivi compositor, the application content
>> provided in argument surface will
>> > + be used as surface content. If an other
>> ivi application already registered
>> > + content for surface with surface_id, an
>> error event will indicate the problem.
>> > + </description>
>> > + <arg name="id_surface" type="uint"/>
>> > + <arg name="surface" type="object"
>> interface="wl_surface"/>
>> > + <arg name="id" type="new_id"
>> interface="ivi_surface"/>
>> > + </request>
>> > +
>> > + <enum name="error_code">
>> > + <description summary="possible error codes
>> returned by ivi compositor">
>> > + These error codes define all possible
>> error codes returned by ivi compositor
>> > + on server-side errors.
>> > + </description>
>> > + <entry name="unknown_error" value="1"
>> summary="unknown error encountered"/>
>>
>> What kinds of things do you use "unknown error" for? I'm not sure
>> how that's useful to the client.
>>
>
> Hi Jason,
>
> Thank you for reviewing.
>
> I see. From this review point, it shall not return no useful value to the
client.
> I break down more here.
> - id in use: specified ID for ivi_surface is already used by itself or
other client.
> - resource in use: specified ID of wl_surface is already tie to another
ID of ivi_surface.
> - invalid resource: specified ID of wl_surface is not valid in server.
>
> I think these three is sufficient for client.
>
>
>>> + <entry name="resource_in_use" value="2"
>>
>> summary="resource is in use and can not be shared"/>
>>
>> What kind of resource does this refer to? It looks like you use it
>> if someone tries to call surface_create twice on the same surface, but
>> you don't specify.
>>
>>> + </enum>
>>
>> > +
>> > + <event name="error">
>> > + <description summary="server-side error
>> detected">
>> > + The ivi compositor encountered error while
>> processing a request by this
>> > + application. The error is defined by
>> argument error_code and optional
>> > + error_text.
>> > + If the application requires to associate
>> this error event to a request,
>> > + it can
>> > + 1. send request
>> > + 2. force display roundtrip
>> > + 3. check, if error event was
>> received
>> > + but this restricts the application to
>> have only one open request at a time.
>> > + </description>
>> > + <arg name="error_code" type="int"/>
>> > + <arg name="error_text" type="string"
>> allow-null="true"/>
>> > + </event>
>>
>> Why are you using this rather than the built-in wl_display.error?
>> The built-in wl_display.error also terminates the client when an error
>> is sent. Under what error conditions would you want the client to
>> continue?
>>
>
> Good suggestion!
> According to wayland.xml, error code from 0 to 2 is reserved for global.
> Please teach me there is any manner which number I can use for the above
object? In the feature, if wayland.xml updated to add new global error code
to 3, the local number may need to be incremented.

The wl_display.error event is a bit confusing. The wl_resource_post_error
function takes three arguments. The first argument is an object; the last
two are an error code and a human-readable message string. The error code
should be interpreted relative to the given object. Therefore, you don't
need to worry about colliding with the codes defined in wl_display. If the
error is defined in wl_application you should pass the wl_application
resource into the error event.

One warning about wl_display.error event: all errors are considered fatal
and the client gets automatically disconnected. Given the errors you
listed, this is probably OK. If you want a non-fatal error, you should use
something else And probably not call it "error" (to avoid confusion).

Hope that helps,
--Jason Ekstrand

>
> BR,
> Nobuhiko
>>>
>>> +
>>
>> > + </interface>
>> > +
>> > +</protocol>
>> > --
>> > 1.8.3.1
>> >
>> > _______________________________________________
>> > wayland-devel mailing list
>> > wayland-devel at lists.freedesktop.org
>> > http://lists.freedesktop.org/mailman/listinfo/wayland-devel [1]
>>
>>
>> Links:
>> ------
>> [1] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20140306/eee29eee/attachment-0001.html>
Nobuhiko Tanibata
2014-03-07 07:49:28 UTC
Permalink
2014-03-07 11:37 ? Jason Ekstrand ????????:
> On Mar 6, 2014 7:08 PM, "Nobuhiko Tanibata"
> <nobuhiko_tanibata at xddp.denso.co.jp> wrote:
> >
> > 2014-03-07 00:21 ? Jason Ekstrand ????????:
> >
> >> On Mar 6, 2014 3:53 AM, "Nobuhiko Tanibata"
> >> <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
> >> >
> >> > Add interface ivi_application, which creates ivi_surface objects
> >> tied
> >> > to a given wl_surface with a given id. The given id can be used
> in
> >> a
> >> > shell to identify which application is assigned to a wl_surface
> and
> >> > layout the surface wherever the shell wants. ivi_surface objects
> >> can
> >> > be used to receive status of wl_surface in the scenegraph of the
> >> > compositor.
> >>
> >> In general, I think this looks pretty good. It's nice and simple
> and
> >> only adds what's needed for clients. I do have a couple comments
> >> below.
> >> --Jason Ekstrand
> >>
> >>>
> >> > Signed-off-by: Nobuhiko Tanibata
> >> <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> >> > ---
> >> > protocol/ivi-application.xml | 88
> >> ++++++++++++++++++++++++++++++++++++++++++++
> >> > 1 file changed, 88 insertions(+)
> >> > create mode 100644 protocol/ivi-application.xml
> >> >
> >> > diff --git a/protocol/ivi-application.xml
> >> b/protocol/ivi-application.xml
> >> > new file mode 100644
> >> > index 0000000..e58ad26
> >> > --- /dev/null
> >> > +++ b/protocol/ivi-application.xml
> >> > @@ -0,0 +1,88 @@
> >> > +<?xml version="1.0" encoding="UTF-8"?>
> >> > +<protocol name="ivi_application">
> >> > +
> >> > + <copyright>
> >> > + Copyright (C) 2013 DENSO CORPORATION
> >> > + Copyright (c) 2013 BMW Car IT GmbH
> >> > +
> >> > + Permission is hereby granted, free of charge, to any person
> >> obtaining a copy
> >> > + of this software and associated documentation files (the
> >> "Software"), to deal
> >> > + in the Software without restriction, including without
> >> limitation the rights
> >> > + to use, copy, modify, merge, publish, distribute,
> >> sublicense, and/or sell
> >> > + copies of the Software, and to permit persons to whom the
> >> Software is
> >> > + furnished to do so, subject to the following conditions:
> >> > +
> >> > + The above copyright notice and this permission notice shall
> >> be included in
> >> > + all copies or substantial portions of the Software.
> >> > +
> >> > + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
> >> KIND, EXPRESS OR
> >> > + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> >> MERCHANTABILITY,
> >> > + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> >> EVENT SHALL THE
> >> > + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> >> DAMAGES OR OTHER
> >> > + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> >> OTHERWISE, ARISING FROM,
> >> > + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> >> OTHER DEALINGS IN
> >> > + THE SOFTWARE.
> >> > + </copyright>
> >> > +
> >> > + <interface name="ivi_surface" version="1">
> >> > + <description summary="application interface to surface
> >> in ivi compositor"/>
> >> > +
> >> > + <request name="destroy" type="destructor">
> >> > + <description summary="destroy ivi_surface"/>
> >> > + </request>
> >> > +
> >> > + <event name="visibility">
> >> > + <description summary="visibility of surface in
> >> ivi compositor has changed">
> >> > + The new visibility state is provided in
> >> argument visibility.
> >> > + If visibility is 0, the surface has become
> >> invisible.
> >> > + If visibility is not 0, the surface has
> >> become visible.
> >> > + </description>
> >> > + <arg name="visibility" type="int"/>
> >> > + </event>
> >> > +
> >> > + </interface>
> >> > +
> >> > + <interface name="ivi_application" version="1">
> >> > + <description summary="interface for ivi applications
> >> to use ivi compositor features"/>
> >> > +
> >> > + <request name="surface_create">
> >> > + <description summary="create surface in ivi
> >> compositor">
> >> > + surface_create will create a new surface
> >> with surface_id in ivi compositor,
> >> > + if it does not yet exists. If the surface
> >> with surface_id already exists in
> >> > + ivi compositor, the application content
> >> provided in argument surface will
> >> > + be used as surface content. If an other
> >> ivi application already registered
> >> > + content for surface with surface_id, an
> >> error event will indicate the problem.
> >> > + </description>
> >> > + <arg name="id_surface" type="uint"/>
> >> > + <arg name="surface" type="object"
> >> interface="wl_surface"/>
> >> > + <arg name="id" type="new_id"
> >> interface="ivi_surface"/>
> >> > + </request>
> >> > +
> >> > + <enum name="error_code">
> >> > + <description summary="possible error codes
> >> returned by ivi compositor">
> >> > + These error codes define all possible
> >> error codes returned by ivi compositor
> >> > + on server-side errors.
> >> > + </description>
> >> > + <entry name="unknown_error" value="1"
> >> summary="unknown error encountered"/>
> >>
> >> What kinds of things do you use "unknown error" for? I'm not sure
> >> how that's useful to the client.
> >>
> >
> > Hi Jason,
> >
> > Thank you for reviewing.
> >
> > I see. From this review point, it shall not return no useful value
> to the client.
> > I break down more here.
> > - id in use: specified ID for ivi_surface is already used by itself
> or other client.
> > - resource in use: specified ID of wl_surface is already tie to
> another ID of ivi_surface.
> > - invalid resource: specified ID of wl_surface is not valid in
> server.
> >
> > I think these three is sufficient for client.
> >
> >
> >>> + <entry name="resource_in_use" value="2"
> >>
> >> summary="resource is in use and can not be shared"/>
> >>
> >> What kind of resource does this refer to? It looks like you use it
> >> if someone tries to call surface_create twice on the same surface,
> but
> >> you don't specify.
> >>
> >>> + </enum>
> >>
> >> > +
> >> > + <event name="error">
> >> > + <description summary="server-side error
> >> detected">
> >> > + The ivi compositor encountered error while
> >> processing a request by this
> >> > + application. The error is defined by
> >> argument error_code and optional
> >> > + error_text.
> >> > + If the application requires to associate
> >> this error event to a request,
> >> > + it can
> >> > + 1. send request
> >> > + 2. force display roundtrip
> >> > + 3. check, if error event was
> >> received
> >> > + but this restricts the application to
> >> have only one open request at a time.
> >> > + </description>
> >> > + <arg name="error_code" type="int"/>
> >> > + <arg name="error_text" type="string"
> >> allow-null="true"/>
> >> > + </event>
> >>
> >> Why are you using this rather than the built-in wl_display.error?
> >> The built-in wl_display.error also terminates the client when an
> error
> >> is sent. Under what error conditions would you want the client to
> >> continue?
> >>
> >
> > Good suggestion!
> > According to wayland.xml, error code from 0 to 2 is reserved for
> global.
> > Please teach me there is any manner which number I can use for the
> above object? In the feature, if wayland.xml updated to add new global
> error code to 3, the local number may need to be incremented.
>
> The wl_display.error event is a bit confusing. The
> wl_resource_post_error function takes three arguments. The first
> argument is an object; the last two are an error code and a
> human-readable message string. The error code should be interpreted
> relative to the given object. Therefore, you don't need to worry about
> colliding with the codes defined in wl_display. If the error is
> defined in wl_application you should pass the wl_application resource
> into the error event.
>
> One warning about wl_display.error event: all errors are considered
> fatal and the client gets automatically disconnected. Given the errors
> you listed, this is probably OK. If you want a non-fatal error, you

I see. Thank you. In its usecase, a ivi_application will create several
ivi_surfaces. If it is disconnected, all ivi_surfaces are destroyed and
it will not fit the use case.

So I will consider it to be changed to naming "warning" as event in V2.

Thanks,
Nobuhiko

> should use something else And probably not call it "error" (to avoid
> confusion).
>
> Hope that helps,
> --Jason Ekstrand
>
>>
> > BR,
> > Nobuhiko
> >>>
> >>> +
> >>
> >> > + </interface>
> >> > +
> >> > +</protocol>
> >> > --
> >> > 1.8.3.1
> >> >
> >> > _______________________________________________
> >> > wayland-devel mailing list
> >> > wayland-devel at lists.freedesktop.org
> >> > http://lists.freedesktop.org/mailman/listinfo/wayland-devel [1]
> [1]
> >>
> >>
> >> Links:
> >> ------
> >> [1] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
> [1]
>
>
> Links:
> ------
> [1] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Nobuhiko Tanibata
2014-03-07 13:56:02 UTC
Permalink
Add interface ivi_application, which creates ivi_surface objects tied
to a given wl_surface with a given id. The given id can be used in a
shell to identify which application is assigned to a wl_surface and
layout the surface wherever the shell wants. ivi_surface objects can
be used to receive status of wl_surface in the scenegraph of the
compositor.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- Rename "error" to "warning" because meaning of "error" in wayland is fatal.

protocol/ivi-application.xml | 88 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
create mode 100755 protocol/ivi-application.xml

diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml
new file mode 100755
index 0000000..8659ec6
--- /dev/null
+++ b/protocol/ivi-application.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ivi_application">
+
+ <copyright>
+ Copyright (C) 2013 DENSO CORPORATION
+ Copyright (c) 2013 BMW Car IT GmbH
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ </copyright>
+
+ <interface name="ivi_surface" version="1">
+ <description summary="application interface to surface in ivi compositor"/>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy ivi_surface"/>
+ </request>
+
+ <event name="visibility">
+ <description summary="visibility of surface in ivi compositor has changed">
+ The new visibility state is provided in argument visibility.
+ If visibility is 0, the surface has become invisible.
+ If visibility is not 0, the surface has become visible.
+ </description>
+ <arg name="visibility" type="int"/>
+ </event>
+
+ </interface>
+
+ <interface name="ivi_application" version="1">
+ <description summary="interface for ivi applications to use ivi compositor features"/>
+
+ <request name="surface_create">
+ <description summary="create surface in ivi compositor">
+ surface_create will create a new surface with surface_id in ivi compositor,
+ if it does not yet exists. If the surface with surface_id already exists in
+ ivi compositor, the application content provided in argument surface will
+ be used as surface content. If an other ivi application already registered
+ content for surface with surface_id, an warning event will indicate the problem.
+ </description>
+ <arg name="id_surface" type="uint"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="id" type="new_id" interface="ivi_surface"/>
+ </request>
+
+ <enum name="warning_code">
+ <description summary="possible warning codes returned by ivi compositor">
+ These warning codes define all possible warning codes returned by ivi compositor
+ on server-side warnings.
+ </description>
+ <entry name="invalid_wl_surface" value="1" summary="wl_surface is invalid"/>
+ <entry name="surface_id_in_use" value="2" summary="surface_id is in use and can not be shared"/>
+ </enum>
+
+ <event name="warning">
+ <description summary="server-side warning detected">
+ The ivi compositor encountered warning while processing a request by this
+ application. The warning is defined by argument warning_code and optional
+ warning_text.
+ If the application requires to associate this warning event to a request,
+ it can
+ 1. send request
+ 2. force display roundtrip
+ 3. check, if warning event was received
+ but this restricts the application to have only one open request at a time.
+ </description>
+ <arg name="warning_code" type="int"/>
+ <arg name="warning_text" type="string" allow-null="true"/>
+ </event>
+
+ </interface>
+
+</protocol>
--
1.8.3.1
Jason Ekstrand
2014-03-07 16:39:44 UTC
Permalink
On Mar 7, 2014 7:56 AM, "Nobuhiko Tanibata" <
NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
> Add interface ivi_application, which creates ivi_surface objects tied
> to a given wl_surface with a given id. The given id can be used in a
> shell to identify which application is assigned to a wl_surface and
> layout the surface wherever the shell wants. ivi_surface objects can
> be used to receive status of wl_surface in the scenegraph of the
> compositor.
>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - Rename "error" to "warning" because meaning of "error" in wayland is
fatal.
>
> protocol/ivi-application.xml | 88
++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 88 insertions(+)
> create mode 100755 protocol/ivi-application.xml
>
> diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml
> new file mode 100755
> index 0000000..8659ec6
> --- /dev/null
> +++ b/protocol/ivi-application.xml
> @@ -0,0 +1,88 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<protocol name="ivi_application">
> +
> + <copyright>
> + Copyright (C) 2013 DENSO CORPORATION
> + Copyright (c) 2013 BMW Car IT GmbH
> +
> + Permission is hereby granted, free of charge, to any person
obtaining a copy
> + of this software and associated documentation files (the
"Software"), to deal
> + in the Software without restriction, including without limitation
the rights
> + to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
> + copies of the Software, and to permit persons to whom the Software is
> + furnished to do so, subject to the following conditions:
> +
> + The above copyright notice and this permission notice shall be
included in
> + all copies or substantial portions of the Software.
> +
> + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
> + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
> + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE
> + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER
> + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
> + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN
> + THE SOFTWARE.
> + </copyright>
> +
> + <interface name="ivi_surface" version="1">
> + <description summary="application interface to surface in ivi
compositor"/>
> +
> + <request name="destroy" type="destructor">
> + <description summary="destroy ivi_surface"/>
> + </request>
> +
> + <event name="visibility">
> + <description summary="visibility of surface in ivi
compositor has changed">
> + The new visibility state is provided in argument
visibility.
> + If visibility is 0, the surface has become invisible.
> + If visibility is not 0, the surface has become visible.
> + </description>
> + <arg name="visibility" type="int"/>
> + </event>
> +
> + </interface>
> +
> + <interface name="ivi_application" version="1">
> + <description summary="interface for ivi applications to use ivi
compositor features"/>
> +
> + <request name="surface_create">
> + <description summary="create surface in ivi compositor">
> + surface_create will create a new surface with surface_id
in ivi compositor,
> + if it does not yet exists. If the surface with
surface_id already exists in
> + ivi compositor, the application content provided in
argument surface will
> + be used as surface content. If an other ivi application
already registered
> + content for surface with surface_id, an warning event
will indicate the problem.
> + </description>
> + <arg name="id_surface" type="uint"/>
> + <arg name="surface" type="object" interface="wl_surface"/>
> + <arg name="id" type="new_id" interface="ivi_surface"/>
> + </request>
> +
> + <enum name="warning_code">
> + <description summary="possible warning codes returned by ivi
compositor">
> + These warning codes define all possible warning codes
returned by ivi compositor
> + on server-side warnings.
> + </description>
> + <entry name="invalid_wl_surface" value="1"
summary="wl_surface is invalid"/>
> + <entry name="surface_id_in_use" value="2"
summary="surface_id is in use and can not be shared"/>
> + </enum>

I have a couple more thoughts about these errors/warnings. For one, I
think some of these should be errors. For instance, there is no way that
the given wl_surface will be invalid unless the client has destroyed it.
Honestly, I'm not even sure if it's possible, given how libwayland is
written, to get a truely invalid wl_surface. From what you've written in
previous e-mails, I can't quite tell but it sounds like you want to prevent
a client from attaaching multiple ivi_surface objects (and IVI ID's) to the
same surface. If this is the case then doing so should probably also be a
fatal error because that means the client was written wrong.

With regards to what happens if a client tries to use an ID that's already
in use, I'm not 100% sure what to do there. You know IVI systems better
than I do. Is this something that happens with some degree of regularity?
Or is this something that only happens if the there is a mistake in the
client code? I'll leave that up to you.

That said, if there is an issue, you need to explicitly say what happens to
the newly created ivi_surface object. The Wayland protocol has no concept
of returning NULL. Whenever a request or event is fired which has a new_id
parameter, both client and server-side objects always get created. If
surface_create can throw a non-fatal error, we need to decide what happens
to the new ivi_surface object. One way to do this would be to have the
error/warning event on the ivi_surface itself instead of on
ivi_application. Then the client would know that if it recieves the
error/warning, that it needs to destroy the corresponding ivi_surface.
Otherwise, like you note below, they have to roundtrip after every call to
ivi_application.surface_create.

Thanks,
--Jason Ekstrand

> +
> + <event name="warning">
> + <description summary="server-side warning detected">
> + The ivi compositor encountered warning while processing
a request by this
> + application. The warning is defined by argument
warning_code and optional
> + warning_text.
> + If the application requires to associate this warning
event to a request,
> + it can
> + 1. send request
> + 2. force display roundtrip
> + 3. check, if warning event was received
> + but this restricts the application to have only one
open request at a time.
> + </description>
> + <arg name="warning_code" type="int"/>
> + <arg name="warning_text" type="string" allow-null="true"/>
> + </event>
> +
> + </interface>
> +
> +</protocol>
> --
> 1.8.3.1
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20140307/5aae03b2/attachment-0001.html>
Pekka Paalanen
2014-03-10 08:41:38 UTC
Permalink
On Fri, 7 Mar 2014 10:39:44 -0600
Jason Ekstrand <jason at jlekstrand.net> wrote:

> On Mar 7, 2014 7:56 AM, "Nobuhiko Tanibata" <
> NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
> >
> > Add interface ivi_application, which creates ivi_surface objects
> > tied to a given wl_surface with a given id. The given id can be
> > used in a shell to identify which application is assigned to a
> > wl_surface and layout the surface wherever the shell wants.
> > ivi_surface objects can be used to receive status of wl_surface in
> > the scenegraph of the compositor.
> >
> > Signed-off-by: Nobuhiko Tanibata
> > <NOBUHIKO_TANIBATA at xddp.denso.co.jp> ---
> >
> > Changes for v2:
> > - Rename "error" to "warning" because meaning of "error" in
> > wayland is
> fatal.
> >
> > protocol/ivi-application.xml | 88
> ++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 88 insertions(+)
> > create mode 100755 protocol/ivi-application.xml
> >
> > diff --git a/protocol/ivi-application.xml
> > b/protocol/ivi-application.xml new file mode 100755
> > index 0000000..8659ec6
> > --- /dev/null
> > +++ b/protocol/ivi-application.xml
> > @@ -0,0 +1,88 @@
> > +<?xml version="1.0" encoding="UTF-8"?>
> > +<protocol name="ivi_application">
> > +
> > + <copyright>
> > + Copyright (C) 2013 DENSO CORPORATION
> > + Copyright (c) 2013 BMW Car IT GmbH
> > +
> > + Permission is hereby granted, free of charge, to any person
> obtaining a copy
> > + of this software and associated documentation files (the
> "Software"), to deal
> > + in the Software without restriction, including without
> > limitation
> the rights
> > + to use, copy, modify, merge, publish, distribute, sublicense,
> > and/or
> sell
> > + copies of the Software, and to permit persons to whom the
> > Software is
> > + furnished to do so, subject to the following conditions:
> > +
> > + The above copyright notice and this permission notice shall be
> included in
> > + all copies or substantial portions of the Software.
> > +
> > + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> > + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> > + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
> > EVENT
> SHALL THE
> > + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> > OR
> OTHER
> > + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING FROM,
> > + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> DEALINGS IN
> > + THE SOFTWARE.
> > + </copyright>
> > +
> > + <interface name="ivi_surface" version="1">
> > + <description summary="application interface to surface in
> > ivi
> compositor"/>
> > +
> > + <request name="destroy" type="destructor">
> > + <description summary="destroy ivi_surface"/>
> > + </request>
> > +
> > + <event name="visibility">
> > + <description summary="visibility of surface in ivi
> compositor has changed">
> > + The new visibility state is provided in argument
> visibility.
> > + If visibility is 0, the surface has become
> > invisible.
> > + If visibility is not 0, the surface has become
> > visible.
> > + </description>
> > + <arg name="visibility" type="int"/>
> > + </event>
> > +
> > + </interface>
> > +
> > + <interface name="ivi_application" version="1">
> > + <description summary="interface for ivi applications to
> > use ivi
> compositor features"/>
> > +
> > + <request name="surface_create">
> > + <description summary="create surface in ivi
> > compositor">
> > + surface_create will create a new surface with
> > surface_id
> in ivi compositor,
> > + if it does not yet exists. If the surface with
> surface_id already exists in
> > + ivi compositor, the application content provided in
> argument surface will
> > + be used as surface content. If an other ivi
> > application
> already registered
> > + content for surface with surface_id, an warning
> > event
> will indicate the problem.
> > + </description>
> > + <arg name="id_surface" type="uint"/>
> > + <arg name="surface" type="object"
> > interface="wl_surface"/>
> > + <arg name="id" type="new_id" interface="ivi_surface"/>
> > + </request>
> > +
> > + <enum name="warning_code">
> > + <description summary="possible warning codes returned
> > by ivi
> compositor">
> > + These warning codes define all possible warning
> > codes
> returned by ivi compositor
> > + on server-side warnings.
> > + </description>
> > + <entry name="invalid_wl_surface" value="1"
> summary="wl_surface is invalid"/>
> > + <entry name="surface_id_in_use" value="2"
> summary="surface_id is in use and can not be shared"/>
> > + </enum>
>
> I have a couple more thoughts about these errors/warnings. For one, I
> think some of these should be errors. For instance, there is no way
> that the given wl_surface will be invalid unless the client has
> destroyed it. Honestly, I'm not even sure if it's possible, given how
> libwayland is written, to get a truely invalid wl_surface. From what
> you've written in previous e-mails, I can't quite tell but it sounds
> like you want to prevent a client from attaaching multiple
> ivi_surface objects (and IVI ID's) to the same surface. If this is
> the case then doing so should probably also be a fatal error because
> that means the client was written wrong.
>
> With regards to what happens if a client tries to use an ID that's
> already in use, I'm not 100% sure what to do there. You know IVI
> systems better than I do. Is this something that happens with some
> degree of regularity? Or is this something that only happens if the
> there is a mistake in the client code? I'll leave that up to you.
>
> That said, if there is an issue, you need to explicitly say what
> happens to the newly created ivi_surface object. The Wayland
> protocol has no concept of returning NULL. Whenever a request or
> event is fired which has a new_id parameter, both client and
> server-side objects always get created. If surface_create can throw
> a non-fatal error, we need to decide what happens to the new
> ivi_surface object. One way to do this would be to have the
> error/warning event on the ivi_surface itself instead of on
> ivi_application. Then the client would know that if it recieves the
> error/warning, that it needs to destroy the corresponding
> ivi_surface. Otherwise, like you note below, they have to roundtrip
> after every call to ivi_application.surface_create.

Hi Nobuhiko,

Jason pretty much covered everything that came to my mind, too.

I just want to stress, that if a problem is caused by e.g. bad
IVI-system configuration done by the system manufacturer rather than
something the end user did, then I think you should keep to fatal
errors. If a car manufacturer or a software vendor configures or codes
something wrong, you really want to catch all those errors ASAP.
Killing the whole client is a good way to point out such error
conditions that really should never happen at runtime. Conflicting
surface ID thing sounds like it is the system maker's fault, not an end
user mistake.

OTOH, if these problem cases can happen when the end user does
something wrong, e.g. tries to open an application twice or whatever,
the first thing would be to make sure the UI prevents such things from
occurring in the first place. If you still need non-fatal errors in the
protocol, then you have to have a solid plan on what happens with the
request that caused it. Jason explained it well, you have to define how
the already created protocol object works after the error has occurred
in the compositor, i.e. even before the client receives the error
event. The client might send requests to or requests referring the
failed object before it processes the error event. You also should say
something about how the client is expected to recover from this error.
If the client is not disconnected, there must be a way to recover
smoothly.

Jason's point about avoiding the roundtrip is a very good one.

I haven't read the rest of the patches yet, but if you have error
events defined in other protocol parts, the same comments apply.

Personally I would hope for some more explanations on what the "ID" is,
and how it is used, or at least a pointer in the .xml to more extensive
documentation. It is quite odd to see numeric IDs passed manually in
Wayland protocol.


Thanks,
pq

> > +
> > + <event name="warning">
> > + <description summary="server-side warning detected">
> > + The ivi compositor encountered warning while
> > processing
> a request by this
> > + application. The warning is defined by argument
> warning_code and optional
> > + warning_text.
> > + If the application requires to associate this
> > warning
> event to a request,
> > + it can
> > + 1. send request
> > + 2. force display roundtrip
> > + 3. check, if warning event was received
> > + but this restricts the application to have only
> > one
> open request at a time.
> > + </description>
> > + <arg name="warning_code" type="int"/>
> > + <arg name="warning_text" type="string"
> > allow-null="true"/>
> > + </event>
> > +
> > + </interface>
> > +
> > +</protocol>
> > --
> > 1.8.3.1
> >
> > _______________________________________________
> > wayland-devel mailing list
> > wayland-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Nobuhiko Tanibata
2014-03-10 10:26:10 UTC
Permalink
2014-03-10 17:41 ? Pekka Paalanen ????????:
> On Fri, 7 Mar 2014 10:39:44 -0600
> Jason Ekstrand <jason at jlekstrand.net> wrote:
>
>> On Mar 7, 2014 7:56 AM, "Nobuhiko Tanibata" <
>> NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>> >
>> > Add interface ivi_application, which creates ivi_surface objects
>> > tied to a given wl_surface with a given id. The given id can be
>> > used in a shell to identify which application is assigned to a
>> > wl_surface and layout the surface wherever the shell wants.
>> > ivi_surface objects can be used to receive status of wl_surface in
>> > the scenegraph of the compositor.
>> >
>> > Signed-off-by: Nobuhiko Tanibata
>> > <NOBUHIKO_TANIBATA at xddp.denso.co.jp> ---
>> >
>> > Changes for v2:
>> > - Rename "error" to "warning" because meaning of "error" in
>> > wayland is
>> fatal.
>> >
>> > protocol/ivi-application.xml | 88
>> ++++++++++++++++++++++++++++++++++++++++++++
>> > 1 file changed, 88 insertions(+)
>> > create mode 100755 protocol/ivi-application.xml
>> >
>> > diff --git a/protocol/ivi-application.xml
>> > b/protocol/ivi-application.xml new file mode 100755
>> > index 0000000..8659ec6
>> > --- /dev/null
>> > +++ b/protocol/ivi-application.xml
>> > @@ -0,0 +1,88 @@
>> > +<?xml version="1.0" encoding="UTF-8"?>
>> > +<protocol name="ivi_application">
>> > +
>> > + <copyright>
>> > + Copyright (C) 2013 DENSO CORPORATION
>> > + Copyright (c) 2013 BMW Car IT GmbH
>> > +
>> > + Permission is hereby granted, free of charge, to any person
>> obtaining a copy
>> > + of this software and associated documentation files (the
>> "Software"), to deal
>> > + in the Software without restriction, including without
>> > limitation
>> the rights
>> > + to use, copy, modify, merge, publish, distribute, sublicense,
>> > and/or
>> sell
>> > + copies of the Software, and to permit persons to whom the
>> > Software is
>> > + furnished to do so, subject to the following conditions:
>> > +
>> > + The above copyright notice and this permission notice shall be
>> included in
>> > + all copies or substantial portions of the Software.
>> > +
>> > + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS OR
>> > + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> MERCHANTABILITY,
>> > + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
>> > EVENT
>> SHALL THE
>> > + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
>> > OR
>> OTHER
>> > + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> ARISING FROM,
>> > + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> DEALINGS IN
>> > + THE SOFTWARE.
>> > + </copyright>
>> > +
>> > + <interface name="ivi_surface" version="1">
>> > + <description summary="application interface to surface in
>> > ivi
>> compositor"/>
>> > +
>> > + <request name="destroy" type="destructor">
>> > + <description summary="destroy ivi_surface"/>
>> > + </request>
>> > +
>> > + <event name="visibility">
>> > + <description summary="visibility of surface in ivi
>> compositor has changed">
>> > + The new visibility state is provided in argument
>> visibility.
>> > + If visibility is 0, the surface has become
>> > invisible.
>> > + If visibility is not 0, the surface has become
>> > visible.
>> > + </description>
>> > + <arg name="visibility" type="int"/>
>> > + </event>
>> > +
>> > + </interface>
>> > +
>> > + <interface name="ivi_application" version="1">
>> > + <description summary="interface for ivi applications to
>> > use ivi
>> compositor features"/>
>> > +
>> > + <request name="surface_create">
>> > + <description summary="create surface in ivi
>> > compositor">
>> > + surface_create will create a new surface with
>> > surface_id
>> in ivi compositor,
>> > + if it does not yet exists. If the surface with
>> surface_id already exists in
>> > + ivi compositor, the application content provided in
>> argument surface will
>> > + be used as surface content. If an other ivi
>> > application
>> already registered
>> > + content for surface with surface_id, an warning
>> > event
>> will indicate the problem.
>> > + </description>
>> > + <arg name="id_surface" type="uint"/>
>> > + <arg name="surface" type="object"
>> > interface="wl_surface"/>
>> > + <arg name="id" type="new_id" interface="ivi_surface"/>
>> > + </request>
>> > +
>> > + <enum name="warning_code">
>> > + <description summary="possible warning codes returned
>> > by ivi
>> compositor">
>> > + These warning codes define all possible warning
>> > codes
>> returned by ivi compositor
>> > + on server-side warnings.
>> > + </description>
>> > + <entry name="invalid_wl_surface" value="1"
>> summary="wl_surface is invalid"/>
>> > + <entry name="surface_id_in_use" value="2"
>> summary="surface_id is in use and can not be shared"/>
>> > + </enum>
>>
>> I have a couple more thoughts about these errors/warnings. For one, I
>> think some of these should be errors. For instance, there is no way
>> that the given wl_surface will be invalid unless the client has
>> destroyed it. Honestly, I'm not even sure if it's possible, given how
>> libwayland is written, to get a truely invalid wl_surface. From what
>> you've written in previous e-mails, I can't quite tell but it sounds
>> like you want to prevent a client from attaaching multiple
>> ivi_surface objects (and IVI ID's) to the same surface. If this is
>> the case then doing so should probably also be a fatal error because
>> that means the client was written wrong.
>>
>> With regards to what happens if a client tries to use an ID that's
>> already in use, I'm not 100% sure what to do there. You know IVI
>> systems better than I do. Is this something that happens with some
>> degree of regularity? Or is this something that only happens if the
>> there is a mistake in the client code? I'll leave that up to you.
>>

Hi Jason and pq,

- invalid_wl_surface
In the automotive use case, the worst case may need to be taken account.
In this use case, One application, e.g. Car navigation, will create
several ivi_surfaces in one process, its means one connection. These
surfaces for Map, traffic info, corner view, and so on. If it is
disconnected when something happen on creation of only ivi_surface, All
surfaces of car navigation will not work. Ideally, we shall remove all
bugs and release well-tested application to prevent it. However its
application required to work partially as fault tolerant. That's way, I
propose it as warnings and it is really fatal to the system, the Car
navigation application will notify it to the central controller to
decide whether the Car navigation application shall be restarted or not.

>> That said, if there is an issue, you need to explicitly say what
>> happens to the newly created ivi_surface object. The Wayland
>> protocol has no concept of returning NULL. Whenever a request or
>> event is fired which has a new_id parameter, both client and
>> server-side objects always get created. If surface_create can throw
>> a non-fatal error, we need to decide what happens to the new
>> ivi_surface object. One way to do this would be to have the
>> error/warning event on the ivi_surface itself instead of on
>> ivi_application. Then the client would know that if it recieves the
>> error/warning, that it needs to destroy the corresponding
>> ivi_surface. Otherwise, like you note below, they have to roundtrip
>> after every call to ivi_application.surface_create.
>

In case of that I have to do it, I will follow your suggested way. Thank
you for good ideas.

> Hi Nobuhiko,
>
> Jason pretty much covered everything that came to my mind, too.
>
> I just want to stress, that if a problem is caused by e.g. bad
> IVI-system configuration done by the system manufacturer rather than
> something the end user did, then I think you should keep to fatal
> errors. If a car manufacturer or a software vendor configures or codes
> something wrong, you really want to catch all those errors ASAP.
> Killing the whole client is a good way to point out such error
> conditions that really should never happen at runtime. Conflicting
> surface ID thing sounds like it is the system maker's fault, not an end
> user mistake.
>

Thank you for comment as well. As I mention it in the above, I want to
suggest the above mentioned use case.

> OTOH, if these problem cases can happen when the end user does
> something wrong, e.g. tries to open an application twice or whatever,
> the first thing would be to make sure the UI prevents such things from
> occurring in the first place.
I agree with you. UI shall prevent it.

> If you still need non-fatal errors in the
> protocol, then you have to have a solid plan on what happens with the
> request that caused it. Jason explained it well, you have to define how
> the already created protocol object works after the error has occurred
> in the compositor, i.e. even before the client receives the error
> event. The client might send requests to or requests referring the
> failed object before it processes the error event. You also should say
> something about how the client is expected to recover from this error.
> If the client is not disconnected, there must be a way to recover
> smoothly.
>

Yes, you are right. I will add clear comment in ivi_application.xml to
say how to
follow such a error.

> Jason's point about avoiding the roundtrip is a very good one.
>
> I haven't read the rest of the patches yet, but if you have error
> events defined in other protocol parts, the same comments apply.
>
> Personally I would hope for some more explanations on what the "ID" is,
> and how it is used, or at least a pointer in the .xml to more extensive
> documentation. It is quite odd to see numeric IDs passed manually in
> Wayland protocol.
>

Traditionally, automotive system list up all applications which will be
installed to the application with numeric IDs. The text might be OK to
manage them. Additionally, in the future, certified download
applications are also manged by IDs. This might be easier way then using
just a text. I will add such description to protocol summary.

Thank you,
Nobuhiko

>
> Thanks,
> pq
>
>> > +
>> > + <event name="warning">
>> > + <description summary="server-side warning detected">
>> > + The ivi compositor encountered warning while
>> > processing
>> a request by this
>> > + application. The warning is defined by argument
>> warning_code and optional
>> > + warning_text.
>> > + If the application requires to associate this
>> > warning
>> event to a request,
>> > + it can
>> > + 1. send request
>> > + 2. force display roundtrip
>> > + 3. check, if warning event was received
>> > + but this restricts the application to have only
>> > one
>> open request at a time.
>> > + </description>
>> > + <arg name="warning_code" type="int"/>
>> > + <arg name="warning_text" type="string"
>> > allow-null="true"/>
>> > + </event>
>> > +
>> > + </interface>
>> > +
>> > +</protocol>
>> > --
>> > 1.8.3.1
>> >
>> > _______________________________________________
>> > wayland-devel mailing list
>> > wayland-devel at lists.freedesktop.org
>> > http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Pekka Paalanen
2014-03-10 13:01:47 UTC
Permalink
On Fri, 7 Mar 2014 22:56:02 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> Add interface ivi_application, which creates ivi_surface objects tied
> to a given wl_surface with a given id. The given id can be used in a
> shell to identify which application is assigned to a wl_surface and
> layout the surface wherever the shell wants. ivi_surface objects can
> be used to receive status of wl_surface in the scenegraph of the
> compositor.
>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - Rename "error" to "warning" because meaning of "error" in wayland is fatal.
>
> protocol/ivi-application.xml | 88 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 88 insertions(+)
> create mode 100755 protocol/ivi-application.xml
>
> diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml
> new file mode 100755
> index 0000000..8659ec6
> --- /dev/null
> +++ b/protocol/ivi-application.xml
> @@ -0,0 +1,88 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<protocol name="ivi_application">
> +
> + <copyright>
> + Copyright (C) 2013 DENSO CORPORATION
> + Copyright (c) 2013 BMW Car IT GmbH
> +
> + Permission is hereby granted, free of charge, to any person obtaining a copy
> + of this software and associated documentation files (the "Software"), to deal
> + in the Software without restriction, including without limitation the rights
> + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + copies of the Software, and to permit persons to whom the Software is
> + furnished to do so, subject to the following conditions:
> +
> + The above copyright notice and this permission notice shall be included in
> + all copies or substantial portions of the Software.
> +
> + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + THE SOFTWARE.
> + </copyright>
> +
> + <interface name="ivi_surface" version="1">
> + <description summary="application interface to surface in ivi compositor"/>

Hi,

one more thing that came to my mind: you need to define what happens
when the wl_surface, that was given to ivi_application.surface_create
to create this ivi_surface, gets destroyed while the ivi_surface still
exists.


Thanks,
pq

> +
> + <request name="destroy" type="destructor">
> + <description summary="destroy ivi_surface"/>
> + </request>
> +
> + <event name="visibility">
> + <description summary="visibility of surface in ivi compositor has changed">
> + The new visibility state is provided in argument visibility.
> + If visibility is 0, the surface has become invisible.
> + If visibility is not 0, the surface has become visible.
> + </description>
> + <arg name="visibility" type="int"/>
> + </event>
> +
> + </interface>
> +
> + <interface name="ivi_application" version="1">
> + <description summary="interface for ivi applications to use ivi compositor features"/>
> +
> + <request name="surface_create">
> + <description summary="create surface in ivi compositor">
> + surface_create will create a new surface with surface_id in ivi compositor,
> + if it does not yet exists. If the surface with surface_id already exists in
> + ivi compositor, the application content provided in argument surface will
> + be used as surface content. If an other ivi application already registered
> + content for surface with surface_id, an warning event will indicate the problem.
> + </description>
> + <arg name="id_surface" type="uint"/>
> + <arg name="surface" type="object" interface="wl_surface"/>
> + <arg name="id" type="new_id" interface="ivi_surface"/>
> + </request>
> +
> + <enum name="warning_code">
> + <description summary="possible warning codes returned by ivi compositor">
> + These warning codes define all possible warning codes returned by ivi compositor
> + on server-side warnings.
> + </description>
> + <entry name="invalid_wl_surface" value="1" summary="wl_surface is invalid"/>
> + <entry name="surface_id_in_use" value="2" summary="surface_id is in use and can not be shared"/>
> + </enum>
> +
> + <event name="warning">
> + <description summary="server-side warning detected">
> + The ivi compositor encountered warning while processing a request by this
> + application. The warning is defined by argument warning_code and optional
> + warning_text.
> + If the application requires to associate this warning event to a request,
> + it can
> + 1. send request
> + 2. force display roundtrip
> + 3. check, if warning event was received
> + but this restricts the application to have only one open request at a time.
> + </description>
> + <arg name="warning_code" type="int"/>
> + <arg name="warning_text" type="string" allow-null="true"/>
> + </event>
> +
> + </interface>
> +
> +</protocol>
Nobuhiko Tanibata
2014-03-12 15:03:21 UTC
Permalink
Add interface ivi_application, which creates ivi_surface objects tied
to a given wl_surface with a given id. The given id can be used in a
shell to identify which application is assigned to a wl_surface and
layout the surface wherever the shell wants. ivi_surface objects can
be used to receive status of wl_surface in the scenegraph of the
compositor.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- Rename "error" to "warning" because meaning of "error" in wayland is fatal.

Changes for v3:
- Move "warning" from ivi_application to ivi_surface.
- Squash Makefile.
- Add description to ivi_surface:destroy.
- Update description of ivi_application:surface_create.

protocol/Makefile.am | 3 +-
protocol/ivi-application.xml | 96 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 98 insertions(+), 1 deletion(-)
create mode 100644 protocol/ivi-application.xml

diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 5e331a7..9913f16 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -8,7 +8,8 @@ protocol_sources = \
text-cursor-position.xml \
wayland-test.xml \
xdg-shell.xml \
- scaler.xml
+ scaler.xml \
+ ivi-application.xml

if HAVE_XMLLINT
.PHONY: validate
diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml
new file mode 100644
index 0000000..8f5c23d
--- /dev/null
+++ b/protocol/ivi-application.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ivi_application">
+
+ <copyright>
+ Copyright (C) 2013 DENSO CORPORATION
+ Copyright (c) 2013 BMW Car IT GmbH
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ </copyright>
+
+ <interface name="ivi_surface" version="1">
+ <description summary="application interface to surface in ivi compositor"/>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy ivi_surface">
+ This removes link from surface_id to wl_surface. However it doesn't
+ remove internal properties, e.g. position, visibility, and so on, which
+ is set to the surface_id. This means when some issues happen on clients
+ and a ivi_surface is destroyed, it can use previous properties immediately
+ without setting it again if it restarts and attaches new wl_surface to
+ the same surface_id.
+ </description>
+ </request>
+
+ <event name="visibility">
+ <description summary="visibility of surface in ivi compositor has changed">
+ The new visibility state is provided in argument visibility.
+ If visibility is 0, the surface has become invisible.
+ If visibility is not 0, the surface has become visible.
+ </description>
+ <arg name="visibility" type="int"/>
+ </event>
+
+ <enum name="warning_code">
+ <description summary="possible warning codes returned by ivi compositor">
+ These warning codes define all possible warning codes returned by ivi compositor
+ on server-side warnings.
+ invalid_wl_surface: invalid wl_surface is set. This happen if wl_surface is destroy before this.
+ surface_id_in_use: surface_id is already assigned by another application.
+ </description>
+ <entry name="invalid_wl_surface" value="1" summary="wl_surface is invalid"/>
+ <entry name="surface_id_in_use" value="2" summary="surface_id is in use and can not be shared"/>
+ </enum>
+
+ <event name="warning">
+ <description summary="server-side warning detected">
+ The ivi compositor encountered warning while processing a request by this
+ application. The warning is defined by argument warning_code and optional
+ warning_text. If the warning is detected, client shall destroy the ivi_surface
+ object.
+ </description>
+ <arg name="warning_code" type="int"/>
+ <arg name="warning_text" type="string" allow-null="true"/>
+ </event>
+
+ </interface>
+
+ <interface name="ivi_application" version="1">
+ <description summary="interface for ivi applications to use ivi compositor features"/>
+
+ <request name="surface_create">
+ <description summary="create ivi_surface with numeric ID in ivi compositor">
+ surface_create will create a interface:ivi_surface with numeric ID; surface_id in
+ ivi compositor. These surface_ids are defined as unique in the system to identify
+ it inside of ivi compositor. The ivi compositor implements business logic how to
+ set properties of the surface with surface_id according to status of the system.
+ E.g. a unique ID for Car Navigation application is used for implementing special
+ logic of the application about where it shall be located. Created ivi_surface
+ notifies warnings when following situation happens,
+ - Invalid wl_surface is set. This happen if wl_surface is destroy before this.
+ - surface_id is already assigned by another application.
+ </description>
+ <arg name="id_surface" type="uint"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="id" type="new_id" interface="ivi_surface"/>
+ </request>
+
+ </interface>
+
+</protocol>
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 09:54:41 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
protocol/Makefile.am | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 5e331a7..9913f16 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -8,7 +8,8 @@ protocol_sources = \
text-cursor-position.xml \
wayland-test.xml \
xdg-shell.xml \
- scaler.xml
+ scaler.xml \
+ ivi-application.xml

if HAVE_XMLLINT
.PHONY: validate
--
1.8.3.1
Pekka Paalanen
2014-03-10 10:00:20 UTC
Permalink
On Thu, 6 Mar 2014 18:54:41 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
> protocol/Makefile.am | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/protocol/Makefile.am b/protocol/Makefile.am
> index 5e331a7..9913f16 100644
> --- a/protocol/Makefile.am
> +++ b/protocol/Makefile.am
> @@ -8,7 +8,8 @@ protocol_sources = \
> text-cursor-position.xml \
> wayland-test.xml \
> xdg-shell.xml \
> - scaler.xml
> + scaler.xml \
> + ivi-application.xml
>
> if HAVE_XMLLINT
> .PHONY: validate

Hi,

you can squash this into the patch that adds the .xml file.


Thanks,
pq
Nobuhiko Tanibata
2014-03-11 05:54:04 UTC
Permalink
Hi pq,

I will embed this patch to previous one.
Regarding other patch, I also did the same thing, I will enclose update
of Makefile to corresponding patch which update e.g. *.c.

BR,
Nobuhiko

2014-03-10 19:00 ? Pekka Paalanen ????????:
> On Thu, 6 Mar 2014 18:54:41 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>> protocol/Makefile.am | 3 ++-
>> 1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/protocol/Makefile.am b/protocol/Makefile.am
>> index 5e331a7..9913f16 100644
>> --- a/protocol/Makefile.am
>> +++ b/protocol/Makefile.am
>> @@ -8,7 +8,8 @@ protocol_sources = \
>> text-cursor-position.xml \
>> wayland-test.xml \
>> xdg-shell.xml \
>> - scaler.xml
>> + scaler.xml \
>> + ivi-application.xml
>>
>> if HAVE_XMLLINT
>> .PHONY: validate
>
> Hi,
>
> you can squash this into the patch that adds the .xml file.
>
>
> Thanks,
> pq
Nobuhiko Tanibata
2014-03-06 09:56:58 UTC
Permalink
In-Vehicle Infotainment system traditionally manages surfaces with global
identification. A protocol, ivi_application, supports such a feature by
implementing a request, ivi_application::surface_creation defined in
ivi_application.xml. Additionally, it initialize a library, weston-layout,
to manage properties of surfaces and group surfaces in layer. In detail,
refer library, weston_layout.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
ivi-shell/ivi-shell.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 333 insertions(+)
create mode 100644 ivi-shell/ivi-shell.c

diff --git a/ivi-shell/ivi-shell.c b/ivi-shell/ivi-shell.c
new file mode 100644
index 0000000..f4c4d25
--- /dev/null
+++ b/ivi-shell/ivi-shell.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/**
+ * ivi-shell supports a type of shell for In-Vehicle Infotainment system.
+ * In-Vehicle Infotainment system traditionally manages surfaces with global
+ * identification. A protocol, ivi_application, supports such a feature
+ * by implementing a request, ivi_application::surface_creation defined in
+ * ivi_application.xml.
+ *
+ * Additionally, it initialize a library, weston-layout, to manage properties of
+ * surfaces and group surfaces in layer. In detail, refer weston_layout.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+
+#include "compositor.h"
+#include "ivi-application-server-protocol.h"
+#include "weston-layout.h"
+
+struct ivi_shell;
+
+struct ivi_shell_surface
+{
+ struct ivi_shell *shell;
+ struct weston_layout_surface *layout_surface;
+
+ struct weston_surface *surface;
+ uint32_t id_surface;
+
+ int32_t width;
+ int32_t height;
+
+ struct wl_list link;
+};
+
+struct ivi_shell
+{
+ struct wl_resource *resource;
+ struct wl_listener destroy_listener;
+
+ struct weston_compositor *compositor;
+ struct weston_seat *seat;
+
+ struct wl_list list_surface;
+};
+
+/* ------------------------------------------------------------------------- */
+/* common functions */
+/* ------------------------------------------------------------------------- */
+
+static void
+configure(struct weston_view *view, float x, float y)
+{
+ if (view != NULL) {
+ weston_view_set_position(view, x, y);
+ weston_view_update_transform(view);
+ }
+}
+
+/**
+ * Implementation of ivi_surface
+ */
+
+static void
+ivi_shell_surface_configure(struct weston_surface *, int32_t, int32_t);
+
+static struct ivi_shell_surface *
+get_ivi_shell_surface(struct weston_surface *surface)
+{
+ if (surface->configure == ivi_shell_surface_configure) {
+ return surface->configure_private;
+ } else {
+ return NULL;
+ }
+}
+
+static void
+ivi_shell_surface_configure(struct weston_surface *es,
+ int32_t sx, int32_t sy)
+{
+ struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(es);
+ struct weston_view *view = NULL;
+ float from_x = 0.0f;
+ float from_y = 0.0f;
+ float to_x = 0.0f;
+ float to_y = 0.0f;
+
+ if ((es->width == 0) || (es->height == 0) || (ivisurf == NULL)) {
+ return;
+ }
+
+ view = weston_layout_get_weston_view(ivisurf->layout_surface);
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->width != es->width || ivisurf->height != es->height) {
+
+ ivisurf->width = es->width;
+ ivisurf->height = es->height;
+
+ weston_view_to_global_float(view, 0, 0, &from_x, &from_y);
+ weston_view_to_global_float(view, sx, sy, &to_x, &to_y);
+ configure(view,
+ view->geometry.x + to_x - from_x,
+ view->geometry.y + to_y - from_y);
+
+ weston_layout_surfaceConfigure(ivisurf->layout_surface, es->width, es->height);
+ }
+}
+
+static void
+surface_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource);
+ struct ivi_shell *shell = ivisurf->shell;
+
+ weston_layout_surfaceRemove(ivisurf->layout_surface);
+
+ ivisurf->surface->configure = NULL;
+ ivisurf->surface->configure_private = NULL;
+
+ if (!wl_list_empty(&ivisurf->link)) {
+ wl_list_remove(&ivisurf->link);
+ }
+ wl_list_init(&shell->list_surface);
+
+ free(ivisurf);
+ ivisurf = NULL;
+}
+
+static const struct ivi_surface_interface surface_implementation = {
+ surface_destroy,
+};
+
+static struct ivi_shell_surface *
+is_surf_in_surfaces(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct ivi_shell_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Implementation of ivi_application::surface_create.
+ * Creating new ivi_shell_surface with identification to identify the surface
+ * in the system.
+ */
+static void
+application_surface_create(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface,
+ struct wl_resource *surface_resource,
+ uint32_t id)
+{
+ struct ivi_shell *shell = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *layout_surface = NULL;
+ struct ivi_shell_surface *ivisurf = NULL;
+ struct weston_surface *es = NULL;
+
+ es = wl_resource_get_user_data(surface_resource);
+ if (es == NULL) {
+ weston_log("application_surface_create: invalid surface\n");
+ return;
+ }
+
+ ivisurf = is_surf_in_surfaces(&shell->list_surface, id_surface);
+
+ layout_surface = weston_layout_surfaceCreate(es, id_surface);
+ if (layout_surface == NULL) {
+//FIXME
+ weston_log("id_surface is already created\n");
+
+ ivisurf->surface = es;
+ ivisurf->width = 0;
+ ivisurf->height = 0;
+
+ es->configure = ivi_shell_surface_configure;
+ es->configure_private = ivisurf;
+
+ resource = wl_resource_create(client, &ivi_surface_interface, 1, id);
+ if (resource == NULL) {
+ weston_log("couldn't get surface object");
+ return;
+ }
+
+ wl_resource_set_implementation(resource,
+ &surface_implementation,
+ ivisurf, NULL);
+ return;
+ }
+
+ ivisurf = calloc(1, sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ wl_list_init(&ivisurf->link);
+ ivisurf->shell = shell;
+ ivisurf->layout_surface = layout_surface;
+ ivisurf->surface = es;
+ ivisurf->id_surface = id_surface;
+ ivisurf->width = 0;
+ ivisurf->height = 0;
+
+ es->configure = ivi_shell_surface_configure;
+ es->configure_private = ivisurf;
+
+ wl_list_insert(&shell->list_surface, &ivisurf->link);
+
+ resource = wl_resource_create(client, &ivi_surface_interface, 1, id);
+ if (resource == NULL) {
+ weston_log("couldn't get surface object");
+ return;
+ }
+
+ wl_resource_set_implementation(resource,
+ &surface_implementation,
+ ivisurf, NULL);
+}
+
+static const struct ivi_application_interface application_implementation = {
+ application_surface_create
+};
+
+static void
+bind_ivi_application(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct ivi_shell *shell = data;
+ struct wl_resource *resource = NULL;
+
+ resource = wl_resource_create(client, &ivi_application_interface, 1, id);
+
+ wl_resource_set_implementation(resource,
+ &application_implementation,
+ shell, NULL);
+}
+
+/**
+ * Initialization/destruction method of ivi-shell
+ */
+static void
+shell_destroy(struct wl_listener *listener, void *data)
+{
+ struct ivi_shell *shell = NULL;
+
+ shell = container_of(listener, struct ivi_shell, destroy_listener);
+
+ free(shell);
+ shell = NULL;
+}
+
+static void
+init_ivi_shell(struct weston_compositor *ec, struct ivi_shell *shell)
+{
+ shell->compositor = ec;
+
+ wl_list_init(&ec->layer_list);
+ wl_list_init(&shell->list_surface);
+}
+
+/**
+ * Initialization of ivi-shell. A library, weston_layout, is also initialized
+ * here by calling weston_layout_initWithCompositor.
+ *
+ */
+
+WL_EXPORT int
+module_init(struct weston_compositor *ec,
+ int *argc, char *argv[])
+{
+ struct ivi_shell *shell = NULL;
+ struct weston_seat *seat = NULL;
+
+ shell = calloc(1, sizeof *shell);
+ if (shell == NULL) {
+ return -1;
+ }
+
+ init_ivi_shell(ec, shell);
+ weston_layout_initWithCompositor(ec);
+
+ shell->destroy_listener.notify = shell_destroy;
+ wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
+
+ if (wl_global_create(ec->wl_display, &ivi_application_interface, 1,
+ shell, bind_ivi_application) == NULL) {
+ return -1;
+ }
+
+ wl_list_for_each(seat, &ec->seat_list, link) {
+ if (seat) {
+ shell->seat = seat;
+ }
+ }
+
+ return 0;
+}
--
1.8.3.1
Pekka Paalanen
2014-03-10 10:47:58 UTC
Permalink
On Thu, 6 Mar 2014 18:56:58 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> In-Vehicle Infotainment system traditionally manages surfaces with global
> identification. A protocol, ivi_application, supports such a feature by
> implementing a request, ivi_application::surface_creation defined in
> ivi_application.xml. Additionally, it initialize a library, weston-layout,
> to manage properties of surfaces and group surfaces in layer. In detail,
> refer library, weston_layout.
>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
> ivi-shell/ivi-shell.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 333 insertions(+)
> create mode 100644 ivi-shell/ivi-shell.c
>
> diff --git a/ivi-shell/ivi-shell.c b/ivi-shell/ivi-shell.c
> new file mode 100644
> index 0000000..f4c4d25
> --- /dev/null
> +++ b/ivi-shell/ivi-shell.c
> @@ -0,0 +1,333 @@
> +/*
> + * Copyright (C) 2013 DENSO CORPORATION
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission. The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose. It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +
> +/**
> + * ivi-shell supports a type of shell for In-Vehicle Infotainment system.
> + * In-Vehicle Infotainment system traditionally manages surfaces with global
> + * identification. A protocol, ivi_application, supports such a feature
> + * by implementing a request, ivi_application::surface_creation defined in
> + * ivi_application.xml.
> + *
> + * Additionally, it initialize a library, weston-layout, to manage properties of
> + * surfaces and group surfaces in layer. In detail, refer weston_layout.
> + */
> +
> +#include <sys/wait.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <linux/input.h>
> +
> +#include "compositor.h"
> +#include "ivi-application-server-protocol.h"
> +#include "weston-layout.h"

weston-layout.h is introduced in the following patch, so this patch
won't build, breaking bisectability if this series was applied.

> +
> +struct ivi_shell;
> +
> +struct ivi_shell_surface
> +{
> + struct ivi_shell *shell;
> + struct weston_layout_surface *layout_surface;
> +
> + struct weston_surface *surface;
> + uint32_t id_surface;
> +
> + int32_t width;
> + int32_t height;
> +
> + struct wl_list link;
> +};
> +
> +struct ivi_shell
> +{
> + struct wl_resource *resource;
> + struct wl_listener destroy_listener;
> +
> + struct weston_compositor *compositor;
> + struct weston_seat *seat;

'compositor' and 'seat' seem pretty unused?

> +
> + struct wl_list list_surface;

We prefer the convention <something>_list instead. Personally, I've
also added a comment about what is in this list, like
/* ivi_shell_surface::link */ because that is an invariant.

> +};
> +
> +/* ------------------------------------------------------------------------- */
> +/* common functions */
> +/* ------------------------------------------------------------------------- */
> +
> +static void
> +configure(struct weston_view *view, float x, float y)
> +{
> + if (view != NULL) {
> + weston_view_set_position(view, x, y);
> + weston_view_update_transform(view);

Something in this feels odd... the part about calling
weston_view_update_transform() manually... is that ok, or should it be
called only when mapping the surface?

> + }
> +}
> +
> +/**
> + * Implementation of ivi_surface
> + */
> +
> +static void
> +ivi_shell_surface_configure(struct weston_surface *, int32_t, int32_t);
> +
> +static struct ivi_shell_surface *
> +get_ivi_shell_surface(struct weston_surface *surface)
> +{
> + if (surface->configure == ivi_shell_surface_configure) {
> + return surface->configure_private;
> + } else {
> + return NULL;
> + }
> +}
> +
> +static void
> +ivi_shell_surface_configure(struct weston_surface *es,
> + int32_t sx, int32_t sy)
> +{
> + struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(es);
> + struct weston_view *view = NULL;
> + float from_x = 0.0f;
> + float from_y = 0.0f;
> + float to_x = 0.0f;
> + float to_y = 0.0f;
> +
> + if ((es->width == 0) || (es->height == 0) || (ivisurf == NULL)) {
> + return;
> + }
> +
> + view = weston_layout_get_weston_view(ivisurf->layout_surface);
> + if (view == NULL) {
> + return;
> + }
> +
> + if (ivisurf->width != es->width || ivisurf->height != es->height) {
> +
> + ivisurf->width = es->width;
> + ivisurf->height = es->height;
> +
> + weston_view_to_global_float(view, 0, 0, &from_x, &from_y);
> + weston_view_to_global_float(view, sx, sy, &to_x, &to_y);
> + configure(view,
> + view->geometry.x + to_x - from_x,
> + view->geometry.y + to_y - from_y);
> +
> + weston_layout_surfaceConfigure(ivisurf->layout_surface, es->width, es->height);
> + }
> +}
> +
> +static void
> +surface_destroy(struct wl_client *client,
> + struct wl_resource *resource)
> +{
> + struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource);
> + struct ivi_shell *shell = ivisurf->shell;
> +
> + weston_layout_surfaceRemove(ivisurf->layout_surface);
> +
> + ivisurf->surface->configure = NULL;
> + ivisurf->surface->configure_private = NULL;
> +
> + if (!wl_list_empty(&ivisurf->link)) {
> + wl_list_remove(&ivisurf->link);
> + }
> + wl_list_init(&shell->list_surface);
> +
> + free(ivisurf);
> + ivisurf = NULL;

Local variable.

I just realized that your protocol spec does not define what should
happen on destruction.

> +}
> +
> +static const struct ivi_surface_interface surface_implementation = {
> + surface_destroy,
> +};
> +
> +static struct ivi_shell_surface *
> +is_surf_in_surfaces(struct wl_list *list_surf, uint32_t id_surface)
> +{
> + struct ivi_shell_surface *ivisurf;
> +
> + wl_list_for_each(ivisurf, list_surf, link) {
> + if (ivisurf->id_surface == id_surface) {
> + return ivisurf;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +/**
> + * Implementation of ivi_application::surface_create.
> + * Creating new ivi_shell_surface with identification to identify the surface
> + * in the system.
> + */
> +static void
> +application_surface_create(struct wl_client *client,
> + struct wl_resource *resource,
> + uint32_t id_surface,
> + struct wl_resource *surface_resource,
> + uint32_t id)
> +{
> + struct ivi_shell *shell = wl_resource_get_user_data(resource);
> + struct weston_layout_surface *layout_surface = NULL;
> + struct ivi_shell_surface *ivisurf = NULL;
> + struct weston_surface *es = NULL;
> +
> + es = wl_resource_get_user_data(surface_resource);
> + if (es == NULL) {
> + weston_log("application_surface_create: invalid surface\n");
> + return;
> + }
> +
> + ivisurf = is_surf_in_surfaces(&shell->list_surface, id_surface);
> +
> + layout_surface = weston_layout_surfaceCreate(es, id_surface);
> + if (layout_surface == NULL) {
> +//FIXME

Forgot something?
Seems like double-checking the same thing, slightly confusing. Avoid
calling weston_layout_surfaceCreate() to begin with, if (ivisurf)?

> + weston_log("id_surface is already created\n");
> +
> + ivisurf->surface = es;
> + ivisurf->width = 0;
> + ivisurf->height = 0;
> +
> + es->configure = ivi_shell_surface_configure;
> + es->configure_private = ivisurf;
> +
> + resource = wl_resource_create(client, &ivi_surface_interface, 1, id);
> + if (resource == NULL) {
> + weston_log("couldn't get surface object");
> + return;
> + }
> +
> + wl_resource_set_implementation(resource,
> + &surface_implementation,
> + ivisurf, NULL);

Does this mean, that if a client calls ivi_application.surface_create
with an already used ID, it will get a handle to the existing
ivi_shell_surface? Is that supposed to work? If yes, then
ivi_shell_surface needs a list of all wl_resources pointing to it.

IDs are global, aren't they? So it could get a handle to some *other*
client's ivi_shell_surface. That doesn't sound good.

> + return;
> + }
> +
> + ivisurf = calloc(1, sizeof *ivisurf);
> + if (ivisurf == NULL) {
> + weston_log("fails to allocate memory\n");
> + return;
> + }
> +
> + wl_list_init(&ivisurf->link);
> + ivisurf->shell = shell;
> + ivisurf->layout_surface = layout_surface;
> + ivisurf->surface = es;
> + ivisurf->id_surface = id_surface;
> + ivisurf->width = 0;
> + ivisurf->height = 0;
> +
> + es->configure = ivi_shell_surface_configure;
> + es->configure_private = ivisurf;
> +
> + wl_list_insert(&shell->list_surface, &ivisurf->link);
> +
> + resource = wl_resource_create(client, &ivi_surface_interface, 1, id);
> + if (resource == NULL) {
> + weston_log("couldn't get surface object");
> + return;
> + }
> +
> + wl_resource_set_implementation(resource,
> + &surface_implementation,
> + ivisurf, NULL);

Are you sure you don't need a destructor here? If the client
disconnects without explicitly destroying all its protocol objects, how
does ivisurf get freed?

> +}
> +
> +static const struct ivi_application_interface application_implementation = {
> + application_surface_create
> +};
> +
> +static void
> +bind_ivi_application(struct wl_client *client,
> + void *data, uint32_t version, uint32_t id)
> +{
> + struct ivi_shell *shell = data;
> + struct wl_resource *resource = NULL;
> +
> + resource = wl_resource_create(client, &ivi_application_interface, 1, id);
> +
> + wl_resource_set_implementation(resource,
> + &application_implementation,
> + shell, NULL);
> +}
> +
> +/**
> + * Initialization/destruction method of ivi-shell
> + */
> +static void
> +shell_destroy(struct wl_listener *listener, void *data)
> +{
> + struct ivi_shell *shell = NULL;
> +
> + shell = container_of(listener, struct ivi_shell, destroy_listener);
> +
> + free(shell);
> + shell = NULL;

Nulling a local variable again.

I think you should do some sanity/leak checks here, like ensuring that
the surface list is empty, no?

> +}
> +
> +static void
> +init_ivi_shell(struct weston_compositor *ec, struct ivi_shell *shell)
> +{
> + shell->compositor = ec;
> +
> + wl_list_init(&ec->layer_list);
> + wl_list_init(&shell->list_surface);
> +}
> +
> +/**
> + * Initialization of ivi-shell. A library, weston_layout, is also initialized
> + * here by calling weston_layout_initWithCompositor.
> + *
> + */
> +
> +WL_EXPORT int
> +module_init(struct weston_compositor *ec,
> + int *argc, char *argv[])
> +{
> + struct ivi_shell *shell = NULL;
> + struct weston_seat *seat = NULL;
> +
> + shell = calloc(1, sizeof *shell);
> + if (shell == NULL) {
> + return -1;
> + }
> +
> + init_ivi_shell(ec, shell);
> + weston_layout_initWithCompositor(ec);

It's kind of surprising... this module's init requires another module to
have been loaded before, otherwise this module will not load, right?
I wonder if you get a sensible error message when that happens.

> +
> + shell->destroy_listener.notify = shell_destroy;
> + wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
> +
> + if (wl_global_create(ec->wl_display, &ivi_application_interface, 1,
> + shell, bind_ivi_application) == NULL) {
> + return -1;
> + }
> +
> + wl_list_for_each(seat, &ec->seat_list, link) {
> + if (seat) {
> + shell->seat = seat;

'seat' cannot be NULL here. It seems you are assuming that there can be
only one seat? Why?

> + }
> + }
> +
> + return 0;
> +}


Thanks,
pq
Nobuhiko Tanibata
2014-03-11 05:51:21 UTC
Permalink
2014-03-10 19:47 ? Pekka Paalanen ????????:
> On Thu, 6 Mar 2014 18:56:58 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> In-Vehicle Infotainment system traditionally manages surfaces with
>> global
>> identification. A protocol, ivi_application, supports such a feature
>> by
>> implementing a request, ivi_application::surface_creation defined in
>> ivi_application.xml. Additionally, it initialize a library,
>> weston-layout,
>> to manage properties of surfaces and group surfaces in layer. In
>> detail,
>> refer library, weston_layout.
>>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>> ivi-shell/ivi-shell.c | 333
>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 333 insertions(+)
>> create mode 100644 ivi-shell/ivi-shell.c
>>
>> diff --git a/ivi-shell/ivi-shell.c b/ivi-shell/ivi-shell.c
>> new file mode 100644
>> index 0000000..f4c4d25
>> --- /dev/null
>> +++ b/ivi-shell/ivi-shell.c
>> @@ -0,0 +1,333 @@
>> +/*
>> + * Copyright (C) 2013 DENSO CORPORATION
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this
>> software and
>> + * its documentation for any purpose is hereby granted without fee,
>> provided
>> + * that the above copyright notice appear in all copies and that both
>> that
>> + * copyright notice and this permission notice appear in supporting
>> + * documentation, and that the name of the copyright holders not be
>> used in
>> + * advertising or publicity pertaining to distribution of the
>> software
>> + * without specific, written prior permission. The copyright holders
>> make
>> + * no representations about the suitability of this software for any
>> + * purpose. It is provided "as is" without express or implied
>> warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
>> WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
>> OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
>> IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +
>> +/**
>> + * ivi-shell supports a type of shell for In-Vehicle Infotainment
>> system.
>> + * In-Vehicle Infotainment system traditionally manages surfaces with
>> global
>> + * identification. A protocol, ivi_application, supports such a
>> feature
>> + * by implementing a request, ivi_application::surface_creation
>> defined in
>> + * ivi_application.xml.
>> + *
>> + * Additionally, it initialize a library, weston-layout, to manage
>> properties of
>> + * surfaces and group surfaces in layer. In detail, refer
>> weston_layout.
>> + */
>> +
>> +#include <sys/wait.h>
>> +#include <unistd.h>
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <linux/input.h>
>> +
>> +#include "compositor.h"
>> +#include "ivi-application-server-protocol.h"
>> +#include "weston-layout.h"
>
> weston-layout.h is introduced in the following patch, so this patch
> won't build, breaking bisectability if this series was applied.
>

I agree.

>> +
>> +struct ivi_shell;
>> +
>> +struct ivi_shell_surface
>> +{
>> + struct ivi_shell *shell;
>> + struct weston_layout_surface *layout_surface;
>> +
>> + struct weston_surface *surface;
>> + uint32_t id_surface;
>> +
>> + int32_t width;
>> + int32_t height;
>> +
>> + struct wl_list link;
>> +};
>> +
>> +struct ivi_shell
>> +{
>> + struct wl_resource *resource;
>> + struct wl_listener destroy_listener;
>> +
>> + struct weston_compositor *compositor;
>> + struct weston_seat *seat;
>
> 'compositor' and 'seat' seem pretty unused?
>
>> +
>> + struct wl_list list_surface;
>
> We prefer the convention <something>_list instead. Personally, I've
> also added a comment about what is in this list, like
> /* ivi_shell_surface::link */ because that is an invariant.

I agree.

>
>> +};
>> +
>> +/*
>> ------------------------------------------------------------------------- */
>> +/* common functions
>> */
>> +/*
>> ------------------------------------------------------------------------- */
>> +
>> +static void
>> +configure(struct weston_view *view, float x, float y)
>> +{
>> + if (view != NULL) {
>> + weston_view_set_position(view, x, y);
>> + weston_view_update_transform(view);
>
> Something in this feels odd... the part about calling
> weston_view_update_transform() manually... is that ok, or should it be
> called only when mapping the surface?
>

I move the above code to below.

>> + }
>> +}
>> +
>> +/**
>> + * Implementation of ivi_surface
>> + */
>> +
>> +static void
>> +ivi_shell_surface_configure(struct weston_surface *, int32_t,
>> int32_t);
>> +
>> +static struct ivi_shell_surface *
>> +get_ivi_shell_surface(struct weston_surface *surface)
>> +{
>> + if (surface->configure == ivi_shell_surface_configure) {
>> + return surface->configure_private;
>> + } else {
>> + return NULL;
>> + }
>> +}
>> +
>> +static void
>> +ivi_shell_surface_configure(struct weston_surface *es,
>> + int32_t sx, int32_t sy)
>> +{
>> + struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(es);
>> + struct weston_view *view = NULL;
>> + float from_x = 0.0f;
>> + float from_y = 0.0f;
>> + float to_x = 0.0f;
>> + float to_y = 0.0f;
>> +
>> + if ((es->width == 0) || (es->height == 0) || (ivisurf == NULL)) {
>> + return;
>> + }
>> +
>> + view = weston_layout_get_weston_view(ivisurf->layout_surface);
>> + if (view == NULL) {
>> + return;
>> + }
>> +
>> + if (ivisurf->width != es->width || ivisurf->height != es->height)
>> {
>> +
>> + ivisurf->width = es->width;
>> + ivisurf->height = es->height;
>> +
>> + weston_view_to_global_float(view, 0, 0, &from_x, &from_y);
>> + weston_view_to_global_float(view, sx, sy, &to_x, &to_y);
>> + configure(view,
>> + view->geometry.x + to_x - from_x,
>> + view->geometry.y + to_y - from_y);
>> +
>> + weston_layout_surfaceConfigure(ivisurf->layout_surface,
>> es->width, es->height);
>> + }
>> +}
>> +
>> +static void
>> +surface_destroy(struct wl_client *client,
>> + struct wl_resource *resource)
>> +{
>> + struct ivi_shell_surface *ivisurf =
>> wl_resource_get_user_data(resource);
>> + struct ivi_shell *shell = ivisurf->shell;
>> +
>> + weston_layout_surfaceRemove(ivisurf->layout_surface);
>> +
>> + ivisurf->surface->configure = NULL;
>> + ivisurf->surface->configure_private = NULL;
>> +
>> + if (!wl_list_empty(&ivisurf->link)) {
>> + wl_list_remove(&ivisurf->link);
>> + }
>> + wl_list_init(&shell->list_surface);
>> +
>> + free(ivisurf);
>> + ivisurf = NULL;
>
> Local variable.
>
> I just realized that your protocol spec does not define what should
> happen on destruction.

I will add description to ivi_application.xml.

>
>> +}
>> +
>> +static const struct ivi_surface_interface surface_implementation = {
>> + surface_destroy,
>> +};
>> +
>> +static struct ivi_shell_surface *
>> +is_surf_in_surfaces(struct wl_list *list_surf, uint32_t id_surface)
>> +{
>> + struct ivi_shell_surface *ivisurf;
>> +
>> + wl_list_for_each(ivisurf, list_surf, link) {
>> + if (ivisurf->id_surface == id_surface) {
>> + return ivisurf;
>> + }
>> + }
>> +
>> + return NULL;
>> +}
>> +
>> +/**
>> + * Implementation of ivi_application::surface_create.
>> + * Creating new ivi_shell_surface with identification to identify the
>> surface
>> + * in the system.
>> + */
>> +static void
>> +application_surface_create(struct wl_client *client,
>> + struct wl_resource *resource,
>> + uint32_t id_surface,
>> + struct wl_resource *surface_resource,
>> + uint32_t id)
>> +{
>> + struct ivi_shell *shell = wl_resource_get_user_data(resource);
>> + struct weston_layout_surface *layout_surface = NULL;
>> + struct ivi_shell_surface *ivisurf = NULL;
>> + struct weston_surface *es = NULL;
>> +
>> + es = wl_resource_get_user_data(surface_resource);
>> + if (es == NULL) {
>> + weston_log("application_surface_create: invalid surface\n");
>> + return;
>> + }
>> +
>> + ivisurf = is_surf_in_surfaces(&shell->list_surface, id_surface);
>> +
>> + layout_surface = weston_layout_surfaceCreate(es, id_surface);
>> + if (layout_surface == NULL) {
>> +//FIXME
>
> Forgot something?
> Seems like double-checking the same thing, slightly confusing. Avoid
> calling weston_layout_surfaceCreate() to begin with, if (ivisurf)?
>
>> + weston_log("id_surface is already created\n");
>> +
>> + ivisurf->surface = es;
>> + ivisurf->width = 0;
>> + ivisurf->height = 0;
>> +
>> + es->configure = ivi_shell_surface_configure;
>> + es->configure_private = ivisurf;
>> +
>> + resource = wl_resource_create(client, &ivi_surface_interface,
>> 1, id);
>> + if (resource == NULL) {
>> + weston_log("couldn't get surface object");
>> + return;
>> + }
>> +
>> + wl_resource_set_implementation(resource,
>> + &surface_implementation,
>> + ivisurf, NULL);
>
> Does this mean, that if a client calls ivi_application.surface_create
> with an already used ID, it will get a handle to the existing
> ivi_shell_surface? Is that supposed to work? If yes, then
> ivi_shell_surface needs a list of all wl_resources pointing to it.
>
> IDs are global, aren't they? So it could get a handle to some *other*
> client's ivi_shell_surface. That doesn't sound good.
>

I will realign warning in ivi_application.xml and update the above code.
Basically, I agree with your comments.

>> + return;
>> + }
>> +
>> + ivisurf = calloc(1, sizeof *ivisurf);
>> + if (ivisurf == NULL) {
>> + weston_log("fails to allocate memory\n");
>> + return;
>> + }
>> +
>> + wl_list_init(&ivisurf->link);
>> + ivisurf->shell = shell;
>> + ivisurf->layout_surface = layout_surface;
>> + ivisurf->surface = es;
>> + ivisurf->id_surface = id_surface;
>> + ivisurf->width = 0;
>> + ivisurf->height = 0;
>> +
>> + es->configure = ivi_shell_surface_configure;
>> + es->configure_private = ivisurf;
>> +
>> + wl_list_insert(&shell->list_surface, &ivisurf->link);
>> +
>> + resource = wl_resource_create(client, &ivi_surface_interface, 1,
>> id);
>> + if (resource == NULL) {
>> + weston_log("couldn't get surface object");
>> + return;
>> + }
>> +
>> + wl_resource_set_implementation(resource,
>> + &surface_implementation,
>> + ivisurf, NULL);
>
> Are you sure you don't need a destructor here? If the client
> disconnects without explicitly destroying all its protocol objects, how
> does ivisurf get freed?
>
I agree.

>> +}
>> +
>> +static const struct ivi_application_interface
>> application_implementation = {
>> + application_surface_create
>> +};
>> +
>> +static void
>> +bind_ivi_application(struct wl_client *client,
>> + void *data, uint32_t version, uint32_t id)
>> +{
>> + struct ivi_shell *shell = data;
>> + struct wl_resource *resource = NULL;
>> +
>> + resource = wl_resource_create(client, &ivi_application_interface,
>> 1, id);
>> +
>> + wl_resource_set_implementation(resource,
>> + &application_implementation,
>> + shell, NULL);
>> +}
>> +
>> +/**
>> + * Initialization/destruction method of ivi-shell
>> + */
>> +static void
>> +shell_destroy(struct wl_listener *listener, void *data)
>> +{
>> + struct ivi_shell *shell = NULL;
>> +
>> + shell = container_of(listener, struct ivi_shell,
>> destroy_listener);
>> +
>> + free(shell);
>> + shell = NULL;
>
> Nulling a local variable again.
>
> I think you should do some sanity/leak checks here, like ensuring that
> the surface list is empty, no?

I agree. This is just my habit.

>
>> +}
>> +
>> +static void
>> +init_ivi_shell(struct weston_compositor *ec, struct ivi_shell *shell)
>> +{
>> + shell->compositor = ec;
>> +
>> + wl_list_init(&ec->layer_list);
>> + wl_list_init(&shell->list_surface);
>> +}
>> +
>> +/**
>> + * Initialization of ivi-shell. A library, weston_layout, is also
>> initialized
>> + * here by calling weston_layout_initWithCompositor.
>> + *
>> + */
>> +
>> +WL_EXPORT int
>> +module_init(struct weston_compositor *ec,
>> + int *argc, char *argv[])
>> +{
>> + struct ivi_shell *shell = NULL;
>> + struct weston_seat *seat = NULL;
>> +
>> + shell = calloc(1, sizeof *shell);
>> + if (shell == NULL) {
>> + return -1;
>> + }
>> +
>> + init_ivi_shell(ec, shell);
>> + weston_layout_initWithCompositor(ec);
>
> It's kind of surprising... this module's init requires another module
> to
> have been loaded before, otherwise this module will not load, right?
> I wonder if you get a sensible error message when that happens.

westen_layout is not a module to be loaded by ivi-shell. It is shared
library.
If it is not weston manner, I can link it statically. Please give me
your suggestion?

>
>> +
>> + shell->destroy_listener.notify = shell_destroy;
>> + wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
>> +
>> + if (wl_global_create(ec->wl_display, &ivi_application_interface,
>> 1,
>> + shell, bind_ivi_application) == NULL) {
>> + return -1;
>> + }
>> +
>> + wl_list_for_each(seat, &ec->seat_list, link) {
>> + if (seat) {
>> + shell->seat = seat;
>
> 'seat' cannot be NULL here. It seems you are assuming that there can be
> only one seat? Why?
>

Ideally, I agree. However I am in automotive software, and I have habit
to avoid NULL access as much as possible in case of the worst scenario.


Thank you,
Nobuhiko
>> + }
>> + }
>> +
>> + return 0;
>> +}
>
>
> Thanks,
> pq
Pekka Paalanen
2014-03-11 08:14:31 UTC
Permalink
On Tue, 11 Mar 2014 14:51:21 +0900
Nobuhiko Tanibata <nobuhiko_tanibata at xddp.denso.co.jp> wrote:

> 2014-03-10 19:47 ? Pekka Paalanen ????????:
> > On Thu, 6 Mar 2014 18:56:58 +0900
> > Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
> >
> >> In-Vehicle Infotainment system traditionally manages surfaces with
> >> global
> >> identification. A protocol, ivi_application, supports such a feature
> >> by
> >> implementing a request, ivi_application::surface_creation defined in
> >> ivi_application.xml. Additionally, it initialize a library,
> >> weston-layout,
> >> to manage properties of surfaces and group surfaces in layer. In
> >> detail,
> >> refer library, weston_layout.
> >>
> >> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> >> ---
> >> ivi-shell/ivi-shell.c | 333
> >> ++++++++++++++++++++++++++++++++++++++++++++++++++
> >> 1 file changed, 333 insertions(+)
> >> create mode 100644 ivi-shell/ivi-shell.c

...

> >> +static void
> >> +init_ivi_shell(struct weston_compositor *ec, struct ivi_shell *shell)
> >> +{
> >> + shell->compositor = ec;
> >> +
> >> + wl_list_init(&ec->layer_list);
> >> + wl_list_init(&shell->list_surface);
> >> +}
> >> +
> >> +/**
> >> + * Initialization of ivi-shell. A library, weston_layout, is also
> >> initialized
> >> + * here by calling weston_layout_initWithCompositor.
> >> + *
> >> + */
> >> +
> >> +WL_EXPORT int
> >> +module_init(struct weston_compositor *ec,
> >> + int *argc, char *argv[])
> >> +{
> >> + struct ivi_shell *shell = NULL;
> >> + struct weston_seat *seat = NULL;
> >> +
> >> + shell = calloc(1, sizeof *shell);
> >> + if (shell == NULL) {
> >> + return -1;
> >> + }
> >> +
> >> + init_ivi_shell(ec, shell);
> >> + weston_layout_initWithCompositor(ec);
> >
> > It's kind of surprising... this module's init requires another module
> > to
> > have been loaded before, otherwise this module will not load, right?
> > I wonder if you get a sensible error message when that happens.
>
> westen_layout is not a module to be loaded by ivi-shell. It is shared
> library.
> If it is not weston manner, I can link it statically. Please give me
> your suggestion?

Oh, ok, that should be alright then. I just jumped into a conclusion
that all .so's were plugins. I stand corrected. I read these patches
one by one, when I can.

Is there a reason weston_layout should be a dynamic library? Do you
expect it's ABI to be stable, and have a use case for swapping one of
the two while keeping the other compiled binary intact?

If you are not committing to a stable library ABI, then I'd suggest not
having it as a dynamic library to avoid any confusion and abuse; to
avoid the risk of suddenly realizing you cannot change the API, because
someone else is using it or having a different implementation of it.

> >> +
> >> + shell->destroy_listener.notify = shell_destroy;
> >> + wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
> >> +
> >> + if (wl_global_create(ec->wl_display, &ivi_application_interface,
> >> 1,
> >> + shell, bind_ivi_application) == NULL) {
> >> + return -1;
> >> + }
> >> +
> >> + wl_list_for_each(seat, &ec->seat_list, link) {
> >> + if (seat) {
> >> + shell->seat = seat;
> >
> > 'seat' cannot be NULL here. It seems you are assuming that there can be
> > only one seat? Why?
> >
>
> Ideally, I agree. However I am in automotive software, and I have habit
> to avoid NULL access as much as possible in case of the worst scenario.

Then put an assert(), though in this case even that would be too much.
You can never get a NULL from wl_list_for_each(). You might get a bad
pointer if the list is corrupted, but the odds of getting exactly NULL
are diminishing even with corruption.

Silently ignoring NULLs where they should never appear may hide real
problems in testing, and even in production you'd probably want to log
it somehow to help post mortem.


Thanks,
pq
Nobuhiko Tanibata
2014-03-11 16:31:38 UTC
Permalink
2014-03-11 17:14 ? Pekka Paalanen ????????:
> On Tue, 11 Mar 2014 14:51:21 +0900
> Nobuhiko Tanibata <nobuhiko_tanibata at xddp.denso.co.jp> wrote:
>
>> 2014-03-10 19:47 ? Pekka Paalanen ????????:
>> > On Thu, 6 Mar 2014 18:56:58 +0900
>> > Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>> >
>> >> In-Vehicle Infotainment system traditionally manages surfaces with
>> >> global
>> >> identification. A protocol, ivi_application, supports such a feature
>> >> by
>> >> implementing a request, ivi_application::surface_creation defined in
>> >> ivi_application.xml. Additionally, it initialize a library,
>> >> weston-layout,
>> >> to manage properties of surfaces and group surfaces in layer. In
>> >> detail,
>> >> refer library, weston_layout.
>> >>
>> >> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> >> ---
>> >> ivi-shell/ivi-shell.c | 333
>> >> ++++++++++++++++++++++++++++++++++++++++++++++++++
>> >> 1 file changed, 333 insertions(+)
>> >> create mode 100644 ivi-shell/ivi-shell.c
>
> ...
>
>> >> +static void
>> >> +init_ivi_shell(struct weston_compositor *ec, struct ivi_shell *shell)
>> >> +{
>> >> + shell->compositor = ec;
>> >> +
>> >> + wl_list_init(&ec->layer_list);
>> >> + wl_list_init(&shell->list_surface);
>> >> +}
>> >> +
>> >> +/**
>> >> + * Initialization of ivi-shell. A library, weston_layout, is also
>> >> initialized
>> >> + * here by calling weston_layout_initWithCompositor.
>> >> + *
>> >> + */
>> >> +
>> >> +WL_EXPORT int
>> >> +module_init(struct weston_compositor *ec,
>> >> + int *argc, char *argv[])
>> >> +{
>> >> + struct ivi_shell *shell = NULL;
>> >> + struct weston_seat *seat = NULL;
>> >> +
>> >> + shell = calloc(1, sizeof *shell);
>> >> + if (shell == NULL) {
>> >> + return -1;
>> >> + }
>> >> +
>> >> + init_ivi_shell(ec, shell);
>> >> + weston_layout_initWithCompositor(ec);
>> >
>> > It's kind of surprising... this module's init requires another module
>> > to
>> > have been loaded before, otherwise this module will not load, right?
>> > I wonder if you get a sensible error message when that happens.
>>
>> westen_layout is not a module to be loaded by ivi-shell. It is shared
>> library.
>> If it is not weston manner, I can link it statically. Please give me
>> your suggestion?
>
> Oh, ok, that should be alright then. I just jumped into a conclusion
> that all .so's were plugins. I stand corrected. I read these patches
> one by one, when I can.
>
> Is there a reason weston_layout should be a dynamic library? Do you
> expect it's ABI to be stable, and have a use case for swapping one of
> the two while keeping the other compiled binary intact?
>
> If you are not committing to a stable library ABI, then I'd suggest not
> having it as a dynamic library to avoid any confusion and abuse; to
> avoid the risk of suddenly realizing you cannot change the API, because
> someone else is using it or having a different implementation of it.
>

Hi pq,

I see. I agree with your comments.

>> >> +
>> >> + shell->destroy_listener.notify = shell_destroy;
>> >> + wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
>> >> +
>> >> + if (wl_global_create(ec->wl_display, &ivi_application_interface,
>> >> 1,
>> >> + shell, bind_ivi_application) == NULL) {
>> >> + return -1;
>> >> + }
>> >> +
>> >> + wl_list_for_each(seat, &ec->seat_list, link) {
>> >> + if (seat) {
>> >> + shell->seat = seat;
>> >
>> > 'seat' cannot be NULL here. It seems you are assuming that there can be
>> > only one seat? Why?
>> >
>>
>> Ideally, I agree. However I am in automotive software, and I have
>> habit
>> to avoid NULL access as much as possible in case of the worst
>> scenario.
>
> Then put an assert(), though in this case even that would be too much.
> You can never get a NULL from wl_list_for_each(). You might get a bad
> pointer if the list is corrupted, but the odds of getting exactly NULL
> are diminishing even with corruption.
>
> Silently ignoring NULLs where they should never appear may hide real
> problems in testing, and even in production you'd probably want to log
> it somehow to help post mortem.
>
OK. I will modify my patches.

Thank you very much for many comments!

BR,
Nobuhiko

>
> Thanks,
> pq
Bill Spitzak
2014-03-11 19:10:45 UTC
Permalink
Pekka Paalanen wrote:

>>>> + wl_list_for_each(seat, &ec->seat_list, link) {
>>>> + if (seat) {
>>>> + shell->seat = seat;
>>> 'seat' cannot be NULL here. It seems you are assuming that there can be
>>> only one seat? Why?
>>>
>> Ideally, I agree. However I am in automotive software, and I have habit
>> to avoid NULL access as much as possible in case of the worst scenario.
>
> Then put an assert(), though in this case even that would be too much.
> You can never get a NULL from wl_list_for_each(). You might get a bad
> pointer if the list is corrupted, but the odds of getting exactly NULL
> are diminishing even with corruption.
>
> Silently ignoring NULLs where they should never appear may hide real
> problems in testing, and even in production you'd probably want to log
> it somehow to help post mortem.

In addition, seeing an "if (x)" is a strong indication to the programmer
that x *can* be NULL, and they will then make modifications to perceived
bugs on the assumption that NULL is a possible value. This often leads
to this same mistake being propagated to every function called by this
and every use of a variable this value is stored into.

An assert(x) however is a strong indication that x is *not* NULL.

If you really are tempted to make a test so that if you missed a bug
there is less chance of the optimized program crashing, what I do is
something like this:

assert(x);
if (!x) return; // THIS SHOULD NOT HAPPEN
Nobuhiko Tanibata
2014-03-11 23:50:18 UTC
Permalink
2014-03-12 04:10 ? Bill Spitzak ????????:
> Pekka Paalanen wrote:
>
>>>>> + wl_list_for_each(seat, &ec->seat_list, link) {
>>>>> + if (seat) {
>>>>> + shell->seat = seat;
>>>> 'seat' cannot be NULL here. It seems you are assuming that there can
>>>> be
>>>> only one seat? Why?
>>>>
>>> Ideally, I agree. However I am in automotive software, and I have
>>> habit to avoid NULL access as much as possible in case of the worst
>>> scenario.
>>
>> Then put an assert(), though in this case even that would be too much.
>> You can never get a NULL from wl_list_for_each(). You might get a bad
>> pointer if the list is corrupted, but the odds of getting exactly NULL
>> are diminishing even with corruption.
>>
>> Silently ignoring NULLs where they should never appear may hide real
>> problems in testing, and even in production you'd probably want to log
>> it somehow to help post mortem.
>
> In addition, seeing an "if (x)" is a strong indication to the
> programmer that x *can* be NULL, and they will then make modifications
> to perceived bugs on the assumption that NULL is a possible value.
> This often leads to this same mistake being propagated to every
> function called by this and every use of a variable this value is
> stored into.
>
> An assert(x) however is a strong indication that x is *not* NULL.
>
> If you really are tempted to make a test so that if you missed a bug
> there is less chance of the optimized program crashing, what I do is
> something like this:
>
> assert(x);
> if (!x) return; // THIS SHOULD NOT HAPPEN

Hi pq and Bill,

Thank you a lot. I will follow the above way.

BR,
Nobuhiko
Nobuhiko Tanibata
2014-03-14 13:18:58 UTC
Permalink
2014-03-11 17:14 ? Pekka Paalanen ????????:
> On Tue, 11 Mar 2014 14:51:21 +0900
> Nobuhiko Tanibata <nobuhiko_tanibata at xddp.denso.co.jp> wrote:
>
>> 2014-03-10 19:47 ? Pekka Paalanen ????????:
>> > On Thu, 6 Mar 2014 18:56:58 +0900
>> > Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>> >
>> >> In-Vehicle Infotainment system traditionally manages surfaces with
>> >> global
>> >> identification. A protocol, ivi_application, supports such a feature
>> >> by
>> >> implementing a request, ivi_application::surface_creation defined in
>> >> ivi_application.xml. Additionally, it initialize a library,
>> >> weston-layout,
>> >> to manage properties of surfaces and group surfaces in layer. In
>> >> detail,
>> >> refer library, weston_layout.
>> >>
>> >> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> >> ---
>> >> ivi-shell/ivi-shell.c | 333
>> >> ++++++++++++++++++++++++++++++++++++++++++++++++++
>> >> 1 file changed, 333 insertions(+)
>> >> create mode 100644 ivi-shell/ivi-shell.c
>
> ...
>
>> >> +static void
>> >> +init_ivi_shell(struct weston_compositor *ec, struct ivi_shell *shell)
>> >> +{
>> >> + shell->compositor = ec;
>> >> +
>> >> + wl_list_init(&ec->layer_list);
>> >> + wl_list_init(&shell->list_surface);
>> >> +}
>> >> +
>> >> +/**
>> >> + * Initialization of ivi-shell. A library, weston_layout, is also
>> >> initialized
>> >> + * here by calling weston_layout_initWithCompositor.
>> >> + *
>> >> + */
>> >> +
>> >> +WL_EXPORT int
>> >> +module_init(struct weston_compositor *ec,
>> >> + int *argc, char *argv[])
>> >> +{
>> >> + struct ivi_shell *shell = NULL;
>> >> + struct weston_seat *seat = NULL;
>> >> +
>> >> + shell = calloc(1, sizeof *shell);
>> >> + if (shell == NULL) {
>> >> + return -1;
>> >> + }
>> >> +
>> >> + init_ivi_shell(ec, shell);
>> >> + weston_layout_initWithCompositor(ec);
>> >
>> > It's kind of surprising... this module's init requires another module
>> > to
>> > have been loaded before, otherwise this module will not load, right?
>> > I wonder if you get a sensible error message when that happens.
>>
>> westen_layout is not a module to be loaded by ivi-shell. It is shared
>> library.
>> If it is not weston manner, I can link it statically. Please give me
>> your suggestion?
>
> Oh, ok, that should be alright then. I just jumped into a conclusion
> that all .so's were plugins. I stand corrected. I read these patches
> one by one, when I can.
>
> Is there a reason weston_layout should be a dynamic library? Do you
> expect it's ABI to be stable, and have a use case for swapping one of
> the two while keeping the other compiled binary intact?
>
> If you are not committing to a stable library ABI, then I'd suggest not
> having it as a dynamic library to avoid any confusion and abuse; to
> avoid the risk of suddenly realizing you cannot change the API, because
> someone else is using it or having a different implementation of it.
>

Hi pq,

I forget one important reason why weston_layout should be a dynamic
library.
At first email, I enclosed a pdf. It said ivi-controller.so which is
maintained in another repository of GENIVI. It will link weston_layout.
If I embed it in ivi-shell.so, I might need to set ivi-shell.so as
shared library
to be linked to ivi-controller.so.

These APIs are based on GENIVI layer manager APIs. So it is stable and
not be changed wihtout critical reason.

BR,
Nobuhiko

>> >> +
>> >> + shell->destroy_listener.notify = shell_destroy;
>> >> + wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
>> >> +
>> >> + if (wl_global_create(ec->wl_display, &ivi_application_interface,
>> >> 1,
>> >> + shell, bind_ivi_application) == NULL) {
>> >> + return -1;
>> >> + }
>> >> +
>> >> + wl_list_for_each(seat, &ec->seat_list, link) {
>> >> + if (seat) {
>> >> + shell->seat = seat;
>> >
>> > 'seat' cannot be NULL here. It seems you are assuming that there can be
>> > only one seat? Why?
>> >
>>
>> Ideally, I agree. However I am in automotive software, and I have
>> habit
>> to avoid NULL access as much as possible in case of the worst
>> scenario.
>
> Then put an assert(), though in this case even that would be too much.
> You can never get a NULL from wl_list_for_each(). You might get a bad
> pointer if the list is corrupted, but the odds of getting exactly NULL
> are diminishing even with corruption.
>
> Silently ignoring NULLs where they should never appear may hide real
> problems in testing, and even in production you'd probably want to log
> it somehow to help post mortem.
>
>
> Thanks,
> pq
Nobuhiko Tanibata
2014-03-15 05:41:51 UTC
Permalink
In-Vehicle Infotainment system traditionally manages surfaces with global
identification. A protocol, ivi_application, supports such a feature by
implementing a request, ivi_application::surface_creation defined in
ivi_application.xml. Additionally, it initialize a library, weston-layout,
to manage properties of surfaces and group surfaces in layer. In detail,
refer library, weston_layout.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- apply review comments of mailing list.
- squash update of Makefile into this patch.
- move this patch after patch of weston-layout.
- support inherit propoerties of id_surface when client attaches another
wl_surface with id_surface after destroying ivi_surface once.

ivi-shell/Makefile.am | 24 +++-
ivi-shell/ivi-shell.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 344 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/ivi-shell.c

diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
index 4d54c2d..d0c0d62 100644
--- a/ivi-shell/Makefile.am
+++ b/ivi-shell/Makefile.am
@@ -1,7 +1,8 @@
moduledir = $(libdir)/weston

module_LTLIBRARIES = \
- $(libweston_layout)
+ $(libweston_layout) \
+ $(ivi_shell)

AM_CPPFLAGS = \
-I$(top_srcdir)/shared \
@@ -17,6 +18,7 @@ westoninclude_HEADERS =

if ENABLE_IVI_SHELL
westoninclude_HEADERS += \
+ ivi-application-client-protocol.h \
weston-layout.h

libweston_layout = libweston-layout.la
@@ -27,4 +29,24 @@ libweston_layout_la_SOURCES = \
weston-layout.c \
weston-layout.h

+ivi_shell = ivi-shell.la
+ivi_shell_la_LDFLAGS = -module -avoid-version
+ivi_shell_la_LIBADD = $(COMPOSITOR_LIBS) $(IVI_SHELL_LIBS) ./libweston-layout.la
+ivi_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(IVI_SHELL_CFLAGS)
+ivi_shell_la_SOURCES = \
+ ivi-shell.c \
+ weston-layout.h \
+ ivi-application-protocol.c \
+ ivi-application-server-protocol.h
+
endif
+
+BUILT_SOURCES = \
+ ivi-application-protocol.c \
+ ivi-application-server-protocol.h \
+ ivi-application-client-protocol.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+wayland_protocoldir = $(top_srcdir)/protocol
+include $(top_srcdir)/wayland-scanner.mk
diff --git a/ivi-shell/ivi-shell.c b/ivi-shell/ivi-shell.c
new file mode 100644
index 0000000..d5b1f2d
--- /dev/null
+++ b/ivi-shell/ivi-shell.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/**
+ * ivi-shell supports a type of shell for In-Vehicle Infotainment system.
+ * In-Vehicle Infotainment system traditionally manages surfaces with global
+ * identification. A protocol, ivi_application, supports such a feature
+ * by implementing a request, ivi_application::surface_creation defined in
+ * ivi_application.xml.
+ *
+ * Additionally, it initialize a library, weston-layout, to manage properties of
+ * surfaces and group surfaces in layer. In detail, refer weston_layout.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+
+#include "compositor.h"
+#include "ivi-application-server-protocol.h"
+#include "weston-layout.h"
+
+struct ivi_shell;
+
+struct ivi_shell_surface
+{
+ struct ivi_shell *shell;
+ struct weston_layout_surface *layout_surface;
+
+ struct weston_surface *surface;
+ uint32_t id_surface;
+
+ int32_t width;
+ int32_t height;
+
+ struct wl_list link;
+};
+
+struct ivi_shell
+{
+ struct wl_resource *resource;
+ struct wl_listener destroy_listener;
+
+ struct weston_compositor *compositor;
+
+ struct wl_list ivi_surface_list; /* struct ivi_shell_surface::link */
+};
+
+/* ------------------------------------------------------------------------- */
+/* common functions */
+/* ------------------------------------------------------------------------- */
+
+static void
+configure(struct weston_view *view, float x, float y)
+{
+ if (view != NULL) {
+ weston_view_set_position(view, x, y);
+ weston_view_update_transform(view);
+ }
+}
+
+/**
+ * Implementation of ivi_surface
+ */
+
+static void
+ivi_shell_surface_configure(struct weston_surface *, int32_t, int32_t);
+
+static struct ivi_shell_surface *
+get_ivi_shell_surface(struct weston_surface *surface)
+{
+ if (surface->configure == ivi_shell_surface_configure) {
+ return surface->configure_private;
+ } else {
+ return NULL;
+ }
+}
+
+static void
+ivi_shell_surface_configure(struct weston_surface *es,
+ int32_t sx, int32_t sy)
+{
+ struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(es);
+ struct weston_view *view = NULL;
+ float from_x = 0.0f;
+ float from_y = 0.0f;
+ float to_x = 0.0f;
+ float to_y = 0.0f;
+
+ if ((es->width == 0) || (es->height == 0) || (ivisurf == NULL)) {
+ return;
+ }
+
+ view = weston_layout_get_weston_view(ivisurf->layout_surface);
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->width != es->width || ivisurf->height != es->height) {
+
+ ivisurf->width = es->width;
+ ivisurf->height = es->height;
+
+ weston_view_to_global_float(view, 0, 0, &from_x, &from_y);
+ weston_view_to_global_float(view, sx, sy, &to_x, &to_y);
+ configure(view,
+ view->geometry.x + to_x - from_x,
+ view->geometry.y + to_y - from_y);
+
+ weston_layout_surfaceConfigure(ivisurf->layout_surface, es->width, es->height);
+ }
+}
+
+static void
+surface_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource);
+
+ if (ivisurf != NULL) {
+ ivisurf->surface->configure = NULL;
+ ivisurf->surface->configure_private = NULL;
+ ivisurf->surface = NULL;
+ weston_layout_surfaceSetNativeContent(NULL, 0, 0, ivisurf->id_surface);
+ }
+
+ wl_resource_destroy(resource);
+}
+
+static const struct ivi_surface_interface surface_implementation = {
+ surface_destroy,
+};
+
+static struct ivi_shell_surface *
+is_surf_in_surfaces(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct ivi_shell_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+static const struct {
+ uint32_t warning_code; /* enum ivi_surface_warning_code */
+ const char *msg;
+} warning_strings[] = {
+ {IVI_SURFACE_WARNING_CODE_INVALID_WL_SURFACE, "wl_surface is invalid"},
+ {IVI_SURFACE_WARNING_CODE_SURFACE_ID_IN_USE, "surface_id is already assigned by another app"}
+};
+
+/**
+ * Implementation of ivi_application::surface_create.
+ * Creating new ivi_shell_surface with identification to identify the surface
+ * in the system.
+ */
+static void
+application_surface_create(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface,
+ struct wl_resource *surface_resource,
+ uint32_t id)
+{
+ struct ivi_shell *shell = wl_resource_get_user_data(resource);
+ struct ivi_shell_surface *ivisurf = NULL;
+ struct weston_layout_surface *layout_surface = NULL;
+ struct weston_surface *es = wl_resource_get_user_data(surface_resource);
+ struct wl_resource *res;
+ int32_t warn_idx = -1;
+
+ if (es != NULL) {
+ layout_surface = weston_layout_surfaceCreate(es, id_surface);
+ if (layout_surface == NULL)
+ warn_idx = 1;
+ } else {
+ warn_idx = 0;
+ }
+
+ res = wl_resource_create(client, &ivi_surface_interface, 1, id);
+ if (res == NULL) {
+ weston_log("couldn't get surface object");
+ return;
+ }
+
+ if (warn_idx >= 0) {
+ wl_resource_set_implementation(res, &surface_implementation,
+ NULL, NULL);
+ ivi_surface_send_warning(res,
+ warning_strings[warn_idx].warning_code,
+ warning_strings[warn_idx].msg);
+ return;
+ }
+
+ ivisurf = is_surf_in_surfaces(&shell->ivi_surface_list, id_surface);
+ if (ivisurf == NULL) {
+ ivisurf = calloc(1, sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ wl_list_init(&ivisurf->link);
+ wl_list_insert(&shell->ivi_surface_list, &ivisurf->link);
+
+ ivisurf->shell = shell;
+ ivisurf->id_surface = id_surface;
+ }
+
+ ivisurf->width = 0;
+ ivisurf->height = 0;
+ ivisurf->layout_surface = layout_surface;
+ ivisurf->surface = es;
+
+ es->configure = ivi_shell_surface_configure;
+ es->configure_private = ivisurf;
+
+ wl_resource_set_implementation(res, &surface_implementation,
+ ivisurf, NULL);
+}
+
+static const struct ivi_application_interface application_implementation = {
+ application_surface_create
+};
+
+static void
+bind_ivi_application(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct ivi_shell *shell = data;
+ struct wl_resource *resource = NULL;
+
+ resource = wl_resource_create(client, &ivi_application_interface, 1, id);
+
+ wl_resource_set_implementation(resource,
+ &application_implementation,
+ shell, NULL);
+}
+
+/**
+ * Initialization/destruction method of ivi-shell
+ */
+static void
+shell_destroy(struct wl_listener *listener, void *data)
+{
+ struct ivi_shell *shell =
+ container_of(listener, struct ivi_shell, destroy_listener);
+ struct ivi_shell_surface *ivisurf, *next;
+
+ wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) {
+ wl_list_remove(&ivisurf->link);
+ free(ivisurf);
+ }
+
+ free(shell);
+}
+
+static void
+init_ivi_shell(struct weston_compositor *ec, struct ivi_shell *shell)
+{
+ shell->compositor = ec;
+
+ wl_list_init(&ec->layer_list);
+ wl_list_init(&shell->ivi_surface_list);
+}
+
+/**
+ * Initialization of ivi-shell. A library, weston_layout, is also initialized
+ * here by calling weston_layout_initWithCompositor.
+ *
+ */
+
+WL_EXPORT int
+module_init(struct weston_compositor *ec,
+ int *argc, char *argv[])
+{
+ struct ivi_shell *shell = NULL;
+
+ shell = calloc(1, sizeof *shell);
+ if (shell == NULL) {
+ return -1;
+ }
+
+ init_ivi_shell(ec, shell);
+ weston_layout_initWithCompositor(ec);
+
+ shell->destroy_listener.notify = shell_destroy;
+ wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
+
+ if (wl_global_create(ec->wl_display, &ivi_application_interface, 1,
+ shell, bind_ivi_application) == NULL) {
+ return -1;
+ }
+
+ return 0;
+}
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 09:57:58 UTC
Permalink
API set of controlling properties of surface and layer which groups
surfaces. An unique ID whose type is integer is required to create
surface and layer. With the unique ID, surface and layer are identified
to control them. The API set consists of APIs to control properties of
surface and layers about followings,

- visibility.
- opacity.
- clipping (x,y,width,height).
- position and size of it to be displayed.
- orientation per 90 degree.
- add or remove surfaces to a layer.
- order of surfaces/layers in layer/screen to be displayed.
- commit to apply property changes.
- notifications of property change.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
ivi-shell/weston-layout.c | 2633 +++++++++++++++++++++++++++++++++++++++++++++
ivi-shell/weston-layout.h | 920 ++++++++++++++++
2 files changed, 3553 insertions(+)
create mode 100644 ivi-shell/weston-layout.c
create mode 100644 ivi-shell/weston-layout.h

diff --git a/ivi-shell/weston-layout.c b/ivi-shell/weston-layout.c
new file mode 100644
index 0000000..0517e2d
--- /dev/null
+++ b/ivi-shell/weston-layout.c
@@ -0,0 +1,2633 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * Implementation of weston-layout library. The actual view on screen is
+ * not updated till calling weston_layout_commitChanges. A overview from
+ * calling API for updating properties of surfaces/layer to asking compositor
+ * to compose them by using weston_compositor_schedule_repaint,
+ * 0/ initialize this library by weston_layout_initWithCompositor
+ * with (struct weston_compositor *ec) from ivi-shell.
+ * 1/ When a API for updating properties of surface/layer, it updates
+ * pending prop of weston_layout_surface/layer/screen which are structure to
+ * store properties.
+ * 2/ Before calling commitChanges, in case of calling a API to get a property,
+ * return current property, not pending property.
+ * 3/ At the timing of calling weston_layout_commitChanges, pending properties
+ * are applied
+ * to properties.
+ * 4/ According properties, set transformation by using weston_matrix and
+ * weston_view per surfaces and layers in while loop.
+ * 5/ Set damage and trigger transform by using weston_view_geometry_dirty and
+ * weston_view_geometry_dirty.
+ * 6/ Notify update of properties.
+ * 7/ Trigger composition by weston_compositor_schedule_repaint.
+ *
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <cairo.h>
+
+#include "compositor.h"
+#include "weston-layout.h"
+
+enum weston_layout_surface_orientation {
+ WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES = 0,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES = 1,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES = 2,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES = 3,
+};
+
+enum weston_layout_surface_pixelformat {
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_R_8 = 0,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGB_888 = 1,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888 = 2,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGB_565 = 3,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_5551 = 4,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_6661 = 5,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_4444 = 6,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_UNKNOWN = 7,
+};
+
+struct link_layer {
+ struct weston_layout_layer *ivilayer;
+ struct wl_list link;
+};
+
+struct link_screen {
+ struct weston_layout_screen *iviscrn;
+ struct wl_list link;
+};
+
+struct link_layerPropertyNotification {
+ layerPropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfacePropertyNotification {
+ surfacePropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerCreateNotification {
+ layerCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerRemoveNotification {
+ layerRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceCreateNotification {
+ surfaceCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceRemoveNotification {
+ surfaceRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceConfigureNotification {
+ surfaceConfigureNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct weston_layout;
+
+struct weston_layout_surface {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_layer;
+ uint32_t update_count;
+ uint32_t id_surface;
+
+ struct weston_layout *layout;
+ struct weston_surface *surface;
+ struct weston_view *view;
+
+ uint32_t buffer_width;
+ uint32_t buffer_height;
+
+ struct wl_listener surface_destroy_listener;
+ struct weston_transform surface_rotation;
+ struct weston_transform layer_rotation;
+ struct weston_transform surface_pos;
+ struct weston_transform layer_pos;
+ struct weston_transform scaling;
+ struct weston_layout_SurfaceProperties prop;
+ int32_t pixelformat;
+ uint32_t event_mask;
+
+ struct {
+ struct weston_layout_SurfaceProperties prop;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list link;
+ struct wl_list list_layer;
+ } order;
+};
+
+struct weston_layout_layer {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_screen;
+ uint32_t id_layer;
+
+ struct weston_layout *layout;
+ struct weston_layer el;
+
+ struct weston_layout_LayerProperties prop;
+ uint32_t event_mask;
+
+ struct {
+ struct weston_layout_LayerProperties prop;
+ struct wl_list list_surface;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_surface;
+ struct wl_list link;
+ } order;
+};
+
+struct weston_layout_screen {
+ struct wl_list link;
+ uint32_t id_screen;
+
+ struct weston_layout *layout;
+ struct weston_output *output;
+
+ uint32_t event_mask;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } order;
+};
+
+struct weston_layout {
+ struct weston_compositor *compositor;
+
+ struct wl_list list_surface;
+ struct wl_list list_layer;
+ struct wl_list list_screen;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ } layer_notification;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ struct wl_list list_configure;
+ } surface_notification;
+
+ /* to enalbe displaying cursor*/
+ int32_t is_cursor_enabled;
+};
+
+struct weston_layout ivilayout = {0};
+
+static struct weston_layout *
+get_instance(void)
+{
+ return &ivilayout;
+}
+
+/**
+ * Internal API to add/remove a surface from layer.
+ */
+static void
+add_ordersurface_to_layer(struct weston_layout_surface *ivisurf,
+ struct weston_layout_layer *ivilayer)
+{
+ struct link_layer *link_layer = NULL;
+
+ link_layer = malloc(sizeof *link_layer);
+ if (link_layer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_layer->ivilayer = ivilayer;
+ wl_list_init(&link_layer->link);
+ wl_list_insert(&ivisurf->list_layer, &link_layer->link);
+}
+
+static void
+remove_ordersurface_from_layer(struct weston_layout_surface *ivisurf)
+{
+ struct link_layer *link_layer = NULL;
+ struct link_layer *next = NULL;
+
+ wl_list_for_each_safe(link_layer, next, &ivisurf->list_layer, link) {
+ if (!wl_list_empty(&link_layer->link)) {
+ wl_list_remove(&link_layer->link);
+ }
+ free(link_layer);
+ link_layer = NULL;
+ }
+ wl_list_init(&ivisurf->list_layer);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static void
+add_orderlayer_to_screen(struct weston_layout_layer *ivilayer,
+ struct weston_layout_screen *iviscrn)
+{
+ struct link_screen *link_scrn = NULL;
+
+ link_scrn = malloc(sizeof *link_scrn);
+ if (link_scrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_scrn->iviscrn = iviscrn;
+ wl_list_init(&link_scrn->link);
+ wl_list_insert(&ivilayer->list_screen, &link_scrn->link);
+}
+
+static void
+remove_orderlayer_from_screen(struct weston_layout_layer *ivilayer)
+{
+ struct link_screen *link_scrn = NULL;
+ struct link_screen *next = NULL;
+
+ wl_list_for_each_safe(link_scrn, next, &ivilayer->list_screen, link) {
+ if (!wl_list_empty(&link_scrn->link)) {
+ wl_list_remove(&link_scrn->link);
+ }
+ free(link_scrn);
+ link_scrn = NULL;
+ }
+ wl_list_init(&ivilayer->list_screen);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static struct weston_layout_surface *
+get_surface(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct weston_layout_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+static struct weston_layout_layer *
+get_layer(struct wl_list *list_layer, uint32_t id_layer)
+{
+ struct weston_layout_layer *ivilayer;
+
+ wl_list_for_each(ivilayer, list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Called at destruction of ivi_surface
+ */
+static void
+westonsurface_destroy_from_ivisurface(struct wl_listener *listener, void *data)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+
+ ivisurf = container_of(listener, struct weston_layout_surface,
+ surface_destroy_listener);
+ ivisurf->surface = NULL;
+}
+
+/**
+ * Internal API to check layer/surface already added in layer/screen.
+ * Called by weston_layout_layerAddSurface/weston_layout_screenAddLayer
+ */
+static int
+is_surface_in_layer(struct weston_layout_surface *ivisurf,
+ struct weston_layout_layer *ivilayer)
+{
+ struct weston_layout_surface *surf = NULL;
+
+ wl_list_for_each(surf, &ivilayer->pending.list_surface, pending.link) {
+ if (surf->id_surface == ivisurf->id_surface) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+is_layer_in_screen(struct weston_layout_layer *ivilayer,
+ struct weston_layout_screen *iviscrn)
+{
+ struct weston_layout_layer *layer = NULL;
+
+ wl_list_for_each(layer, &iviscrn->pending.list_layer, pending.link) {
+ if (layer->id_layer == ivilayer->id_layer) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Internal API to initialize screens found from output_list of weston_compositor.
+ * Called by weston_layout_initWithCompositor.
+ */
+static void
+create_screen(struct weston_compositor *ec)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_output *output = NULL;
+ int32_t count = 0;
+
+ wl_list_for_each(output, &ec->output_list, link) {
+ iviscrn = calloc(1, sizeof *iviscrn);
+ if (iviscrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ continue;
+ }
+
+ wl_list_init(&iviscrn->link);
+ iviscrn->layout = layout;
+
+ iviscrn->id_screen = count;
+ count++;
+
+ iviscrn->output = output;
+ iviscrn->event_mask = 0;
+
+ wl_list_init(&iviscrn->pending.list_layer);
+ wl_list_init(&iviscrn->pending.link);
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_init(&iviscrn->order.link);
+
+ wl_list_insert(&layout->list_screen, &iviscrn->link);
+ }
+}
+
+/**
+ * Internal APIs to initialize properties of surface/layer when they are created.
+ */
+static void
+init_layerProperties(struct weston_layout_LayerProperties *prop,
+ int32_t width, int32_t height)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+ prop->destWidth = width;
+ prop->destHeight = height;
+}
+
+static void
+init_surfaceProperties(struct weston_layout_SurfaceProperties *prop)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+}
+
+/**
+ * Internal APIs to be called from weston_layout_commitChanges.
+ */
+static void
+update_opacity(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ double layer_alpha = wl_fixed_to_double(ivilayer->prop.opacity);
+ double surf_alpha = wl_fixed_to_double(ivisurf->prop.opacity);
+
+ if ((ivilayer->event_mask & IVI_NOTIFICATION_OPACITY) ||
+ (ivisurf->event_mask & IVI_NOTIFICATION_OPACITY)) {
+ if (ivisurf->view == NULL) {
+ return;
+ }
+ ivisurf->view->alpha = layer_alpha * surf_alpha;
+ }
+}
+
+static void
+update_surface_orientation(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->surface_rotation.matrix;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ if (view == NULL) {
+ return;
+ }
+
+ if ((ivilayer->prop.destWidth == 0) ||
+ (ivilayer->prop.destHeight == 0)) {
+ return;
+ }
+ width = (float)ivilayer->prop.destWidth;
+ height = (float)ivilayer->prop.destHeight;
+
+ switch (ivisurf->prop.orientation) {
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->surface_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_layer_orientation(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_surface *es = ivisurf->surface;
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->layer_rotation.matrix;
+ struct weston_output *output = NULL;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ if (es == NULL || view == NULL) {
+ return;
+ }
+
+ output = es->output;
+ if (output == NULL) {
+ return;
+ }
+ if ((output->width == 0) || (output->height == 0)) {
+ return;
+ }
+ width = (float)output->width;
+ height = (float)output->height;
+
+ switch (ivilayer->prop.orientation) {
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->layer_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->layer_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_surface_position(struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ float tx = (float)ivisurf->prop.destX;
+ float ty = (float)ivisurf->prop.destY;
+ struct weston_matrix *matrix = &ivisurf->surface_pos.matrix;
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->surface_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+
+#if 0
+ /* disable zoom animation */
+ weston_zoom_run(es, 0.0, 1.0, NULL, NULL);
+#endif
+
+}
+
+static void
+update_layer_position(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->layer_pos.matrix;
+ float tx = (float)ivilayer->prop.destX;
+ float ty = (float)ivilayer->prop.destY;
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->layer_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(
+ &view->geometry.transformation_list,
+ &ivisurf->layer_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_scale(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->scaling.matrix;
+ float sx = 0.0f;
+ float sy = 0.0f;
+ float lw = 0.0f;
+ float sw = 0.0f;
+ float lh = 0.0f;
+ float sh = 0.0f;
+
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->prop.sourceWidth == 0 && ivisurf->prop.sourceHeight == 0) {
+ ivisurf->prop.sourceWidth = ivisurf->buffer_width;
+ ivisurf->prop.sourceHeight = ivisurf->buffer_height;
+
+ if (ivisurf->prop.destWidth == 0 && ivisurf->prop.destHeight == 0) {
+ ivisurf->prop.destWidth = ivisurf->buffer_width;
+ ivisurf->prop.destHeight = ivisurf->buffer_height;
+ }
+ }
+
+ lw = ((float)ivilayer->prop.destWidth / ivilayer->prop.sourceWidth );
+ sw = ((float)ivisurf->prop.destWidth / ivisurf->prop.sourceWidth );
+ lh = ((float)ivilayer->prop.destHeight / ivilayer->prop.sourceHeight);
+ sh = ((float)ivisurf->prop.destHeight / ivisurf->prop.sourceHeight );
+ sx = sw * lw;
+ sy = sh * lh;
+
+ wl_list_remove(&ivisurf->scaling.link);
+ weston_matrix_init(matrix);
+ weston_matrix_scale(matrix, sx, sy, 1.0f);
+
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->scaling.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_prop(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ if (ivilayer->event_mask | ivisurf->event_mask) {
+ update_opacity(ivilayer, ivisurf);
+ update_layer_orientation(ivilayer, ivisurf);
+ update_layer_position(ivilayer, ivisurf);
+ update_surface_position(ivisurf);
+ update_surface_orientation(ivilayer, ivisurf);
+ update_scale(ivilayer, ivisurf);
+
+ ivisurf->update_count++;
+
+ if (ivisurf->view != NULL) {
+ weston_view_geometry_dirty(ivisurf->view);
+ }
+
+ if (ivisurf->surface != NULL) {
+ weston_surface_damage(ivisurf->surface);
+ }
+ }
+}
+
+static void
+commit_changes(struct weston_layout *layout)
+{
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ update_prop(ivilayer, ivisurf);
+ }
+ }
+ }
+}
+
+static void
+commit_list_surface(struct weston_layout *layout)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ ivisurf->prop = ivisurf->pending.prop;
+ }
+}
+
+static void
+commit_list_layer(struct weston_layout *layout)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ ivilayer->prop = ivilayer->pending.prop;
+
+ if (!(ivilayer->event_mask & IVI_NOTIFICATION_ADD)) {
+ continue;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->order.list_surface, order.link) {
+ remove_ordersurface_from_layer(ivisurf);
+
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_for_each(ivisurf, &ivilayer->pending.list_surface,
+ pending.link) {
+ wl_list_insert(&ivilayer->order.list_surface,
+ &ivisurf->order.link);
+ add_ordersurface_to_layer(ivisurf, ivilayer);
+ }
+ }
+}
+
+static void
+commit_list_screen(struct weston_layout *layout)
+{
+ struct weston_compositor *ec = layout->compositor;
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_layer *next = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ if (iviscrn->event_mask & IVI_NOTIFICATION_ADD) {
+ wl_list_for_each_safe(ivilayer, next,
+ &iviscrn->order.list_layer, order.link) {
+ remove_orderlayer_from_screen(ivilayer);
+
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.link);
+ }
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_for_each(ivilayer, &iviscrn->pending.list_layer,
+ pending.link) {
+ wl_list_insert(&iviscrn->order.list_layer,
+ &ivilayer->order.link);
+ add_orderlayer_to_screen(ivilayer, iviscrn);
+ }
+ iviscrn->event_mask = 0;
+ }
+
+ /* For rendering */
+ wl_list_init(&ec->layer_list);
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+ if (ivilayer->prop.visibility == 0) {
+ continue;
+ }
+
+ wl_list_insert(&ec->layer_list, &ivilayer->el.link);
+ wl_list_init(&ivilayer->el.view_list);
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ if (ivisurf->prop.visibility == 0) {
+ continue;
+ }
+
+ if (ivisurf->surface == NULL || ivisurf->view == NULL) {
+ continue;
+ }
+
+ wl_list_insert(&ivilayer->el.view_list,
+ &ivisurf->view->layer_link);
+ ivisurf->surface->output = iviscrn->output;
+ }
+ }
+
+ /*Add cursor layer if cursor is configured.*/
+ if (layout->is_cursor_enabled) {
+ wl_list_insert(&ec->layer_list, &ec->cursor_layer.link);
+ }
+
+ break;
+ }
+}
+
+static void
+send_surface_prop(struct weston_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivisurf->list_notification, link) {
+ notification->callback(ivisurf, &ivisurf->prop,
+ ivisurf->event_mask,
+ notification->userdata);
+ }
+
+ ivisurf->event_mask = 0;
+}
+
+static void
+send_layer_prop(struct weston_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivilayer->list_notification, link) {
+ notification->callback(ivilayer, &ivilayer->prop,
+ ivilayer->event_mask,
+ notification->userdata);
+ }
+
+ ivilayer->event_mask = 0;
+}
+
+static void
+send_prop(struct weston_layout *layout)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ send_layer_prop(ivilayer);
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ send_surface_prop(ivisurf);
+ }
+}
+
+/**
+ * Exported APIs of weston-layout library are implemented from here.
+ * Brief of APIs is described in weston-layout.h.
+ */
+WL_EXPORT struct weston_view *
+weston_layout_get_weston_view(struct weston_layout_surface *surface)
+{
+ return (surface != NULL) ? surface->view : NULL;
+}
+
+WL_EXPORT void
+weston_layout_initWithCompositor(struct weston_compositor *ec)
+{
+ struct weston_layout *layout = get_instance();
+
+ layout->compositor = ec;
+
+ wl_list_init(&layout->list_surface);
+ wl_list_init(&layout->list_layer);
+ wl_list_init(&layout->list_screen);
+
+ wl_list_init(&layout->layer_notification.list_create);
+ wl_list_init(&layout->layer_notification.list_remove);
+
+ wl_list_init(&layout->surface_notification.list_create);
+ wl_list_init(&layout->surface_notification.list_remove);
+ wl_list_init(&layout->surface_notification.list_configure);
+
+ create_screen(ec);
+
+ struct weston_config *config = weston_config_parse("weston.ini");
+ struct weston_config_section *s =
+ weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ /*A cursor is configured if weston.ini has keys.*/
+ char* cursor_theme = NULL;
+ weston_config_section_get_string(s, "cursor-theme", &cursor_theme, NULL);
+ layout->is_cursor_enabled = (NULL != cursor_theme);
+ free(cursor_theme);
+ weston_config_destroy(config);
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationCreateLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationRemoveLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationCreateSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceConfigureNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationConfigureSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_configure, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT uint32_t
+weston_layout_getIdOfSurface(struct weston_layout_surface *ivisurf)
+{
+ return ivisurf->id_surface;
+}
+
+WL_EXPORT uint32_t
+weston_layout_getIdOfLayer(struct weston_layout_layer *ivilayer)
+{
+ return ivilayer->id_layer;
+}
+
+WL_EXPORT struct weston_layout_layer *
+weston_layout_getLayerFromId(uint32_t id_layer)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct weston_layout_surface *
+weston_layout_getSurfaceFromId(uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct weston_layout_screen *
+weston_layout_getScreenFromId(uint32_t id_screen)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ (void)id_screen;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+//FIXME : select iviscrn from list_screen by id_screen
+ return iviscrn;
+ break;
+ }
+
+ return NULL;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreenResolution(struct weston_layout_screen *iviscrn,
+ uint32_t *pWidth, uint32_t *pHeight)
+{
+ struct weston_output *output = NULL;
+
+ if (pWidth == NULL || pHeight == NULL) {
+ weston_log("weston_layout_getScreenResolution: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ *pWidth = output->current_mode->width;
+ *pHeight = output->current_mode->height;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceAddNotification(struct weston_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ if (ivisurf == NULL || callback == NULL) {
+ weston_log("weston_layout_surfaceAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivisurf->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceRemoveNotification(struct weston_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+ struct link_surfacePropertyNotification *next = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivisurf->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ notification = NULL;
+ }
+ wl_list_init(&ivisurf->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT struct weston_layout_surface*
+weston_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (wl_surface == NULL) {
+ weston_log("weston_layout_surfaceCreate: invalid argument\n");
+ return NULL;
+ }
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf != NULL) {
+//FIXME
+ weston_log("id_surface is already created\n");
+ ivisurf->surface = wl_surface;
+ if (wl_surface != NULL) {
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(wl_surface->resource,
+ &ivisurf->surface_destroy_listener);
+
+ }
+
+ if (ivisurf->view != NULL) {
+ weston_view_destroy(ivisurf->view);
+ }
+ ivisurf->view = NULL;
+
+ if (wl_surface != NULL) {
+ ivisurf->view = weston_view_create(wl_surface);
+ if (ivisurf->view == NULL) {
+ weston_log("fails to allocate memory\n");
+ }
+ }
+
+ ivisurf->buffer_width = 0;
+ ivisurf->buffer_height = 0;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return NULL;
+ }
+
+ ivisurf = calloc(1, sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivisurf->link);
+ wl_list_init(&ivisurf->list_notification);
+ wl_list_init(&ivisurf->list_layer);
+ ivisurf->id_surface = id_surface;
+ ivisurf->layout = layout;
+
+ ivisurf->surface = wl_surface;
+ if (wl_surface != NULL) {
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(wl_surface->resource,
+ &ivisurf->surface_destroy_listener);
+
+ ivisurf->view = weston_view_create(wl_surface);
+ if (ivisurf->view == NULL) {
+ weston_log("fails to allocate memory\n");
+ }
+ }
+
+ ivisurf->buffer_width = 0;
+ ivisurf->buffer_height = 0;
+
+ wl_list_init(&ivisurf->surface_rotation.link);
+ wl_list_init(&ivisurf->layer_rotation.link);
+ wl_list_init(&ivisurf->surface_pos.link);
+ wl_list_init(&ivisurf->layer_pos.link);
+ wl_list_init(&ivisurf->scaling.link);
+
+ init_surfaceProperties(&ivisurf->prop);
+ ivisurf->pixelformat = WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+ ivisurf->event_mask = 0;
+
+ ivisurf->pending.prop = ivisurf->prop;
+ wl_list_init(&ivisurf->pending.link);
+
+ wl_list_init(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.list_layer);
+
+ wl_list_insert(&layout->list_surface, &ivisurf->link);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return ivisurf;
+}
+
+WL_EXPORT void
+weston_layout_surfaceConfigure(struct weston_layout_surface *ivisurf,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf->buffer_width = width;
+ ivisurf->buffer_height = height;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_configure, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceRemove(struct weston_layout_surface *ivisurf)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceRemove: invalid argument\n");
+ return -1;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+ if (!wl_list_empty(&ivisurf->link)) {
+ wl_list_remove(&ivisurf->link);
+ }
+ remove_ordersurface_from_layer(ivisurf);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ if (ivisurf->view != NULL) {
+ weston_view_destroy(ivisurf->view);
+ }
+
+ free(ivisurf);
+ ivisurf = NULL;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_UpdateInputEventAcceptanceOn(struct weston_layout_surface *ivisurf,
+ uint32_t devices, uint32_t acceptance)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)devices;
+ (void)acceptance;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceInitialize(struct weston_layout_surface **pSurfaceId)
+{
+ /* not supported */
+ (void)pSurfaceId;
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getPropertiesOfLayer(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties *pLayerProperties)
+{
+ if (ivilayer == NULL || pLayerProperties == NULL) {
+ weston_log("weston_layout_getPropertiesOfLayer: invalid argument\n");
+ return -1;
+ }
+
+ *pLayerProperties = ivilayer->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ uint32_t *pNumberOfHardwareLayers)
+{
+ /* not supported */
+ (void)id_screen;
+ (void)pNumberOfHardwareLayers;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreens(uint32_t *pLength, weston_layout_screen_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getScreens: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_screen_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ (*ppArray)[n++] = iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreensUnderLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_screen_ptr **ppArray)
+{
+ struct link_screen *link_scrn = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getScreensUnderLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_screen_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_scrn, &ivilayer->list_screen, link) {
+ (*ppArray)[n++] = link_scrn->iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayers(uint32_t *pLength, weston_layout_layer_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayersOnScreen(struct weston_layout_screen *iviscrn,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (iviscrn == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayersOnScreen: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&iviscrn->order.list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayersUnderSurface(struct weston_layout_surface *ivisurf,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray)
+{
+ struct link_layer *link_layer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivisurf == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivisurf->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_layer, &ivisurf->list_layer, link) {
+ (*ppArray)[n++] = link_layer->ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getSurfaces(uint32_t *pLength, weston_layout_surface_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getSurfaces: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_surface);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_surface_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getSurfacesOnLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_surface_ptr **ppArray)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getSurfaceIDsOnLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->order.list_surface);
+
+ if (length != 0) {
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_surface_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT struct weston_layout_layer *
+weston_layout_layerCreateWithDimension(uint32_t id_layer,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ struct link_layerCreateNotification *notification = NULL;
+
+ ivilayer = get_layer(&layout->list_layer, id_layer);
+ if (ivilayer != NULL) {
+ weston_log("id_layer is already created\n");
+ return ivilayer;
+ }
+
+ ivilayer = calloc(1, sizeof *ivilayer);
+ if (ivilayer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivilayer->link);
+ wl_list_init(&ivilayer->list_notification);
+ wl_list_init(&ivilayer->list_screen);
+ ivilayer->layout = layout;
+ ivilayer->id_layer = id_layer;
+
+ init_layerProperties(&ivilayer->prop, width, height);
+ ivilayer->event_mask = 0;
+
+ wl_list_init(&ivilayer->pending.list_surface);
+ wl_list_init(&ivilayer->pending.link);
+ ivilayer->pending.prop = ivilayer->prop;
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_init(&ivilayer->order.link);
+
+ wl_list_insert(&layout->list_layer, &ivilayer->link);
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ return ivilayer;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemove(struct weston_layout_layer *ivilayer)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerRemove: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+ if (!wl_list_empty(&ivilayer->link)) {
+ wl_list_remove(&ivilayer->link);
+ }
+ remove_orderlayer_from_screen(ivilayer);
+
+ free(ivilayer);
+ ivilayer = NULL;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetType(struct weston_layout_layer *ivilayer,
+ uint32_t *pLayerType)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pLayerType;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t newVisibility)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetVisibility(struct weston_layout_layer *ivilayer, uint32_t *pVisibility)
+{
+ if (ivilayer == NULL || pVisibility == NULL) {
+ weston_log("weston_layout_layerGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivilayer->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetOpacity(struct weston_layout_layer *ivilayer,
+ float opacity)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->opacity = opacity;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetOpacity(struct weston_layout_layer *ivilayer,
+ float *pOpacity)
+{
+ if (ivilayer == NULL || pOpacity == NULL) {
+ weston_log("weston_layout_layerGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivilayer->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetSourceRectangle(struct weston_layout_layer *ivilayer,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetDestinationRectangle(struct weston_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension)
+{
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_layerGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivilayer->prop.destX;
+ pDimension[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_layerSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetPosition(struct weston_layout_layer *ivilayer, int32_t *pPosition)
+{
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("weston_layout_layerGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivilayer->prop.destX;
+ pPosition[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetPosition(struct weston_layout_layer *ivilayer, int32_t *pPosition)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("weston_layout_layerSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t orientation)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->orientation = orientation;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t *pOrientation)
+{
+ if (ivilayer == NULL || pOrientation == NULL) {
+ weston_log("weston_layout_layerGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivilayer->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetChromaKey(struct weston_layout_layer *ivilayer, uint32_t* pColor)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetRenderOrder(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface **pSurface,
+ uint32_t number)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t *id_surface = NULL;
+ uint32_t i = 0;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_init(&ivilayer->pending.list_surface);
+
+ if (pSurface == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_surface = &pSurface[i]->id_surface;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (*id_surface != ivisurf->id_surface) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetCapabilities(struct weston_layout_layer *ivilayer,
+ uint32_t *pCapabilities)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerTypeGetCapabilities(uint32_t layerType,
+ uint32_t *pCapabilities)
+{
+ /* not supported */
+ (void)layerType;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t newVisibility)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t *pVisibility)
+{
+ if (ivisurf == NULL || pVisibility == NULL) {
+ weston_log("weston_layout_surfaceGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivisurf->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetOpacity(struct weston_layout_surface *ivisurf,
+ float opacity)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->opacity = opacity;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetOpacity(struct weston_layout_surface *ivisurf,
+ float *pOpacity)
+{
+ if (ivisurf == NULL || pOpacity == NULL) {
+ weston_log("weston_layout_surfaceGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivisurf->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_SetKeyboardFocusOn(struct weston_layout_surface *ivisurf)
+{
+ /* not supported */
+ (void)ivisurf;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_GetKeyboardFocusSurfaceId(struct weston_layout_surface **pSurfaceId)
+{
+ /* not supported */
+ (void)pSurfaceId;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetDestinationRectangle(struct weston_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetDimension(struct weston_layout_surface *ivisurf, uint32_t *pDimension)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_surfaceSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension)
+{
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_surfaceGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivisurf->prop.destWidth;
+ pDimension[1] = ivisurf->prop.destHeight;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("weston_layout_surfaceSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("weston_layout_surfaceGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivisurf->prop.destX;
+ pPosition[1] = ivisurf->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t orientation)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->orientation = orientation;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t *pOrientation)
+{
+ if (ivisurf == NULL || pOrientation == NULL) {
+ weston_log("weston_layout_surfaceGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivisurf->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetPixelformat(struct weston_layout_layer *ivisurf, uint32_t *pPixelformat)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)pPixelformat;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetChromaKey(struct weston_layout_surface *ivisurf, uint32_t* pColor)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_screenAddLayer(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer *addlayer)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_layer *next = NULL;
+ int is_layer_in_scrn = 0;
+
+ if (iviscrn == NULL || addlayer == NULL) {
+ weston_log("weston_layout_screenAddLayer: invalid argument\n");
+ return -1;
+ }
+
+ is_layer_in_scrn = is_layer_in_screen(addlayer, iviscrn);
+ if (is_layer_in_scrn == 1) {
+ weston_log("weston_layout_screenAddLayer: addlayer is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivilayer, next, &layout->list_layer, link) {
+ if (ivilayer->id_layer == addlayer->id_layer) {
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_screenSetRenderOrder(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer **pLayer,
+ const uint32_t number)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t *id_layer = NULL;
+ uint32_t i = 0;
+
+ if (iviscrn == NULL) {
+ weston_log("weston_layout_screenSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_init(&iviscrn->pending.list_layer);
+
+ if (pLayer == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_layer = &pLayer[i]->id_layer;
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (*id_layer == ivilayer->id_layer) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeScreenshot(struct weston_layout_screen *iviscrn,
+ const char *filename)
+{
+ struct weston_output *output = NULL;
+ cairo_surface_t *cairo_surf = NULL;
+ int32_t i = 0;
+ int32_t width = 0;
+ int32_t height = 0;
+ int32_t stride = 0;
+ uint8_t *readpixs = NULL;
+ uint8_t *writepixs = NULL;
+ uint8_t *d = NULL;
+ uint8_t *s = NULL;
+
+ if (iviscrn == NULL || filename == NULL) {
+ weston_log("weston_layout_takeScreenshot: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ output->disable_planes--;
+
+ width = output->current_mode->width;
+ height = output->current_mode->height;
+ stride = width * (PIXMAN_FORMAT_BPP(output->compositor->read_format) / 8);
+
+ readpixs = malloc(stride * height);
+ if (readpixs == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+ writepixs = malloc(stride * height);
+ if (writepixs == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ output->compositor->renderer->read_pixels(output,
+ output->compositor->read_format, readpixs,
+ 0, 0, width, height);
+
+ s = readpixs;
+ d = writepixs + stride * (height - 1);
+
+ for (i = 0; i < height; i++) {
+ memcpy(d, s, stride);
+ d -= stride;
+ s += stride;
+ }
+
+ cairo_surf = cairo_image_surface_create_for_data(writepixs,
+ CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+ cairo_surface_write_to_png(cairo_surf, filename);
+ cairo_surface_destroy(cairo_surf);
+ free(writepixs);
+ free(readpixs);
+ writepixs = NULL;
+ readpixs = NULL;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeLayerScreenshot(const char *filename, struct weston_layout_layer *ivilayer)
+{
+ /* not supported */
+ (void)filename;
+ (void)ivilayer;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeSurfaceScreenshot(const char *filename,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_compositor *ec = layout->compositor;
+ cairo_surface_t *cairo_surf;
+ int32_t width;
+ int32_t height;
+ int32_t stride;
+ uint8_t *pixels;
+
+ if (filename == NULL || ivisurf == NULL) {
+ weston_log("weston_layout_takeSurfaceScreenshot: invalid argument\n");
+ return -1;
+ }
+
+ width = ivisurf->prop.destWidth;
+ height = ivisurf->prop.destHeight;
+ stride = width * (PIXMAN_FORMAT_BPP(ec->read_format) / 8);
+
+ pixels = malloc(stride * height);
+ if (pixels == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ ec->renderer->read_surface_pixels(ivisurf->surface,
+ ec->read_format, pixels,
+ 0, 0, width, height);
+
+ cairo_surf = cairo_image_surface_create_for_data(pixels,
+ CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+ cairo_surface_write_to_png(cairo_surf, filename);
+ cairo_surface_destroy(cairo_surf);
+
+ free(pixels);
+ pixels = NULL;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_SetOptimizationMode(uint32_t id, uint32_t mode)
+{
+ /* not supported */
+ (void)id;
+ (void)mode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_GetOptimizationMode(uint32_t id, uint32_t *pMode)
+{
+ /* not supported */
+ (void)id;
+ (void)pMode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerAddNotification(struct weston_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ if (ivilayer == NULL || callback == NULL) {
+ weston_log("weston_layout_layerAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivilayer->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemoveNotification(struct weston_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+ struct link_layerPropertyNotification *next = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivilayer->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ notification = NULL;
+ }
+ wl_list_init(&ivilayer->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getPropertiesOfSurface(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties *pSurfaceProperties)
+{
+ if (ivisurf == NULL || pSurfaceProperties == NULL) {
+ weston_log("weston_layout_getPropertiesOfSurface: invalid argument\n");
+ return -1;
+ }
+
+ *pSurfaceProperties = ivisurf->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerAddSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *addsurf)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+ int is_surf_in_layer = 0;
+
+ if (ivilayer == NULL || addsurf == NULL) {
+ weston_log("weston_layout_layerAddSurface: invalid argument\n");
+ return -1;
+ }
+
+ is_surf_in_layer = is_surface_in_layer(addsurf, ivilayer);
+ if (is_surf_in_layer == 1) {
+ weston_log("weston_layout_layerAddSurface: addsurf is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivisurf, next, &layout->list_surface, link) {
+ if (ivisurf->id_surface == addsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemoveSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *remsurf)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+
+ if (ivilayer == NULL || remsurf == NULL) {
+ weston_log("weston_layout_layerRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->pending.list_surface, pending.link) {
+ if (ivisurf->id_surface == remsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetSourceRectangle(struct weston_layout_surface *ivisurf,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_commitChanges(void)
+{
+ struct weston_layout *layout = get_instance();
+
+ commit_list_surface(layout);
+ commit_list_layer(layout);
+ commit_list_screen(layout);
+
+ commit_changes(layout);
+ send_prop(layout);
+ weston_compositor_schedule_repaint(layout->compositor);
+
+ return 0;
+}
diff --git a/ivi-shell/weston-layout.h b/ivi-shell/weston-layout.h
new file mode 100644
index 0000000..871fea1
--- /dev/null
+++ b/ivi-shell/weston-layout.h
@@ -0,0 +1,920 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * The weston-layout library supports API set of controlling properties of
+ * surface and layer which groups surfaces. An unique ID whose type is integer
+ * is required to create surface and layer. With the unique ID, surface and
+ * layer are identified to control them. The API set consists of APIs to control
+ * properties of surface and layers about followings,
+ * - visibility.
+ * - opacity.
+ * - clipping (x,y,width,height).
+ * - position and size of it to be displayed.
+ * - orientation per 90 degree.
+ * - add or remove surfaces to a layer.
+ * - order of surfaces/layers in layer/screen to be displayed.
+ * - commit to apply property changes.
+ * - notifications of property change.
+ *
+ * Management of surfaces and layers grouping these surfaces are common way in
+ * In-Vehicle Infotainment system, which integrate several domains in one system.
+ * A layer is allocated to a domain in order to control application surfaces
+ * grouped to the layer all together.
+ */
+
+#ifndef _WESTON_LAYOUT_H_
+#define _WESTON_LAYOUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "compositor.h"
+
+struct weston_layout_SurfaceProperties
+{
+ float opacity;
+ uint32_t sourceX;
+ uint32_t sourceY;
+ uint32_t sourceWidth;
+ uint32_t sourceHeight;
+ uint32_t origSourceWidth;
+ uint32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ uint32_t destWidth;
+ uint32_t destHeight;
+ uint32_t orientation;
+ uint32_t visibility;
+ uint32_t frameCounter;
+ uint32_t drawCounter;
+ uint32_t updateCounter;
+ uint32_t pixelformat;
+ uint32_t nativeSurface;
+ uint32_t inputDevicesAcceptance;
+ uint32_t chromaKeyEnabled;
+ uint32_t chromaKeyRed;
+ uint32_t chromaKeyGreen;
+ uint32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct weston_layout_LayerProperties
+{
+ float opacity;
+ uint32_t sourceX;
+ uint32_t sourceY;
+ uint32_t sourceWidth;
+ uint32_t sourceHeight;
+ uint32_t origSourceWidth;
+ uint32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ uint32_t destWidth;
+ uint32_t destHeight;
+ uint32_t orientation;
+ uint32_t visibility;
+ uint32_t type;
+ uint32_t chromaKeyEnabled;
+ uint32_t chromaKeyRed;
+ uint32_t chromaKeyGreen;
+ uint32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct weston_layout_layer;
+struct weston_layout_surface;
+struct weston_layout_screen;
+
+typedef struct weston_layout_surface* weston_layout_surface_ptr;
+typedef struct weston_layout_layer* weston_layout_layer_ptr;
+typedef struct weston_layout_screen* weston_layout_screen_ptr;
+
+#define IVI_BIT(x) (1 << (x))
+enum weston_layout_notification_mask {
+ IVI_NOTIFICATION_OPACITY = IVI_BIT(1),
+ IVI_NOTIFICATION_SOURCE_RECT = IVI_BIT(2),
+ IVI_NOTIFICATION_DEST_RECT = IVI_BIT(3),
+ IVI_NOTIFICATION_DIMENSION = IVI_BIT(4),
+ IVI_NOTIFICATION_POSITION = IVI_BIT(5),
+ IVI_NOTIFICATION_ORIENTATION = IVI_BIT(6),
+ IVI_NOTIFICATION_VISIBILITY = IVI_BIT(7),
+ IVI_NOTIFICATION_PIXELFORMAT = IVI_BIT(8),
+ IVI_NOTIFICATION_ADD = IVI_BIT(9),
+ IVI_NOTIFICATION_ALL = 0xFFFF
+};
+
+typedef void(*layerPropertyNotificationFunc)(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties*,
+ enum weston_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*surfacePropertyNotificationFunc)(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties*,
+ enum weston_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*layerCreateNotificationFunc)(struct weston_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*layerRemoveNotificationFunc)(struct weston_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*surfaceCreateNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceRemoveNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceConfigureNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+/**
+ * \brief to be called by ivi-shell in order to set initail view of
+ * weston_surface.
+ */
+struct weston_view *
+weston_layout_get_weston_view(struct weston_layout_surface *surface);
+
+/**
+ * \brief initialize weston-layout
+ */
+void
+weston_layout_initWithCompositor(struct weston_compositor *ec);
+
+/**
+ * \brief register for notification when layer is created
+ */
+int32_t
+weston_layout_setNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when layer is removed
+ */
+int32_t
+weston_layout_setNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is created
+ */
+int32_t
+weston_layout_setNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is removed
+ */
+int32_t
+weston_layout_setNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is configured
+ */
+int32_t
+weston_layout_setNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief get id of surface from weston_layout_surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+uint32_t
+weston_layout_getIdOfSurface(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief get id of layer from weston_layout_layer
+ *
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+uint32_t
+weston_layout_getIdOfLayer(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief get weston_layout_layer from id of layer
+ *
+ * \return (struct weston_layout_layer *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_layer *
+weston_layout_getLayerFromId(uint32_t id_layer);
+
+/**
+ * \brief get weston_layout_surface from id of surface
+ *
+ * \return (struct weston_layout_surface *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_surface *
+weston_layout_getSurfaceFromId(uint32_t id_surface);
+
+/**
+ * \brief get weston_layout_screen from id of screen
+ *
+ * \return (struct weston_layout_screen *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_screen *
+weston_layout_getScreenFromId(uint32_t id_screen);
+
+/**
+ * \brief Get the screen resolution of a specific screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreenResolution(struct weston_layout_screen *iviscrn,
+ uint32_t *pWidth,
+ uint32_t *pHeight);
+
+/**
+ * \brief register for notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceAddNotification(struct weston_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceRemoveNotification(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Create a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+struct weston_layout_surface *
+weston_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface);
+
+/**
+ * \brief initialize weston_layout_surface dest/source width and height
+ */
+void
+weston_layout_surfaceConfigure(struct weston_layout_surface *ivisurf,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Remove a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceRemove(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Set from which kind of devices the surface can accept input events.
+ * By default, a surface accept input events from all kind of devices (keyboards, pointer, ...)
+ * By calling this function, you can adjust surface preferences. Note that this function only
+ * adjust the acceptance for the specified devices. Non specified are keept untouched.
+ *
+ * Typicall use case for this function is when dealing with pointer or touch events.
+ * Those are normally dispatched to the first visible surface below the coordinate.
+ * If you want a different behavior (i.e. forward events to an other surface below the coordinate,
+ * you can set all above surfaces to refuse input events)
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_UpdateInputEventAcceptanceOn(struct weston_layout_surface *ivisurf,
+ uint32_t devices,
+ uint32_t acceptance);
+
+/**
+ * \brief Get the layer properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getPropertiesOfLayer(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties *pLayerProperties);
+
+/**
+ * \brief Get the number of hardware layers of a screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ uint32_t *pNumberOfHardwareLayers);
+
+/**
+ * \brief Get the screens
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreens(uint32_t *pLength, weston_layout_screen_ptr **ppArray);
+
+/**
+ * \brief Get the screens under the given layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreensUnderLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_screen_ptr **ppArray);
+
+/**
+ * \brief Get all Layers which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayers(uint32_t *pLength, weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Layers of the given screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayersOnScreen(struct weston_layout_screen *iviscrn,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Layers under the given surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayersUnderSurface(struct weston_layout_surface *ivisurf,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getSurfaces(uint32_t *pLength, weston_layout_surface_ptr **ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered to a given layer and are managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getSurfacesOnLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_surface_ptr **ppArray);
+
+/**
+ * \brief Create a layer which should be managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+struct weston_layout_layer *
+weston_layout_layerCreateWithDimension(uint32_t id_layer,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Removes a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemove(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Get the current type of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetType(struct weston_layout_layer *ivilayer,
+ uint32_t *pLayerType);
+
+/**
+ * \brief Set the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetOpacity(struct weston_layout_layer *ivilayer, float opacity);
+
+/**
+ * \brief Get the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetOpacity(struct weston_layout_layer *ivilayer, float *pOpacity);
+
+/**
+ * \brief Set the area of a layer which should be used for the rendering.
+ * Only this part will be visible.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetSourceRectangle(struct weston_layout_layer *ivilayer,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Set the destination area on the display for a layer.
+ * The layer will be scaled and positioned to this rectangle for rendering
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetDestinationRectangle(struct weston_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetPosition(struct weston_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetPosition(struct weston_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t orientation);
+
+/**
+ * \brief Gets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t *pOrientation);
+
+/**
+ * \brief Sets the color value which defines the transparency value.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetChromaKey(struct weston_layout_layer *ivilayer,
+ uint32_t* pColor);
+
+/**
+ * \brief Sets render order of surfaces within one layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetRenderOrder(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface **pSurface,
+ uint32_t number);
+
+/**
+ * \brief Get the capabilities of a layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetCapabilities(struct weston_layout_layer *ivilayer,
+ uint32_t *pCapabilities);
+
+/**
+ * \brief Get the possible capabilities of a layertype
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerTypeGetCapabilities(uint32_t layerType,
+ uint32_t *pCapabilities);
+
+/**
+ * \brief Create the logical surface, which has no native buffer associated
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceInitialize(struct weston_layout_surface **pSurface);
+
+/**
+ * \brief Set the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetOpacity(struct weston_layout_surface *ivisurf,
+ float opacity);
+
+/**
+ * \brief Get the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetOpacity(struct weston_layout_surface *ivisurf,
+ float *pOpacity);
+
+/**
+ * \brief Set the keyboard focus on a certain surface
+ * To receive keyboard events, 2 conditions must be fulfilled:
+ * 1- The surface must accept events from keyboard. See ilm_UpdateInputEventAcceptanceOn
+ * 2- The keyboard focus must be set on that surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_SetKeyboardFocusOn(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Get the indentifier of the surface which hold the keyboard focus
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_GetKeyboardFocusSurfaceId(struct weston_layout_surface **pSurfaceId);
+
+/**
+ * \brief Set the destination area of a surface within a layer for rendering.
+ * The surface will be scaled to this rectangle for rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetDestinationRectangle(struct weston_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension);
+
+/**
+ * \brief Sets the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Get the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t orientation);
+
+/**
+ * \brief Gets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t *pOrientation);
+
+/**
+ * \brief Gets the pixelformat of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetPixelformat(struct weston_layout_layer *ivisurf,
+ uint32_t *pPixelformat);
+
+/**
+ * \brief Sets the color value which defines the transparency value of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetChromaKey(struct weston_layout_surface *ivisurf,
+ uint32_t* pColor);
+
+/**
+ * \brief Add a layer to a screen which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_screenAddLayer(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer *addlayer);
+
+/**
+ * \brief Sets render order of layers on a display
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_screenSetRenderOrder(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer **pLayer,
+ const uint32_t number);
+
+/**
+ * \brief Take a screenshot from the current displayed layer scene.
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeScreenshot(struct weston_layout_screen *iviscrn,
+ const char *filename);
+
+/**
+ * \brief Take a screenshot of a certain layer
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeLayerScreenshot(const char *filename,
+ struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Take a screenshot of a certain surface
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeSurfaceScreenshot(const char *filename,
+ struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Enable or disable a rendering optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_SetOptimizationMode(uint32_t id, uint32_t mode);
+
+/**
+ * \brief Get the current enablement for an optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_GetOptimizationMode(uint32_t id, uint32_t *pMode);
+
+/**
+ * \brief register for notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerAddNotification(struct weston_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemoveNotification(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Get the surface properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getPropertiesOfSurface(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties *pSurfaceProperties);
+
+/**
+ * \brief Add a surface to a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerAddSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *addsurf);
+
+/**
+ * \brief Removes a surface from a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemoveSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *remsurf);
+
+/**
+ * \brief Set the area of a surface which should be used for the rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetSourceRectangle(struct weston_layout_surface *ivisurf,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Commit all changes and execute all enqueued commands since last commit.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_commitChanges(void);
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _WESTON_LAYOUT_H_ */
--
1.8.3.1
Nobuhiko Tanibata
2014-03-15 05:56:34 UTC
Permalink
API set of controlling properties of surface and layer which groups
surfaces. An unique ID whose type is integer is required to create
surface and layer. With the unique ID, surface and layer are identified
to control them. The API set consists of APIs to control properties of
surface and layers about followings,

- visibility.
- opacity.
- clipping (x,y,width,height).
- position and size of it to be displayed.
- orientation per 90 degree.
- add or remove surfaces to a layer.
- order of surfaces/layers in layer/screen to be displayed.
- commit to apply property changes.
- notifications of property change.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- move this patch in front of ivi-shell patch to be compiled successfully.
- unsupport weston_layout_takeSurfaceScreenshot because implementation needs to
be discussed more. It is pending.
- support inherit propoerties of id_surface when client attaches another
wl_surface with id_surface after destroying ivi_surface once.

Makefile.am | 1 +
configure.ac | 15 +-
ivi-shell/Makefile.am | 30 +
ivi-shell/weston-layout.c | 2631 +++++++++++++++++++++++++++++++++++++++++++++
ivi-shell/weston-layout.h | 934 ++++++++++++++++
5 files changed, 3610 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/Makefile.am
create mode 100644 ivi-shell/weston-layout.c
create mode 100644 ivi-shell/weston-layout.h

diff --git a/Makefile.am b/Makefile.am
index f22c542..1bc35e2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,6 +11,7 @@ SUBDIRS = \
src \
$(xwayland_subdir) \
desktop-shell \
+ ivi-shell \
clients \
data \
protocol \
diff --git a/configure.ac b/configure.ac
index cce1850..4c0a90f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -409,6 +409,16 @@ if test "x$enable_dbus" != "xno"; then
fi
AM_CONDITIONAL(ENABLE_DBUS, test "x$enable_dbus" = "xyes")

+# ivi-shell support
+AC_ARG_ENABLE(ivi-shell,
+ AS_HELP_STRING([--disable-ivi-shell],
+ [do not build ivi-shell server plugin and client]),,
+ enable_ivi_shell=yes)
+AM_CONDITIONAL(ENABLE_IVI_SHELL, test "x$enable_ivi_shell" = "xyes")
+if test x$enable_ivi_shell = xyes; then
+ PKG_CHECK_MODULES(IVI_SHELL, [cairo])
+fi
+
AC_ARG_ENABLE(wcap-tools, [ --disable-wcap-tools],, enable_wcap_tools=yes)
AM_CONDITIONAL(BUILD_WCAP_TOOLS, test x$enable_wcap_tools = xyes)
if test x$enable_wcap_tools = xyes; then
@@ -505,7 +515,8 @@ AC_CONFIG_FILES([Makefile
data/Makefile
protocol/Makefile
man/Makefile
- tests/Makefile])
+ tests/Makefile
+ ivi-shell/Makefile])
AC_OUTPUT

AC_MSG_RESULT([
@@ -519,6 +530,8 @@ AC_MSG_RESULT([
XWayland ${enable_xwayland}
dbus ${enable_dbus}

+ ivi-shell ${enable_ivi_shell}
+
Build wcap utility ${enable_wcap_tools}

weston-launch utility ${enable_weston_launch}
diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
new file mode 100644
index 0000000..4d54c2d
--- /dev/null
+++ b/ivi-shell/Makefile.am
@@ -0,0 +1,30 @@
+moduledir = $(libdir)/weston
+
+module_LTLIBRARIES = \
+ $(libweston_layout)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/shared \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src \
+ -DDATADIR='"$(datadir)"' \
+ -DMODULEDIR='"$(moduledir)"' \
+ -DLIBEXECDIR='"$(libexecdir)"' \
+ -DIN_WESTON
+
+westonincludedir = $(includedir)/weston
+westoninclude_HEADERS =
+
+if ENABLE_IVI_SHELL
+westoninclude_HEADERS += \
+ weston-layout.h
+
+libweston_layout = libweston-layout.la
+libweston_layout_la_LDFLAGS = -avoid-version
+libweston_layout_la_LIBADD = $(IVI_SHELL_LIBS) ../shared/libshared.la
+libweston_layout_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
+libweston_layout_la_SOURCES = \
+ weston-layout.c \
+ weston-layout.h
+
+endif
diff --git a/ivi-shell/weston-layout.c b/ivi-shell/weston-layout.c
new file mode 100644
index 0000000..9cb571a
--- /dev/null
+++ b/ivi-shell/weston-layout.c
@@ -0,0 +1,2631 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * Implementation of weston-layout library. The actual view on screen is
+ * not updated till calling weston_layout_commitChanges. A overview from
+ * calling API for updating properties of surfaces/layer to asking compositor
+ * to compose them by using weston_compositor_schedule_repaint,
+ * 0/ initialize this library by weston_layout_initWithCompositor
+ * with (struct weston_compositor *ec) from ivi-shell.
+ * 1/ When a API for updating properties of surface/layer, it updates
+ * pending prop of weston_layout_surface/layer/screen which are structure to
+ * store properties.
+ * 2/ Before calling commitChanges, in case of calling a API to get a property,
+ * return current property, not pending property.
+ * 3/ At the timing of calling weston_layout_commitChanges, pending properties
+ * are applied
+ * to properties.
+ * 4/ According properties, set transformation by using weston_matrix and
+ * weston_view per surfaces and layers in while loop.
+ * 5/ Set damage and trigger transform by using weston_view_geometry_dirty and
+ * weston_view_geometry_dirty.
+ * 6/ Notify update of properties.
+ * 7/ Trigger composition by weston_compositor_schedule_repaint.
+ *
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <cairo.h>
+
+#include "compositor.h"
+#include "weston-layout.h"
+
+enum weston_layout_surface_orientation {
+ WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES = 0,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES = 1,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES = 2,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES = 3,
+};
+
+enum weston_layout_surface_pixelformat {
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_R_8 = 0,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGB_888 = 1,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888 = 2,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGB_565 = 3,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_5551 = 4,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_6661 = 5,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_4444 = 6,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_UNKNOWN = 7,
+};
+
+struct link_layer {
+ struct weston_layout_layer *ivilayer;
+ struct wl_list link;
+};
+
+struct link_screen {
+ struct weston_layout_screen *iviscrn;
+ struct wl_list link;
+};
+
+struct link_layerPropertyNotification {
+ layerPropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfacePropertyNotification {
+ surfacePropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerCreateNotification {
+ layerCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerRemoveNotification {
+ layerRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceCreateNotification {
+ surfaceCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceRemoveNotification {
+ surfaceRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceConfigureNotification {
+ surfaceConfigureNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct weston_layout;
+
+struct weston_layout_surface {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_layer;
+ uint32_t update_count;
+ uint32_t id_surface;
+
+ struct weston_layout *layout;
+ struct weston_surface *surface;
+ struct weston_view *view;
+
+ uint32_t buffer_width;
+ uint32_t buffer_height;
+
+ struct wl_listener surface_destroy_listener;
+ struct weston_transform surface_rotation;
+ struct weston_transform layer_rotation;
+ struct weston_transform surface_pos;
+ struct weston_transform layer_pos;
+ struct weston_transform scaling;
+ struct weston_layout_SurfaceProperties prop;
+ int32_t pixelformat;
+ uint32_t event_mask;
+
+ struct {
+ struct weston_layout_SurfaceProperties prop;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list link;
+ struct wl_list list_layer;
+ } order;
+};
+
+struct weston_layout_layer {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_screen;
+ uint32_t id_layer;
+
+ struct weston_layout *layout;
+ struct weston_layer el;
+
+ struct weston_layout_LayerProperties prop;
+ uint32_t event_mask;
+
+ struct {
+ struct weston_layout_LayerProperties prop;
+ struct wl_list list_surface;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_surface;
+ struct wl_list link;
+ } order;
+};
+
+struct weston_layout_screen {
+ struct wl_list link;
+ uint32_t id_screen;
+
+ struct weston_layout *layout;
+ struct weston_output *output;
+
+ uint32_t event_mask;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } order;
+};
+
+struct weston_layout {
+ struct weston_compositor *compositor;
+
+ struct wl_list list_surface;
+ struct wl_list list_layer;
+ struct wl_list list_screen;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ } layer_notification;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ struct wl_list list_configure;
+ } surface_notification;
+
+ /* to enable displaying cursor*/
+ int32_t is_cursor_enabled;
+};
+
+struct weston_layout ivilayout = {0};
+
+static struct weston_layout *
+get_instance(void)
+{
+ return &ivilayout;
+}
+
+/**
+ * Internal API to add/remove a surface from layer.
+ */
+static void
+add_ordersurface_to_layer(struct weston_layout_surface *ivisurf,
+ struct weston_layout_layer *ivilayer)
+{
+ struct link_layer *link_layer = NULL;
+
+ link_layer = malloc(sizeof *link_layer);
+ if (link_layer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_layer->ivilayer = ivilayer;
+ wl_list_init(&link_layer->link);
+ wl_list_insert(&ivisurf->list_layer, &link_layer->link);
+}
+
+static void
+remove_ordersurface_from_layer(struct weston_layout_surface *ivisurf)
+{
+ struct link_layer *link_layer = NULL;
+ struct link_layer *next = NULL;
+
+ wl_list_for_each_safe(link_layer, next, &ivisurf->list_layer, link) {
+ if (!wl_list_empty(&link_layer->link)) {
+ wl_list_remove(&link_layer->link);
+ }
+ free(link_layer);
+ }
+ wl_list_init(&ivisurf->list_layer);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static void
+add_orderlayer_to_screen(struct weston_layout_layer *ivilayer,
+ struct weston_layout_screen *iviscrn)
+{
+ struct link_screen *link_scrn = NULL;
+
+ link_scrn = malloc(sizeof *link_scrn);
+ if (link_scrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_scrn->iviscrn = iviscrn;
+ wl_list_init(&link_scrn->link);
+ wl_list_insert(&ivilayer->list_screen, &link_scrn->link);
+}
+
+static void
+remove_orderlayer_from_screen(struct weston_layout_layer *ivilayer)
+{
+ struct link_screen *link_scrn = NULL;
+ struct link_screen *next = NULL;
+
+ wl_list_for_each_safe(link_scrn, next, &ivilayer->list_screen, link) {
+ if (!wl_list_empty(&link_scrn->link)) {
+ wl_list_remove(&link_scrn->link);
+ }
+ free(link_scrn);
+ }
+ wl_list_init(&ivilayer->list_screen);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static struct weston_layout_surface *
+get_surface(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct weston_layout_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+static struct weston_layout_layer *
+get_layer(struct wl_list *list_layer, uint32_t id_layer)
+{
+ struct weston_layout_layer *ivilayer;
+
+ wl_list_for_each(ivilayer, list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Called at destruction of ivi_surface
+ */
+static void
+westonsurface_destroy_from_ivisurface(struct wl_listener *listener, void *data)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+
+ ivisurf = container_of(listener, struct weston_layout_surface,
+ surface_destroy_listener);
+ ivisurf->surface = NULL;
+ ivisurf->view = NULL;
+}
+
+/**
+ * Internal API to check layer/surface already added in layer/screen.
+ * Called by weston_layout_layerAddSurface/weston_layout_screenAddLayer
+ */
+static int
+is_surface_in_layer(struct weston_layout_surface *ivisurf,
+ struct weston_layout_layer *ivilayer)
+{
+ struct weston_layout_surface *surf = NULL;
+
+ wl_list_for_each(surf, &ivilayer->pending.list_surface, pending.link) {
+ if (surf->id_surface == ivisurf->id_surface) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+is_layer_in_screen(struct weston_layout_layer *ivilayer,
+ struct weston_layout_screen *iviscrn)
+{
+ struct weston_layout_layer *layer = NULL;
+
+ wl_list_for_each(layer, &iviscrn->pending.list_layer, pending.link) {
+ if (layer->id_layer == ivilayer->id_layer) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Internal API to initialize screens found from output_list of weston_compositor.
+ * Called by weston_layout_initWithCompositor.
+ */
+static void
+create_screen(struct weston_compositor *ec)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_output *output = NULL;
+ int32_t count = 0;
+
+ wl_list_for_each(output, &ec->output_list, link) {
+ iviscrn = calloc(1, sizeof *iviscrn);
+ if (iviscrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ continue;
+ }
+
+ wl_list_init(&iviscrn->link);
+ iviscrn->layout = layout;
+
+ iviscrn->id_screen = count;
+ count++;
+
+ iviscrn->output = output;
+ iviscrn->event_mask = 0;
+
+ wl_list_init(&iviscrn->pending.list_layer);
+ wl_list_init(&iviscrn->pending.link);
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_init(&iviscrn->order.link);
+
+ wl_list_insert(&layout->list_screen, &iviscrn->link);
+ }
+}
+
+/**
+ * Internal APIs to initialize properties of surface/layer when they are created.
+ */
+static void
+init_layerProperties(struct weston_layout_LayerProperties *prop,
+ int32_t width, int32_t height)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+ prop->destWidth = width;
+ prop->destHeight = height;
+}
+
+static void
+init_surfaceProperties(struct weston_layout_SurfaceProperties *prop)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+}
+
+/**
+ * Internal APIs to be called from weston_layout_commitChanges.
+ */
+static void
+update_opacity(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ double layer_alpha = wl_fixed_to_double(ivilayer->prop.opacity);
+ double surf_alpha = wl_fixed_to_double(ivisurf->prop.opacity);
+
+ if ((ivilayer->event_mask & IVI_NOTIFICATION_OPACITY) ||
+ (ivisurf->event_mask & IVI_NOTIFICATION_OPACITY)) {
+ if (ivisurf->view == NULL) {
+ return;
+ }
+ ivisurf->view->alpha = layer_alpha * surf_alpha;
+ }
+}
+
+static void
+update_surface_orientation(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->surface_rotation.matrix;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ if (view == NULL) {
+ return;
+ }
+
+ if ((ivilayer->prop.destWidth == 0) ||
+ (ivilayer->prop.destHeight == 0)) {
+ return;
+ }
+ width = (float)ivilayer->prop.destWidth;
+ height = (float)ivilayer->prop.destHeight;
+
+ switch (ivisurf->prop.orientation) {
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->surface_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_layer_orientation(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_surface *es = ivisurf->surface;
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->layer_rotation.matrix;
+ struct weston_output *output = NULL;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ if (es == NULL || view == NULL) {
+ return;
+ }
+
+ output = es->output;
+ if (output == NULL) {
+ return;
+ }
+ if ((output->width == 0) || (output->height == 0)) {
+ return;
+ }
+ width = (float)output->width;
+ height = (float)output->height;
+
+ switch (ivilayer->prop.orientation) {
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->layer_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->layer_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_surface_position(struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ float tx = (float)ivisurf->prop.destX;
+ float ty = (float)ivisurf->prop.destY;
+ struct weston_matrix *matrix = &ivisurf->surface_pos.matrix;
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->surface_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+
+#if 0
+ /* disable zoom animation */
+ weston_zoom_run(es, 0.0, 1.0, NULL, NULL);
+#endif
+
+}
+
+static void
+update_layer_position(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->layer_pos.matrix;
+ float tx = (float)ivilayer->prop.destX;
+ float ty = (float)ivilayer->prop.destY;
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->layer_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(
+ &view->geometry.transformation_list,
+ &ivisurf->layer_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_scale(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->scaling.matrix;
+ float sx = 0.0f;
+ float sy = 0.0f;
+ float lw = 0.0f;
+ float sw = 0.0f;
+ float lh = 0.0f;
+ float sh = 0.0f;
+
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->prop.sourceWidth == 0 && ivisurf->prop.sourceHeight == 0) {
+ ivisurf->prop.sourceWidth = ivisurf->buffer_width;
+ ivisurf->prop.sourceHeight = ivisurf->buffer_height;
+
+ if (ivisurf->prop.destWidth == 0 && ivisurf->prop.destHeight == 0) {
+ ivisurf->prop.destWidth = ivisurf->buffer_width;
+ ivisurf->prop.destHeight = ivisurf->buffer_height;
+ }
+ }
+
+ lw = ((float)ivilayer->prop.destWidth / ivilayer->prop.sourceWidth );
+ sw = ((float)ivisurf->prop.destWidth / ivisurf->prop.sourceWidth );
+ lh = ((float)ivilayer->prop.destHeight / ivilayer->prop.sourceHeight);
+ sh = ((float)ivisurf->prop.destHeight / ivisurf->prop.sourceHeight );
+ sx = sw * lw;
+ sy = sh * lh;
+
+ wl_list_remove(&ivisurf->scaling.link);
+ weston_matrix_init(matrix);
+ weston_matrix_scale(matrix, sx, sy, 1.0f);
+
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->scaling.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_prop(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ if (ivilayer->event_mask | ivisurf->event_mask) {
+ update_opacity(ivilayer, ivisurf);
+ update_layer_orientation(ivilayer, ivisurf);
+ update_layer_position(ivilayer, ivisurf);
+ update_surface_position(ivisurf);
+ update_surface_orientation(ivilayer, ivisurf);
+ update_scale(ivilayer, ivisurf);
+
+ ivisurf->update_count++;
+
+ if (ivisurf->view != NULL) {
+ weston_view_geometry_dirty(ivisurf->view);
+ }
+
+ if (ivisurf->surface != NULL) {
+ weston_surface_damage(ivisurf->surface);
+ }
+ }
+}
+
+static void
+commit_changes(struct weston_layout *layout)
+{
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ update_prop(ivilayer, ivisurf);
+ }
+ }
+ }
+}
+
+static void
+commit_list_surface(struct weston_layout *layout)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ ivisurf->prop = ivisurf->pending.prop;
+ }
+}
+
+static void
+commit_list_layer(struct weston_layout *layout)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ ivilayer->prop = ivilayer->pending.prop;
+
+ if (!(ivilayer->event_mask &
+ (IVI_NOTIFICATION_ADD | IVI_NOTIFICATION_REMOVE)) ) {
+ continue;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->order.list_surface, order.link) {
+ remove_ordersurface_from_layer(ivisurf);
+
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_for_each(ivisurf, &ivilayer->pending.list_surface,
+ pending.link) {
+ if(!wl_list_empty(&ivisurf->order.link)){
+ wl_list_remove(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_insert(&ivilayer->order.list_surface,
+ &ivisurf->order.link);
+ add_ordersurface_to_layer(ivisurf, ivilayer);
+ }
+ }
+}
+
+static void
+commit_list_screen(struct weston_layout *layout)
+{
+ struct weston_compositor *ec = layout->compositor;
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_layer *next = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ if (iviscrn->event_mask & IVI_NOTIFICATION_ADD) {
+ wl_list_for_each_safe(ivilayer, next,
+ &iviscrn->order.list_layer, order.link) {
+ remove_orderlayer_from_screen(ivilayer);
+
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.link);
+ }
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_for_each(ivilayer, &iviscrn->pending.list_layer,
+ pending.link) {
+ wl_list_insert(&iviscrn->order.list_layer,
+ &ivilayer->order.link);
+ add_orderlayer_to_screen(ivilayer, iviscrn);
+ }
+ iviscrn->event_mask = 0;
+ }
+
+ /* For rendering */
+ wl_list_init(&ec->layer_list);
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+ if (ivilayer->prop.visibility == 0) {
+ continue;
+ }
+
+ wl_list_insert(&ec->layer_list, &ivilayer->el.link);
+ wl_list_init(&ivilayer->el.view_list);
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ if (ivisurf->prop.visibility == 0) {
+ continue;
+ }
+
+ if (ivisurf->surface == NULL || ivisurf->view == NULL) {
+ continue;
+ }
+
+ wl_list_insert(&ivilayer->el.view_list,
+ &ivisurf->view->layer_link);
+ ivisurf->surface->output = iviscrn->output;
+ }
+ }
+
+ /*Add cursor layer if cursor is configured.*/
+ if (layout->is_cursor_enabled) {
+ wl_list_insert(&ec->layer_list, &ec->cursor_layer.link);
+ }
+
+ break;
+ }
+}
+
+static void
+send_surface_prop(struct weston_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivisurf->list_notification, link) {
+ notification->callback(ivisurf, &ivisurf->prop,
+ ivisurf->event_mask,
+ notification->userdata);
+ }
+
+ ivisurf->event_mask = 0;
+}
+
+static void
+send_layer_prop(struct weston_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivilayer->list_notification, link) {
+ notification->callback(ivilayer, &ivilayer->prop,
+ ivilayer->event_mask,
+ notification->userdata);
+ }
+
+ ivilayer->event_mask = 0;
+}
+
+static void
+send_prop(struct weston_layout *layout)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ send_layer_prop(ivilayer);
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ send_surface_prop(ivisurf);
+ }
+}
+
+/**
+ * Exported APIs of weston-layout library are implemented from here.
+ * Brief of APIs is described in weston-layout.h.
+ */
+WL_EXPORT struct weston_view *
+weston_layout_get_weston_view(struct weston_layout_surface *surface)
+{
+ return (surface != NULL) ? surface->view : NULL;
+}
+
+WL_EXPORT void
+weston_layout_initWithCompositor(struct weston_compositor *ec)
+{
+ struct weston_layout *layout = get_instance();
+
+ layout->compositor = ec;
+
+ wl_list_init(&layout->list_surface);
+ wl_list_init(&layout->list_layer);
+ wl_list_init(&layout->list_screen);
+
+ wl_list_init(&layout->layer_notification.list_create);
+ wl_list_init(&layout->layer_notification.list_remove);
+
+ wl_list_init(&layout->surface_notification.list_create);
+ wl_list_init(&layout->surface_notification.list_remove);
+ wl_list_init(&layout->surface_notification.list_configure);
+
+ create_screen(ec);
+
+ struct weston_config *config = weston_config_parse("weston.ini");
+ struct weston_config_section *s =
+ weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ /*A cursor is configured if weston.ini has keys.*/
+ char* cursor_theme = NULL;
+ weston_config_section_get_string(s, "cursor-theme", &cursor_theme, NULL);
+ layout->is_cursor_enabled = (NULL != cursor_theme);
+ free(cursor_theme);
+ weston_config_destroy(config);
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationCreateLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationRemoveLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationCreateSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceConfigureNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationConfigureSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_configure, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT uint32_t
+weston_layout_getIdOfSurface(struct weston_layout_surface *ivisurf)
+{
+ return ivisurf->id_surface;
+}
+
+WL_EXPORT uint32_t
+weston_layout_getIdOfLayer(struct weston_layout_layer *ivilayer)
+{
+ return ivilayer->id_layer;
+}
+
+WL_EXPORT struct weston_layout_layer *
+weston_layout_getLayerFromId(uint32_t id_layer)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct weston_layout_surface *
+weston_layout_getSurfaceFromId(uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct weston_layout_screen *
+weston_layout_getScreenFromId(uint32_t id_screen)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ (void)id_screen;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+//FIXME : select iviscrn from list_screen by id_screen
+ return iviscrn;
+ break;
+ }
+
+ return NULL;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreenResolution(struct weston_layout_screen *iviscrn,
+ uint32_t *pWidth, uint32_t *pHeight)
+{
+ struct weston_output *output = NULL;
+
+ if (pWidth == NULL || pHeight == NULL) {
+ weston_log("weston_layout_getScreenResolution: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ *pWidth = output->current_mode->width;
+ *pHeight = output->current_mode->height;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceAddNotification(struct weston_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ if (ivisurf == NULL || callback == NULL) {
+ weston_log("weston_layout_surfaceAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivisurf->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceRemoveNotification(struct weston_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+ struct link_surfacePropertyNotification *next = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivisurf->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ }
+ wl_list_init(&ivisurf->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT struct weston_layout_surface*
+weston_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (wl_surface == NULL) {
+ weston_log("weston_layout_surfaceCreate: invalid argument\n");
+ return NULL;
+ }
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf != NULL) {
+ if (ivisurf->surface != NULL) {
+ weston_log("id_surface(%d) is already created\n", id_surface);
+ return NULL;
+ } else {
+ /* if ivisurf->surface exist, wl_surface is tied to id_surface again */
+ /* This means client destroys ivi_surface once, and then tries to tie
+ the id_surface to new wl_surface again. The property of id_surface can
+ be inherited.
+ */
+ weston_layout_surfaceSetNativeContent(
+ wl_surface, wl_surface->width, wl_surface->height, id_surface);
+ return ivisurf;
+ }
+ }
+
+ ivisurf = calloc(1, sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivisurf->link);
+ wl_list_init(&ivisurf->list_notification);
+ wl_list_init(&ivisurf->list_layer);
+ ivisurf->id_surface = id_surface;
+ ivisurf->layout = layout;
+
+ ivisurf->surface = wl_surface;
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(wl_surface->resource,
+ &ivisurf->surface_destroy_listener);
+
+ ivisurf->view = weston_view_create(wl_surface);
+ if (ivisurf->view == NULL) {
+ weston_log("fails to allocate memory\n");
+ }
+
+ ivisurf->buffer_width = 0;
+ ivisurf->buffer_height = 0;
+
+ wl_list_init(&ivisurf->surface_rotation.link);
+ wl_list_init(&ivisurf->layer_rotation.link);
+ wl_list_init(&ivisurf->surface_pos.link);
+ wl_list_init(&ivisurf->layer_pos.link);
+ wl_list_init(&ivisurf->scaling.link);
+
+ init_surfaceProperties(&ivisurf->prop);
+ ivisurf->pixelformat = WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+ ivisurf->event_mask = 0;
+
+ ivisurf->pending.prop = ivisurf->prop;
+ wl_list_init(&ivisurf->pending.link);
+
+ wl_list_init(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.list_layer);
+
+ wl_list_insert(&layout->list_surface, &ivisurf->link);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return ivisurf;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetNativeContent(struct weston_surface *surface,
+ uint32_t width,
+ uint32_t height,
+ uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf == NULL) {
+ weston_log("layout surface is not found\n");
+ return -1;
+ }
+
+ if (ivisurf->surface != NULL) {
+ if (surface != NULL) {
+ weston_log("id_surface(%d) is already set the native content\n",
+ id_surface);
+ return -1;
+ }
+
+ wl_list_remove(&ivisurf->surface_destroy_listener.link);
+ weston_view_destroy(ivisurf->view);
+
+ ivisurf->surface = NULL;
+ ivisurf->view = NULL;
+ }
+
+ if (surface == NULL)
+ return 0;
+
+ ivisurf->surface = surface;
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(surface->resource,
+ &ivisurf->surface_destroy_listener);
+ ivisurf->view = weston_view_create(surface);
+ if (ivisurf->view == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ ivisurf->buffer_width = width;
+ ivisurf->buffer_height = height;
+ ivisurf->pixelformat = WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return 0;
+}
+
+WL_EXPORT void
+weston_layout_surfaceConfigure(struct weston_layout_surface *ivisurf,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf->buffer_width = width;
+ ivisurf->buffer_height = height;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_configure, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceRemove(struct weston_layout_surface *ivisurf)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceRemove: invalid argument\n");
+ return -1;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+ if (!wl_list_empty(&ivisurf->link)) {
+ wl_list_remove(&ivisurf->link);
+ }
+ remove_ordersurface_from_layer(ivisurf);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ free(ivisurf);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_UpdateInputEventAcceptanceOn(struct weston_layout_surface *ivisurf,
+ uint32_t devices, uint32_t acceptance)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)devices;
+ (void)acceptance;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceInitialize(struct weston_layout_surface **pSurfaceId)
+{
+ /* not supported */
+ (void)pSurfaceId;
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getPropertiesOfLayer(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties *pLayerProperties)
+{
+ if (ivilayer == NULL || pLayerProperties == NULL) {
+ weston_log("weston_layout_getPropertiesOfLayer: invalid argument\n");
+ return -1;
+ }
+
+ *pLayerProperties = ivilayer->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ uint32_t *pNumberOfHardwareLayers)
+{
+ /* not supported */
+ (void)id_screen;
+ (void)pNumberOfHardwareLayers;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreens(uint32_t *pLength, weston_layout_screen_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getScreens: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_screen_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ (*ppArray)[n++] = iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreensUnderLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_screen_ptr **ppArray)
+{
+ struct link_screen *link_scrn = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getScreensUnderLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_screen_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_scrn, &ivilayer->list_screen, link) {
+ (*ppArray)[n++] = link_scrn->iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayers(uint32_t *pLength, weston_layout_layer_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayersOnScreen(struct weston_layout_screen *iviscrn,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (iviscrn == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayersOnScreen: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&iviscrn->order.list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayersUnderSurface(struct weston_layout_surface *ivisurf,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray)
+{
+ struct link_layer *link_layer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivisurf == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivisurf->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_layer, &ivisurf->list_layer, link) {
+ (*ppArray)[n++] = link_layer->ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getSurfaces(uint32_t *pLength, weston_layout_surface_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getSurfaces: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_surface);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_surface_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getSurfacesOnLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_surface_ptr **ppArray)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getSurfaceIDsOnLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->order.list_surface);
+
+ if (length != 0) {
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_surface_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT struct weston_layout_layer *
+weston_layout_layerCreateWithDimension(uint32_t id_layer,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ struct link_layerCreateNotification *notification = NULL;
+
+ ivilayer = get_layer(&layout->list_layer, id_layer);
+ if (ivilayer != NULL) {
+ weston_log("id_layer is already created\n");
+ return ivilayer;
+ }
+
+ ivilayer = calloc(1, sizeof *ivilayer);
+ if (ivilayer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivilayer->link);
+ wl_list_init(&ivilayer->list_notification);
+ wl_list_init(&ivilayer->list_screen);
+ ivilayer->layout = layout;
+ ivilayer->id_layer = id_layer;
+
+ init_layerProperties(&ivilayer->prop, width, height);
+ ivilayer->event_mask = 0;
+
+ wl_list_init(&ivilayer->pending.list_surface);
+ wl_list_init(&ivilayer->pending.link);
+ ivilayer->pending.prop = ivilayer->prop;
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_init(&ivilayer->order.link);
+
+ wl_list_insert(&layout->list_layer, &ivilayer->link);
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ return ivilayer;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemove(struct weston_layout_layer *ivilayer)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerRemove: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+ if (!wl_list_empty(&ivilayer->link)) {
+ wl_list_remove(&ivilayer->link);
+ }
+ remove_orderlayer_from_screen(ivilayer);
+
+ free(ivilayer);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetType(struct weston_layout_layer *ivilayer,
+ uint32_t *pLayerType)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pLayerType;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t newVisibility)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetVisibility(struct weston_layout_layer *ivilayer, uint32_t *pVisibility)
+{
+ if (ivilayer == NULL || pVisibility == NULL) {
+ weston_log("weston_layout_layerGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivilayer->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetOpacity(struct weston_layout_layer *ivilayer,
+ float opacity)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->opacity = opacity;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetOpacity(struct weston_layout_layer *ivilayer,
+ float *pOpacity)
+{
+ if (ivilayer == NULL || pOpacity == NULL) {
+ weston_log("weston_layout_layerGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivilayer->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetSourceRectangle(struct weston_layout_layer *ivilayer,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetDestinationRectangle(struct weston_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension)
+{
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_layerGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivilayer->prop.destX;
+ pDimension[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_layerSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetPosition(struct weston_layout_layer *ivilayer, int32_t *pPosition)
+{
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("weston_layout_layerGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivilayer->prop.destX;
+ pPosition[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetPosition(struct weston_layout_layer *ivilayer, int32_t *pPosition)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("weston_layout_layerSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t orientation)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->orientation = orientation;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t *pOrientation)
+{
+ if (ivilayer == NULL || pOrientation == NULL) {
+ weston_log("weston_layout_layerGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivilayer->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetChromaKey(struct weston_layout_layer *ivilayer, uint32_t* pColor)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetRenderOrder(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface **pSurface,
+ uint32_t number)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t *id_surface = NULL;
+ uint32_t i = 0;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_init(&ivilayer->pending.list_surface);
+
+ if (pSurface == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_surface = &pSurface[i]->id_surface;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (*id_surface != ivisurf->id_surface) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetCapabilities(struct weston_layout_layer *ivilayer,
+ uint32_t *pCapabilities)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerTypeGetCapabilities(uint32_t layerType,
+ uint32_t *pCapabilities)
+{
+ /* not supported */
+ (void)layerType;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t newVisibility)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t *pVisibility)
+{
+ if (ivisurf == NULL || pVisibility == NULL) {
+ weston_log("weston_layout_surfaceGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivisurf->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetOpacity(struct weston_layout_surface *ivisurf,
+ float opacity)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->opacity = opacity;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetOpacity(struct weston_layout_surface *ivisurf,
+ float *pOpacity)
+{
+ if (ivisurf == NULL || pOpacity == NULL) {
+ weston_log("weston_layout_surfaceGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivisurf->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_SetKeyboardFocusOn(struct weston_layout_surface *ivisurf)
+{
+ /* not supported */
+ (void)ivisurf;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_GetKeyboardFocusSurfaceId(struct weston_layout_surface **pSurfaceId)
+{
+ /* not supported */
+ (void)pSurfaceId;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetDestinationRectangle(struct weston_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetDimension(struct weston_layout_surface *ivisurf, uint32_t *pDimension)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_surfaceSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension)
+{
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_surfaceGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivisurf->prop.destWidth;
+ pDimension[1] = ivisurf->prop.destHeight;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("weston_layout_surfaceSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("weston_layout_surfaceGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivisurf->prop.destX;
+ pPosition[1] = ivisurf->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t orientation)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->orientation = orientation;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t *pOrientation)
+{
+ if (ivisurf == NULL || pOrientation == NULL) {
+ weston_log("weston_layout_surfaceGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivisurf->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetPixelformat(struct weston_layout_layer *ivisurf, uint32_t *pPixelformat)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)pPixelformat;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetChromaKey(struct weston_layout_surface *ivisurf, uint32_t* pColor)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_screenAddLayer(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer *addlayer)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_layer *next = NULL;
+ int is_layer_in_scrn = 0;
+
+ if (iviscrn == NULL || addlayer == NULL) {
+ weston_log("weston_layout_screenAddLayer: invalid argument\n");
+ return -1;
+ }
+
+ is_layer_in_scrn = is_layer_in_screen(addlayer, iviscrn);
+ if (is_layer_in_scrn == 1) {
+ weston_log("weston_layout_screenAddLayer: addlayer is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivilayer, next, &layout->list_layer, link) {
+ if (ivilayer->id_layer == addlayer->id_layer) {
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_screenSetRenderOrder(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer **pLayer,
+ const uint32_t number)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t *id_layer = NULL;
+ uint32_t i = 0;
+
+ if (iviscrn == NULL) {
+ weston_log("weston_layout_screenSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_init(&iviscrn->pending.list_layer);
+
+ if (pLayer == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_layer = &pLayer[i]->id_layer;
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (*id_layer == ivilayer->id_layer) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeScreenshot(struct weston_layout_screen *iviscrn,
+ const char *filename)
+{
+ struct weston_output *output = NULL;
+ cairo_surface_t *cairo_surf = NULL;
+ int32_t i = 0;
+ int32_t width = 0;
+ int32_t height = 0;
+ int32_t stride = 0;
+ uint8_t *readpixs = NULL;
+ uint8_t *writepixs = NULL;
+ uint8_t *d = NULL;
+ uint8_t *s = NULL;
+
+ if (iviscrn == NULL || filename == NULL) {
+ weston_log("weston_layout_takeScreenshot: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ output->disable_planes--;
+
+ width = output->current_mode->width;
+ height = output->current_mode->height;
+ stride = width * (PIXMAN_FORMAT_BPP(output->compositor->read_format) / 8);
+
+ readpixs = malloc(stride * height);
+ if (readpixs == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+ writepixs = malloc(stride * height);
+ if (writepixs == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ output->compositor->renderer->read_pixels(output,
+ output->compositor->read_format, readpixs,
+ 0, 0, width, height);
+
+ s = readpixs;
+ d = writepixs + stride * (height - 1);
+
+ for (i = 0; i < height; i++) {
+ memcpy(d, s, stride);
+ d -= stride;
+ s += stride;
+ }
+
+ cairo_surf = cairo_image_surface_create_for_data(writepixs,
+ CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+ cairo_surface_write_to_png(cairo_surf, filename);
+ cairo_surface_destroy(cairo_surf);
+ free(writepixs);
+ free(readpixs);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeLayerScreenshot(const char *filename, struct weston_layout_layer *ivilayer)
+{
+ /* not supported */
+ (void)filename;
+ (void)ivilayer;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeSurfaceScreenshot(const char *filename,
+ struct weston_layout_surface *ivisurf)
+{
+ weston_log("weston_layout_takeSurfaceScreenshot: "
+ "This function is not supported now\n");
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_SetOptimizationMode(uint32_t id, uint32_t mode)
+{
+ /* not supported */
+ (void)id;
+ (void)mode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_GetOptimizationMode(uint32_t id, uint32_t *pMode)
+{
+ /* not supported */
+ (void)id;
+ (void)pMode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerAddNotification(struct weston_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ if (ivilayer == NULL || callback == NULL) {
+ weston_log("weston_layout_layerAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivilayer->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemoveNotification(struct weston_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+ struct link_layerPropertyNotification *next = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivilayer->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ }
+ wl_list_init(&ivilayer->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getPropertiesOfSurface(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties *pSurfaceProperties)
+{
+ if (ivisurf == NULL || pSurfaceProperties == NULL) {
+ weston_log("weston_layout_getPropertiesOfSurface: invalid argument\n");
+ return -1;
+ }
+
+ *pSurfaceProperties = ivisurf->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerAddSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *addsurf)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+ int is_surf_in_layer = 0;
+
+ if (ivilayer == NULL || addsurf == NULL) {
+ weston_log("weston_layout_layerAddSurface: invalid argument\n");
+ return -1;
+ }
+
+ is_surf_in_layer = is_surface_in_layer(addsurf, ivilayer);
+ if (is_surf_in_layer == 1) {
+ weston_log("weston_layout_layerAddSurface: addsurf is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivisurf, next, &layout->list_surface, link) {
+ if (ivisurf->id_surface == addsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemoveSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *remsurf)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+
+ if (ivilayer == NULL || remsurf == NULL) {
+ weston_log("weston_layout_layerRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->pending.list_surface, pending.link) {
+ if (ivisurf->id_surface == remsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_REMOVE;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetSourceRectangle(struct weston_layout_surface *ivisurf,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_commitChanges(void)
+{
+ struct weston_layout *layout = get_instance();
+
+ commit_list_surface(layout);
+ commit_list_layer(layout);
+ commit_list_screen(layout);
+
+ commit_changes(layout);
+ send_prop(layout);
+ weston_compositor_schedule_repaint(layout->compositor);
+
+ return 0;
+}
diff --git a/ivi-shell/weston-layout.h b/ivi-shell/weston-layout.h
new file mode 100644
index 0000000..2667784
--- /dev/null
+++ b/ivi-shell/weston-layout.h
@@ -0,0 +1,934 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * The weston-layout library supports API set of controlling properties of
+ * surface and layer which groups surfaces. An unique ID whose type is integer
+ * is required to create surface and layer. With the unique ID, surface and
+ * layer are identified to control them. The API set consists of APIs to control
+ * properties of surface and layers about followings,
+ * - visibility.
+ * - opacity.
+ * - clipping (x,y,width,height).
+ * - position and size of it to be displayed.
+ * - orientation per 90 degree.
+ * - add or remove surfaces to a layer.
+ * - order of surfaces/layers in layer/screen to be displayed.
+ * - commit to apply property changes.
+ * - notifications of property change.
+ *
+ * Management of surfaces and layers grouping these surfaces are common way in
+ * In-Vehicle Infotainment system, which integrate several domains in one system.
+ * A layer is allocated to a domain in order to control application surfaces
+ * grouped to the layer all together.
+ */
+
+#ifndef _WESTON_LAYOUT_H_
+#define _WESTON_LAYOUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "compositor.h"
+
+struct weston_layout_SurfaceProperties
+{
+ float opacity;
+ uint32_t sourceX;
+ uint32_t sourceY;
+ uint32_t sourceWidth;
+ uint32_t sourceHeight;
+ uint32_t origSourceWidth;
+ uint32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ uint32_t destWidth;
+ uint32_t destHeight;
+ uint32_t orientation;
+ uint32_t visibility;
+ uint32_t frameCounter;
+ uint32_t drawCounter;
+ uint32_t updateCounter;
+ uint32_t pixelformat;
+ uint32_t nativeSurface;
+ uint32_t inputDevicesAcceptance;
+ uint32_t chromaKeyEnabled;
+ uint32_t chromaKeyRed;
+ uint32_t chromaKeyGreen;
+ uint32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct weston_layout_LayerProperties
+{
+ float opacity;
+ uint32_t sourceX;
+ uint32_t sourceY;
+ uint32_t sourceWidth;
+ uint32_t sourceHeight;
+ uint32_t origSourceWidth;
+ uint32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ uint32_t destWidth;
+ uint32_t destHeight;
+ uint32_t orientation;
+ uint32_t visibility;
+ uint32_t type;
+ uint32_t chromaKeyEnabled;
+ uint32_t chromaKeyRed;
+ uint32_t chromaKeyGreen;
+ uint32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct weston_layout_layer;
+struct weston_layout_surface;
+struct weston_layout_screen;
+
+typedef struct weston_layout_surface* weston_layout_surface_ptr;
+typedef struct weston_layout_layer* weston_layout_layer_ptr;
+typedef struct weston_layout_screen* weston_layout_screen_ptr;
+
+#define IVI_BIT(x) (1 << (x))
+enum weston_layout_notification_mask {
+ IVI_NOTIFICATION_OPACITY = IVI_BIT(1),
+ IVI_NOTIFICATION_SOURCE_RECT = IVI_BIT(2),
+ IVI_NOTIFICATION_DEST_RECT = IVI_BIT(3),
+ IVI_NOTIFICATION_DIMENSION = IVI_BIT(4),
+ IVI_NOTIFICATION_POSITION = IVI_BIT(5),
+ IVI_NOTIFICATION_ORIENTATION = IVI_BIT(6),
+ IVI_NOTIFICATION_VISIBILITY = IVI_BIT(7),
+ IVI_NOTIFICATION_PIXELFORMAT = IVI_BIT(8),
+ IVI_NOTIFICATION_ADD = IVI_BIT(9),
+ IVI_NOTIFICATION_REMOVE = IVI_BIT(10),
+ IVI_NOTIFICATION_ALL = 0xFFFF
+};
+
+typedef void(*layerPropertyNotificationFunc)(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties*,
+ enum weston_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*surfacePropertyNotificationFunc)(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties*,
+ enum weston_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*layerCreateNotificationFunc)(struct weston_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*layerRemoveNotificationFunc)(struct weston_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*surfaceCreateNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceRemoveNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceConfigureNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+/**
+ * \brief to be called by ivi-shell in order to set initail view of
+ * weston_surface.
+ */
+struct weston_view *
+weston_layout_get_weston_view(struct weston_layout_surface *surface);
+
+/**
+ * \brief initialize weston-layout
+ */
+void
+weston_layout_initWithCompositor(struct weston_compositor *ec);
+
+/**
+ * \brief register for notification when layer is created
+ */
+int32_t
+weston_layout_setNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when layer is removed
+ */
+int32_t
+weston_layout_setNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is created
+ */
+int32_t
+weston_layout_setNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is removed
+ */
+int32_t
+weston_layout_setNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is configured
+ */
+int32_t
+weston_layout_setNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief get id of surface from weston_layout_surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+uint32_t
+weston_layout_getIdOfSurface(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief get id of layer from weston_layout_layer
+ *
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+uint32_t
+weston_layout_getIdOfLayer(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief get weston_layout_layer from id of layer
+ *
+ * \return (struct weston_layout_layer *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_layer *
+weston_layout_getLayerFromId(uint32_t id_layer);
+
+/**
+ * \brief get weston_layout_surface from id of surface
+ *
+ * \return (struct weston_layout_surface *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_surface *
+weston_layout_getSurfaceFromId(uint32_t id_surface);
+
+/**
+ * \brief get weston_layout_screen from id of screen
+ *
+ * \return (struct weston_layout_screen *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_screen *
+weston_layout_getScreenFromId(uint32_t id_screen);
+
+/**
+ * \brief Get the screen resolution of a specific screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreenResolution(struct weston_layout_screen *iviscrn,
+ uint32_t *pWidth,
+ uint32_t *pHeight);
+
+/**
+ * \brief register for notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceAddNotification(struct weston_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceRemoveNotification(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Create a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+struct weston_layout_surface *
+weston_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface);
+
+/**
+ * \brief Set the native content of an application to be used as surface content.
+ * If wl_surface is NULL, remove the native content of a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetNativeContent(struct weston_surface *wl_surface,
+ uint32_t width,
+ uint32_t height,
+ uint32_t id_surface);
+
+/**
+ * \brief initialize weston_layout_surface dest/source width and height
+ */
+void
+weston_layout_surfaceConfigure(struct weston_layout_surface *ivisurf,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Remove a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceRemove(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Set from which kind of devices the surface can accept input events.
+ * By default, a surface accept input events from all kind of devices (keyboards, pointer, ...)
+ * By calling this function, you can adjust surface preferences. Note that this function only
+ * adjust the acceptance for the specified devices. Non specified are keept untouched.
+ *
+ * Typicall use case for this function is when dealing with pointer or touch events.
+ * Those are normally dispatched to the first visible surface below the coordinate.
+ * If you want a different behavior (i.e. forward events to an other surface below the coordinate,
+ * you can set all above surfaces to refuse input events)
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_UpdateInputEventAcceptanceOn(struct weston_layout_surface *ivisurf,
+ uint32_t devices,
+ uint32_t acceptance);
+
+/**
+ * \brief Get the layer properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getPropertiesOfLayer(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties *pLayerProperties);
+
+/**
+ * \brief Get the number of hardware layers of a screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ uint32_t *pNumberOfHardwareLayers);
+
+/**
+ * \brief Get the screens
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreens(uint32_t *pLength, weston_layout_screen_ptr **ppArray);
+
+/**
+ * \brief Get the screens under the given layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreensUnderLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_screen_ptr **ppArray);
+
+/**
+ * \brief Get all Layers which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayers(uint32_t *pLength, weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Layers of the given screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayersOnScreen(struct weston_layout_screen *iviscrn,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Layers under the given surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayersUnderSurface(struct weston_layout_surface *ivisurf,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getSurfaces(uint32_t *pLength, weston_layout_surface_ptr **ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered to a given layer and are managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getSurfacesOnLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_surface_ptr **ppArray);
+
+/**
+ * \brief Create a layer which should be managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+struct weston_layout_layer *
+weston_layout_layerCreateWithDimension(uint32_t id_layer,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Removes a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemove(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Get the current type of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetType(struct weston_layout_layer *ivilayer,
+ uint32_t *pLayerType);
+
+/**
+ * \brief Set the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetOpacity(struct weston_layout_layer *ivilayer, float opacity);
+
+/**
+ * \brief Get the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetOpacity(struct weston_layout_layer *ivilayer, float *pOpacity);
+
+/**
+ * \brief Set the area of a layer which should be used for the rendering.
+ * Only this part will be visible.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetSourceRectangle(struct weston_layout_layer *ivilayer,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Set the destination area on the display for a layer.
+ * The layer will be scaled and positioned to this rectangle for rendering
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetDestinationRectangle(struct weston_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetPosition(struct weston_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetPosition(struct weston_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t orientation);
+
+/**
+ * \brief Gets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t *pOrientation);
+
+/**
+ * \brief Sets the color value which defines the transparency value.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetChromaKey(struct weston_layout_layer *ivilayer,
+ uint32_t* pColor);
+
+/**
+ * \brief Sets render order of surfaces within one layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetRenderOrder(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface **pSurface,
+ uint32_t number);
+
+/**
+ * \brief Get the capabilities of a layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetCapabilities(struct weston_layout_layer *ivilayer,
+ uint32_t *pCapabilities);
+
+/**
+ * \brief Get the possible capabilities of a layertype
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerTypeGetCapabilities(uint32_t layerType,
+ uint32_t *pCapabilities);
+
+/**
+ * \brief Create the logical surface, which has no native buffer associated
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceInitialize(struct weston_layout_surface **pSurface);
+
+/**
+ * \brief Set the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetOpacity(struct weston_layout_surface *ivisurf,
+ float opacity);
+
+/**
+ * \brief Get the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetOpacity(struct weston_layout_surface *ivisurf,
+ float *pOpacity);
+
+/**
+ * \brief Set the keyboard focus on a certain surface
+ * To receive keyboard events, 2 conditions must be fulfilled:
+ * 1- The surface must accept events from keyboard. See ilm_UpdateInputEventAcceptanceOn
+ * 2- The keyboard focus must be set on that surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_SetKeyboardFocusOn(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Get the indentifier of the surface which hold the keyboard focus
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_GetKeyboardFocusSurfaceId(struct weston_layout_surface **pSurfaceId);
+
+/**
+ * \brief Set the destination area of a surface within a layer for rendering.
+ * The surface will be scaled to this rectangle for rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetDestinationRectangle(struct weston_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension);
+
+/**
+ * \brief Sets the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Get the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t orientation);
+
+/**
+ * \brief Gets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t *pOrientation);
+
+/**
+ * \brief Gets the pixelformat of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetPixelformat(struct weston_layout_layer *ivisurf,
+ uint32_t *pPixelformat);
+
+/**
+ * \brief Sets the color value which defines the transparency value of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetChromaKey(struct weston_layout_surface *ivisurf,
+ uint32_t* pColor);
+
+/**
+ * \brief Add a layer to a screen which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_screenAddLayer(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer *addlayer);
+
+/**
+ * \brief Sets render order of layers on a display
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_screenSetRenderOrder(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer **pLayer,
+ const uint32_t number);
+
+/**
+ * \brief Take a screenshot from the current displayed layer scene.
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeScreenshot(struct weston_layout_screen *iviscrn,
+ const char *filename);
+
+/**
+ * \brief Take a screenshot of a certain layer
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeLayerScreenshot(const char *filename,
+ struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Take a screenshot of a certain surface
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeSurfaceScreenshot(const char *filename,
+ struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Enable or disable a rendering optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_SetOptimizationMode(uint32_t id, uint32_t mode);
+
+/**
+ * \brief Get the current enablement for an optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_GetOptimizationMode(uint32_t id, uint32_t *pMode);
+
+/**
+ * \brief register for notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerAddNotification(struct weston_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemoveNotification(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Get the surface properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getPropertiesOfSurface(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties *pSurfaceProperties);
+
+/**
+ * \brief Add a surface to a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerAddSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *addsurf);
+
+/**
+ * \brief Removes a surface from a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemoveSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *remsurf);
+
+/**
+ * \brief Set the area of a surface which should be used for the rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetSourceRectangle(struct weston_layout_surface *ivisurf,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Commit all changes and execute all enqueued commands since last commit.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_commitChanges(void);
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _WESTON_LAYOUT_H_ */
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 09:59:48 UTC
Permalink
building ivi-shell.so and libweston-layout.so.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
Makefile.am | 1 +
configure.ac | 15 ++++++++++++++-
ivi-shell/Makefile.am | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 67 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/Makefile.am

diff --git a/Makefile.am b/Makefile.am
index f22c542..1bc35e2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,6 +11,7 @@ SUBDIRS = \
src \
$(xwayland_subdir) \
desktop-shell \
+ ivi-shell \
clients \
data \
protocol \
diff --git a/configure.ac b/configure.ac
index cce1850..4c0a90f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -409,6 +409,16 @@ if test "x$enable_dbus" != "xno"; then
fi
AM_CONDITIONAL(ENABLE_DBUS, test "x$enable_dbus" = "xyes")

+# ivi-shell support
+AC_ARG_ENABLE(ivi-shell,
+ AS_HELP_STRING([--disable-ivi-shell],
+ [do not build ivi-shell server plugin and client]),,
+ enable_ivi_shell=yes)
+AM_CONDITIONAL(ENABLE_IVI_SHELL, test "x$enable_ivi_shell" = "xyes")
+if test x$enable_ivi_shell = xyes; then
+ PKG_CHECK_MODULES(IVI_SHELL, [cairo])
+fi
+
AC_ARG_ENABLE(wcap-tools, [ --disable-wcap-tools],, enable_wcap_tools=yes)
AM_CONDITIONAL(BUILD_WCAP_TOOLS, test x$enable_wcap_tools = xyes)
if test x$enable_wcap_tools = xyes; then
@@ -505,7 +515,8 @@ AC_CONFIG_FILES([Makefile
data/Makefile
protocol/Makefile
man/Makefile
- tests/Makefile])
+ tests/Makefile
+ ivi-shell/Makefile])
AC_OUTPUT

AC_MSG_RESULT([
@@ -519,6 +530,8 @@ AC_MSG_RESULT([
XWayland ${enable_xwayland}
dbus ${enable_dbus}

+ ivi-shell ${enable_ivi_shell}
+
Build wcap utility ${enable_wcap_tools}

weston-launch utility ${enable_weston_launch}
diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
new file mode 100644
index 0000000..d0c0d62
--- /dev/null
+++ b/ivi-shell/Makefile.am
@@ -0,0 +1,52 @@
+moduledir = $(libdir)/weston
+
+module_LTLIBRARIES = \
+ $(libweston_layout) \
+ $(ivi_shell)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/shared \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src \
+ -DDATADIR='"$(datadir)"' \
+ -DMODULEDIR='"$(moduledir)"' \
+ -DLIBEXECDIR='"$(libexecdir)"' \
+ -DIN_WESTON
+
+westonincludedir = $(includedir)/weston
+westoninclude_HEADERS =
+
+if ENABLE_IVI_SHELL
+westoninclude_HEADERS += \
+ ivi-application-client-protocol.h \
+ weston-layout.h
+
+libweston_layout = libweston-layout.la
+libweston_layout_la_LDFLAGS = -avoid-version
+libweston_layout_la_LIBADD = $(IVI_SHELL_LIBS) ../shared/libshared.la
+libweston_layout_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
+libweston_layout_la_SOURCES = \
+ weston-layout.c \
+ weston-layout.h
+
+ivi_shell = ivi-shell.la
+ivi_shell_la_LDFLAGS = -module -avoid-version
+ivi_shell_la_LIBADD = $(COMPOSITOR_LIBS) $(IVI_SHELL_LIBS) ./libweston-layout.la
+ivi_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(IVI_SHELL_CFLAGS)
+ivi_shell_la_SOURCES = \
+ ivi-shell.c \
+ weston-layout.h \
+ ivi-application-protocol.c \
+ ivi-application-server-protocol.h
+
+endif
+
+BUILT_SOURCES = \
+ ivi-application-protocol.c \
+ ivi-application-server-protocol.h \
+ ivi-application-client-protocol.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+wayland_protocoldir = $(top_srcdir)/protocol
+include $(top_srcdir)/wayland-scanner.mk
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 10:00:43 UTC
Permalink
The reference protocol is used between hmi-controller and
hmi-controller-homescreen.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
protocol/ivi-hmi-controller.xml | 105 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 105 insertions(+)
create mode 100644 protocol/ivi-hmi-controller.xml

diff --git a/protocol/ivi-hmi-controller.xml b/protocol/ivi-hmi-controller.xml
new file mode 100644
index 0000000..04e22f4
--- /dev/null
+++ b/protocol/ivi-hmi-controller.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ivi_hmi_controller">
+
+ <copyright>
+ Copyright (C) 2013 DENSO CORPORATION
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ </copyright>
+
+ <interface name="ivi_hmi_controller" version="1">
+ <description summary="set up and control IVI style UI">
+ Currently it's possible to set up surface for background, panel,
+ buttons, and workspace.
+ </description>
+
+ <request name="set_background">
+ <description summary="set surface drawing background by surface ID"/>
+ <arg name="srf_id" type="uint"/>
+ </request>
+
+ <request name="set_panel">
+ <description summary="set surface drawing panel by surface ID"/>
+ <arg name="srf_id" type="uint"/>
+ </request>
+
+ <request name="set_button">
+ <description summary="set surface drawing button by surface ID">
+ Several buttons are regitered on panel by using arg; number.
+ </description>
+ <arg name="srf_id" type="uint"/>
+ <arg name="number" type="uint"/>
+ </request>
+
+ <request name="set_home_button">
+ <description summary="set surface drawing home button by surface ID"/>
+ <arg name="srf_id" type="uint"/>
+ </request>
+
+ <request name="set_workspacebackground">
+ <description summary="set surface drawing background of workspace by surface ID"/>
+ <arg name="srf_id" type="uint"/>
+ </request>
+
+ <request name="add_launchers">
+ <description summary="set a list of surface drawing launchers by a list of surface ID">
+ Per calling this request, a group of launchers are added.
+ </description>
+ <arg name="srf_ids" type="array"/>
+ <arg name="icon_size" type="uint"/>
+ </request>
+
+ <request name="workspace_control">
+ <description summary="start controlling workspace by server">
+ Give seat to the server to be controlled by server side.
+ </description>
+ <arg name="seat" type="object" interface="wl_seat"/>
+ <arg name="serial" type="uint"/>
+ </request>
+
+ <enum name="layout_mode">
+ <entry name="tiling" value="0"/>
+ <entry name="side_by_side" value="1"/>
+ <entry name="full_screen" value="2"/>
+ <entry name="random" value="3" />
+ </enum>
+
+ <request name="switch_mode">
+ <description summary="request mode switch of application layout"/>
+ <arg name="layout_mode" type="uint"/>
+ </request>
+
+ <enum name="home">
+ <entry name="off" value="0"/>
+ <entry name="on" value="1"/>
+ </enum>
+
+ <request name="home">
+ <description summary="request showing workspace or disable"/>
+ <arg name="home" type="uint"/>
+ </request>
+
+ <event name="workspace_end_control">
+ <description summary="notify controlling workspace end"/>
+ <arg name="is_controlled" type="int"/>
+ </event>
+
+ </interface>
+
+</protocol>
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 10:01:31 UTC
Permalink
From: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at denso.co.jp>

---
protocol/Makefile.am | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 9913f16..140aef5 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -9,7 +9,8 @@ protocol_sources = \
wayland-test.xml \
xdg-shell.xml \
scaler.xml \
- ivi-application.xml
+ ivi-application.xml \
+ ivi-hmi-controller.xml

if HAVE_XMLLINT
.PHONY: validate
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 10:02:20 UTC
Permalink
The library is used to manage layout of surfaces/layers. Layout change is
triggered by ivi-hmi-controller protocol, ivi-hmi-controller.xml. A reference
how to use the protocol, see hmi-controller-homescreen.

In-Vehicle Infotainment system usually manage properties of surfaces/layers
by only a central component which decide where surfaces/layers shall be. This
reference show examples to implement the central component as a module of
weston.

Default Scene graph of UI is defined in hmi_controller_create. It consists of
- In the bottom, a base layer to group surfaces of background, panel,
and buttons
- Next, a application layer to show application surfaces.
- Workspace background layer to show a surface of background image.
- Workspace layer to show launcher to launch application with icons. Paths to
binary and icon are defined in weston.ini. The width of this layer is longer
than the size of screen because a workspace has several pages and is
controlled by motion of input.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
ivi-shell/hmi-controller.c | 1776 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1776 insertions(+)
create mode 100644 ivi-shell/hmi-controller.c

diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
new file mode 100644
index 0000000..3cfb19b
--- /dev/null
+++ b/ivi-shell/hmi-controller.c
@@ -0,0 +1,1776 @@
+/*
+ * Copyright (C) 2014 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * A reference implementation how to use weston-layout APIs in order to manage
+ * layout of surfaces/layers. Layout change is triggered by ivi-hmi-controller
+ * protocol, ivi-hmi-controller.xml. A reference how to use the protocol, see
+ * hmi-controller-homescreen.
+ *
+ * In-Vehicle Infotainment system usually manage properties of surfaces/layers
+ * by only a central component which decide where surfaces/layers shall be. This
+ * reference show examples to implement the central component as a module of weston.
+ *
+ * Default Scene graph of UI is defined in hmi_controller_create. It consists of
+ * - In the bottom, a base layer to group surfaces of background, panel,
+ * and buttons
+ * - Next, a application layer to show application surfaces.
+ * - Workspace background layer to show a surface of background image.
+ * - Workspace layer to show launcher to launch application with icons. Paths to
+ * binary and icon are defined in weston.ini. The width of this layer is longer
+ * than the size of screen because a workspace has several pages and is controlled
+ * by motion of input.
+ *
+ * TODO: animation method shall be refined
+ * TODO: support fade-in when UI is ready
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <assert.h>
+#include <time.h>
+
+#include "weston-layout.h"
+#include "hmi-controller-homescreen.h"
+#include "ivi-hmi-controller-server-protocol.h"
+
+/*****************************************************************************
+ * structure, globals
+ ****************************************************************************/
+struct hmi_controller_layer {
+ struct weston_layout_layer *ivilayer;
+ uint32_t id_layer;
+ int32_t x;
+ int32_t y;
+ uint32_t width;
+ uint32_t height;
+};
+
+struct link_layer {
+ struct weston_layout_layer *layout_layer;
+ struct wl_list link;
+};
+
+struct link_animation {
+ struct hmi_controller_animation *animation;
+ struct wl_list link;
+};
+
+struct hmi_controller_animation;
+typedef void (*hmi_controller_animation_frame_func)(void *animation, uint32_t timestamp);
+typedef void (*hmi_controller_animation_frame_user_func)(void *animation);
+typedef void (*hmi_controller_animation_destroy_func)(struct hmi_controller_animation *animation);
+
+struct move_animation_user_data {
+ struct weston_layout_layer* layer;
+ struct animation_set *anima_set;
+ struct hmi_controller *hmi_ctrl;
+};
+
+struct hmi_controller_animation {
+ void *user_data;
+ uint32_t time_start;
+ uint32_t is_done;
+ hmi_controller_animation_frame_func frame_func;
+ hmi_controller_animation_frame_user_func frame_user_func;
+ hmi_controller_animation_destroy_func destroy_func;
+};
+
+struct hmi_controller_animation_fade {
+ struct hmi_controller_animation base;
+ double start;
+ double end;
+ struct weston_spring spring;
+};
+
+struct hmi_controller_animation_move {
+ struct hmi_controller_animation base;
+ double pos;
+ double pos_start;
+ double pos_end;
+ double v0;
+ double a;
+ double time_end;
+};
+
+struct hmi_controller_fade {
+ uint32_t isFadeIn;
+ struct hmi_controller_animation_fade *animation;
+ struct animation_set *anima_set;
+ struct wl_list layer_list;
+};
+
+struct animation_set {
+ struct wl_event_source *event_source;
+ struct wl_list animation_list;
+};
+
+struct
+hmi_server_setting {
+ uint32_t base_layer_id;
+ uint32_t application_layer_id;
+ uint32_t workspace_background_layer_id;
+ uint32_t workspace_layer_id;
+ uint32_t panel_height;
+};
+
+struct hmi_controller
+{
+ struct hmi_server_setting *hmi_setting;
+ struct hmi_controller_layer base_layer;
+ struct hmi_controller_layer application_layer;
+ struct hmi_controller_layer workspace_background_layer;
+ struct hmi_controller_layer workspace_layer;
+ enum ivi_hmi_controller_layout_mode layout_mode;
+
+ struct animation_set *anima_set;
+ struct hmi_controller_fade workspace_fade;
+ struct hmi_controller_animation_move *workspace_swipe_animation;
+ int32_t workspace_count;
+ struct wl_array ui_widgets;
+ int32_t is_initialized;
+};
+
+/*****************************************************************************
+ * local functions
+ ****************************************************************************/
+static void *
+fail_on_null(void *p, size_t size, char* file, int32_t line)
+{
+ if (size && !p) {
+ fprintf(stderr, "%s(%d) %zd: out of memory\n", file, line, size);
+ exit(EXIT_FAILURE);
+ }
+
+ return p;
+}
+
+static void *
+mem_alloc(size_t size, char* file, int32_t line)
+{
+ return fail_on_null(calloc(1, size), size, file, line);
+}
+
+#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
+
+static int32_t
+is_surf_in_uiWidget(struct hmi_controller *hmi_ctrl,
+ struct weston_layout_surface *ivisurf)
+{
+ uint32_t id = weston_layout_getIdOfSurface(ivisurf);
+
+ uint32_t *ui_widget_id = NULL;
+ wl_array_for_each (ui_widget_id, &hmi_ctrl->ui_widgets) {
+ if (*ui_widget_id == id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Internal methods called by mainly ivi_hmi_controller_switch_mode
+ * This reference shows 4 examples how to use weston_layout APIs.
+ */
+static void
+mode_divided_into_tiling(struct hmi_controller *hmi_ctrl,
+ weston_layout_surface_ptr *ppSurface,
+ uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const float surface_width = (float)layer->width * 0.25;
+ const float surface_height = (float)layer->height * 0.5;
+ int32_t surface_x = 0;
+ int32_t surface_y = 0;
+ struct weston_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ uint32_t num = 1;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ if (num <= 8) {
+ if (num < 5) {
+ surface_x = (int32_t)((num - 1) * (surface_width));
+ surface_y = 0;
+ }
+ else {
+ surface_x = (int32_t)((num - 5) * (surface_width));
+ surface_y = (int32_t)surface_height;
+ }
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf, surface_x, surface_y,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 0);
+ assert(!ret);
+ }
+}
+
+static void
+mode_divided_into_sidebyside(struct hmi_controller *hmi_ctrl,
+ weston_layout_surface_ptr *ppSurface,
+ uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ uint32_t surface_width = layer->width / 2;
+ uint32_t surface_height = layer->height;
+ struct weston_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ uint32_t num = 1;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ if (num == 1) {
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf, 0, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+ else if (num == 2) {
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf, surface_width, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+
+ weston_layout_surfaceSetVisibility(ivisurf, 0);
+ assert(!ret);
+ }
+}
+
+static void
+mode_fullscreen_someone(struct hmi_controller *hmi_ctrl,
+ weston_layout_surface_ptr *ppSurface, uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const uint32_t surface_width = layer->width;
+ const uint32_t surface_height = layer->height;
+ struct weston_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf, 0, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+ }
+}
+
+static void
+mode_random_replace(struct hmi_controller *hmi_ctrl,
+ weston_layout_surface_ptr *ppSurface, uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const uint32_t surface_width = (uint32_t)(layer->width * 0.25f);
+ const uint32_t surface_height = (uint32_t)(layer->height * 0.25f);
+ uint32_t surface_x = 0;
+ uint32_t surface_y = 0;
+ struct weston_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ surface_x = rand() % (layer->width - surface_width);
+ surface_y = rand() % (layer->height - surface_height);
+
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf, surface_x, surface_y,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+ }
+}
+
+static int32_t
+has_applicatipn_surface(struct hmi_controller *hmi_ctrl, weston_layout_surface_ptr *ppSurface,
+ uint32_t surface_length)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t i = 0;
+
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Supports 4 example to layout of application surfaces;
+ * tiling, side by side, fullscreen, and random.
+ */
+static void
+switch_mode(struct hmi_controller *hmi_ctrl,
+ enum ivi_hmi_controller_layout_mode layout_mode)
+{
+ if (!hmi_ctrl->is_initialized) {
+ return;
+ }
+
+ struct hmi_controller_layer *layer = &hmi_ctrl->application_layer;
+ weston_layout_surface_ptr *ppSurface = NULL;
+ uint32_t surface_length = 0;
+ int32_t ret = 0;
+
+ hmi_ctrl->layout_mode = layout_mode;
+
+ ret = weston_layout_getSurfaces(&surface_length, &ppSurface);
+ assert(!ret);
+
+ if (!has_applicatipn_surface(hmi_ctrl, ppSurface, surface_length)) {
+ free(ppSurface);
+ ppSurface = NULL;
+ return;
+ }
+
+ switch (layout_mode) {
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING:
+ mode_divided_into_tiling(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE:
+ mode_divided_into_sidebyside(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN:
+ mode_fullscreen_someone(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM:
+ mode_random_replace(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ }
+
+ weston_layout_commitChanges();
+
+ free(ppSurface);
+ ppSurface = NULL;
+
+ return;
+}
+
+/**
+ * Internal method for animation
+ */
+static void
+hmi_controller_animation_frame(
+ struct hmi_controller_animation *animation, uint32_t timestamp)
+{
+ if (0 == animation->time_start) {
+ animation->time_start = timestamp;
+ }
+
+ animation->frame_func(animation, timestamp);
+ animation->frame_user_func(animation);
+}
+
+static int
+animation_set_do_anima(void* data)
+{
+ struct animation_set *anima_set = data;
+ uint32_t fps = 30;
+
+ if (wl_list_empty(&anima_set->animation_list)) {
+ wl_event_source_timer_update(anima_set->event_source, 0);
+ return 1;
+ }
+
+ wl_event_source_timer_update(anima_set->event_source, 1000 / fps);
+
+ struct timespec timestamp = {0};
+ clock_gettime(CLOCK_MONOTONIC, &timestamp);
+ uint32_t msec = (1e+3 * timestamp.tv_sec + 1e-6 * timestamp.tv_nsec);
+
+ struct link_animation *link_animation = NULL;
+ struct link_animation *next = NULL;
+
+ wl_list_for_each_safe(link_animation, next, &anima_set->animation_list, link) {
+ hmi_controller_animation_frame(link_animation->animation, msec);
+ }
+
+ weston_layout_commitChanges();
+ return 1;
+}
+
+static struct animation_set *
+animation_set_create(struct weston_compositor* ec)
+{
+ struct animation_set *anima_set = MEM_ALLOC(sizeof(*anima_set));
+
+ wl_list_init(&anima_set->animation_list);
+
+ struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
+ anima_set->event_source = wl_event_loop_add_timer(loop, animation_set_do_anima, anima_set);
+ wl_event_source_timer_update(anima_set->event_source, 0);
+
+ return anima_set;
+}
+
+static void
+animation_set_add_animation(struct animation_set *anima_set,
+ struct hmi_controller_animation *anima)
+{
+ struct link_animation *link_anima = NULL;
+
+ link_anima = MEM_ALLOC(sizeof(*link_anima));
+ if (NULL == link_anima) {
+ return;
+ }
+
+ link_anima->animation = anima;
+ wl_list_insert(&anima_set->animation_list, &link_anima->link);
+ wl_event_source_timer_update(anima_set->event_source, 1);
+}
+
+static void
+animation_set_remove_animation(struct animation_set *anima_set,
+ struct hmi_controller_animation *anima)
+{
+ struct link_animation *link_animation = NULL;
+ struct link_animation *next = NULL;
+
+ wl_list_for_each_safe(link_animation, next, &anima_set->animation_list, link) {
+ if (link_animation->animation == anima) {
+ wl_list_remove(&link_animation->link);
+ free(link_animation);
+ break;
+ }
+ }
+}
+
+static void
+hmi_controller_animation_spring_frame(
+ struct hmi_controller_animation_fade *animation, uint32_t timestamp)
+{
+ if (0 == animation->spring.timestamp) {
+ animation->spring.timestamp = timestamp;
+ }
+
+ weston_spring_update(&animation->spring, timestamp);
+ animation->base.is_done = weston_spring_done(&animation->spring);
+}
+
+static void
+hmi_controller_animation_move_frame(
+ struct hmi_controller_animation_move *animation, uint32_t timestamp)
+{
+ double s = animation->pos_start;
+ double t = timestamp - animation->base.time_start;
+ double v0 = animation->v0;
+ double a = animation->a;
+ double time_end = animation->time_end;
+
+ if (time_end <= t) {
+ animation->pos = animation->pos_end;
+ animation->base.is_done = 1;
+ } else {
+ animation->pos = v0 * t + 0.5 * a * t * t + s;
+ }
+}
+
+static void
+hmi_controller_animation_destroy(struct hmi_controller_animation *animation)
+{
+ if (animation->destroy_func) {
+ animation->destroy_func(animation);
+ }
+
+ free(animation);
+}
+
+static void
+hmi_controller_fade_animation_destroy(struct hmi_controller_animation *animation)
+{
+ struct hmi_controller_fade *fade = animation->user_data;
+ animation_set_remove_animation(fade->anima_set, animation);
+ fade->animation = NULL;
+ animation->user_data = NULL;
+}
+
+static struct hmi_controller_animation_fade *
+hmi_controller_animation_fade_create(double start, double end, double k,
+ hmi_controller_animation_frame_user_func frame_user_func, void* user_data,
+ hmi_controller_animation_destroy_func destroy_func)
+{
+ struct hmi_controller_animation_fade* animation = MEM_ALLOC(sizeof(*animation));
+
+ animation->base.frame_user_func = frame_user_func;
+ animation->base.user_data = user_data;
+ animation->base.frame_func =
+ (hmi_controller_animation_frame_func)hmi_controller_animation_spring_frame;
+ animation->base.destroy_func = destroy_func;
+
+ animation->start = start;
+ animation->end = end;
+ weston_spring_init(&animation->spring, k, start, end);
+ animation->spring.friction = 1400;
+ animation->spring.previous = -(end - start) * 0.03;
+
+ return animation;
+}
+
+static struct hmi_controller_animation_move *
+hmi_controller_animation_move_create(
+ double pos_start, double pos_end, double v_start, double v_end,
+ hmi_controller_animation_frame_user_func frame_user_func, void* user_data,
+ hmi_controller_animation_destroy_func destroy_func)
+{
+ struct hmi_controller_animation_move* animation = MEM_ALLOC(sizeof(*animation));
+
+ animation->base.frame_user_func = frame_user_func;
+ animation->base.user_data = user_data;
+ animation->base.frame_func =
+ (hmi_controller_animation_frame_func)hmi_controller_animation_move_frame;
+ animation->base.destroy_func = destroy_func;
+
+ animation->pos_start = pos_start;
+ animation->pos_end = pos_end;
+ animation->v0 = v_start;
+ animation->pos = pos_start;
+
+ double dx = (pos_end - pos_start);
+
+ if (1e-3 < fabs(dx)) {
+ animation->a = 0.5 * (v_end * v_end - v_start * v_start) / dx;
+ if (1e-6 < fabs(animation->a)) {
+ animation->time_end = (v_end - v_start) / animation->a;
+
+ } else {
+ animation->a = 0;
+ animation->time_end = fabs(dx / animation->v0);
+ }
+
+ } else {
+ animation->time_end = 0;
+ }
+
+ return animation;
+}
+
+static double
+hmi_controller_animation_fade_alpha_get(struct hmi_controller_animation_fade* animation)
+{
+ if (animation->spring.current > 0.999) {
+ return 1.0;
+ } else if (animation->spring.current < 0.001 ) {
+ return 0.0;
+ } else {
+ return animation->spring.current;
+ }
+}
+
+static uint32_t
+hmi_controller_animation_is_done(struct hmi_controller_animation *animation)
+{
+ return animation->is_done;
+}
+
+static void
+hmi_controller_fade_update(struct hmi_controller_animation_fade *animation, double end)
+{
+ animation->spring.target = end;
+}
+
+static void
+hmi_controller_anima_fade_user_frame(struct hmi_controller_animation_fade *animation)
+{
+ double alpha = hmi_controller_animation_fade_alpha_get(animation);
+ alpha = wl_fixed_from_double(alpha);
+ struct hmi_controller_fade *fade = animation->base.user_data;
+ struct link_layer *linklayer = NULL;
+ int32_t is_done = hmi_controller_animation_is_done(&animation->base);
+ int32_t is_visible = !is_done || fade->isFadeIn;
+
+ wl_list_for_each(linklayer, &fade->layer_list, link) {
+ weston_layout_layerSetOpacity(linklayer->layout_layer, alpha);
+ weston_layout_layerSetVisibility(linklayer->layout_layer, is_visible);
+ }
+
+ if (is_done) {
+ hmi_controller_animation_destroy(&animation->base);
+ }
+}
+
+static void
+hmi_controller_anima_move_user_frame(struct hmi_controller_animation_move *animation)
+{
+ struct move_animation_user_data* user_data = animation->base.user_data;
+ struct weston_layout_layer *layer = user_data->layer;
+ int32_t is_done = hmi_controller_animation_is_done(&animation->base);
+
+ int32_t pos[2] = {0};
+ weston_layout_layerGetPosition(layer, pos);
+
+ pos[0] = (int32_t)animation->pos;
+ weston_layout_layerSetPosition(layer, pos);
+
+ if (is_done) {
+ hmi_controller_animation_destroy(&animation->base);
+ }
+}
+
+static void
+hmi_controller_fade_run(uint32_t isFadeIn, struct hmi_controller_fade *fade)
+{
+ double tint = isFadeIn ? 1.0 : 0.0;
+ fade->isFadeIn = isFadeIn;
+
+ if (fade->animation) {
+ hmi_controller_fade_update(fade->animation, tint);
+ } else {
+ fade->animation = hmi_controller_animation_fade_create(
+ 1.0 - tint, tint, 300.0,
+ (hmi_controller_animation_frame_user_func)hmi_controller_anima_fade_user_frame,
+ fade, hmi_controller_fade_animation_destroy);
+
+ animation_set_add_animation(fade->anima_set, &fade->animation->base);
+ }
+}
+
+/**
+ * Internal method to create layer with hmi_controller_layer and add to a screen
+ */
+static void
+create_layer(struct weston_layout_screen *iviscrn,
+ struct hmi_controller_layer *layer)
+{
+ int32_t ret = 0;
+
+ layer->ivilayer = weston_layout_layerCreateWithDimension(layer->id_layer,
+ layer->width, layer->height);
+ assert(layer->ivilayer != NULL);
+
+ ret = weston_layout_screenAddLayer(iviscrn, layer->ivilayer);
+ assert(!ret);
+
+ ret = weston_layout_layerSetDestinationRectangle(layer->ivilayer, layer->x, layer->y,
+ layer->width, layer->height);
+ assert(!ret);
+
+ ret = weston_layout_layerSetVisibility(layer->ivilayer, 1);
+ assert(!ret);
+}
+
+/**
+ * Internal set notification
+ */
+static void
+set_notification_create_surface(struct weston_layout_surface *ivisurf,
+ void *userdata)
+{
+ struct hmi_controller* hmi_ctrl = userdata;
+ struct weston_layout_layer *application_layer = hmi_ctrl->application_layer.ivilayer;
+ int32_t ret = 0;
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ return;
+ }
+
+ ret = weston_layout_layerAddSurface(application_layer, ivisurf);
+ assert(!ret);
+}
+
+static void
+set_notification_remove_surface(struct weston_layout_surface *ivisurf,
+ void *userdata)
+{
+ (void)ivisurf;
+ struct hmi_controller* hmi_ctrl = userdata;
+ switch_mode(hmi_ctrl, hmi_ctrl->layout_mode);
+}
+
+static void
+set_notification_configure_surface(struct weston_layout_surface *ivisurf,
+ void *userdata)
+{
+ (void)ivisurf;
+ struct hmi_controller* hmi_ctrl = userdata;
+ switch_mode(hmi_ctrl, hmi_ctrl->layout_mode);
+}
+
+/**
+ * A hmi_controller used 4 layers to manage surfaces. The IDs of corresponding layer
+ * are defined in weston.ini. Default scene graph of layers are initialized in
+ * hmi_controller_create
+ */
+static struct hmi_server_setting *
+hmi_server_setting_create(void)
+{
+ struct hmi_server_setting* setting = MEM_ALLOC(sizeof(*setting));
+
+ struct weston_config *config = NULL;
+ config = weston_config_parse("weston.ini");
+
+ struct weston_config_section *shellSection = NULL;
+ shellSection = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ weston_config_section_get_uint(
+ shellSection, "base-layer-id", &setting->base_layer_id, 1000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-layer-id", &setting->workspace_background_layer_id, 2000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-layer-id", &setting->workspace_layer_id, 3000);
+
+ weston_config_section_get_uint(
+ shellSection, "application-layer-id", &setting->application_layer_id, 4000);
+
+ setting->panel_height = 70;
+
+ weston_config_destroy(config);
+
+ return setting;
+}
+
+/**
+ * This is a starting method called from module_init.
+ * This sets up scene graph of layers; base, application, workspace background,
+ * and workspace. These layers are created/added to screen in create_layer
+ *
+ * base: to group surfaces of panel and background
+ * application: to group surfaces of ivi_applications
+ * workspace background: to group a surface of background in workspace
+ * workspace: to group surfaces for launching ivi_applications
+ *
+ * Layers of workspace background and workspace is set to invisible at first.
+ * The properties of it is updated with animation when ivi_hmi_controller_home is
+ * requested.
+ */
+static struct hmi_controller *
+hmi_controller_create(struct weston_compositor *ec)
+{
+ weston_layout_screen_ptr *ppScreen = NULL;
+ struct weston_layout_screen *iviscrn = NULL;
+ uint32_t screen_length = 0;
+ uint32_t screen_width = 0;
+ uint32_t screen_height = 0;
+ int32_t ret = 0;
+ struct link_layer *tmp_link_layer = NULL;
+
+ struct hmi_controller *hmi_ctrl = MEM_ALLOC(sizeof(*hmi_ctrl));
+ wl_array_init(&hmi_ctrl->ui_widgets);
+ hmi_ctrl->layout_mode = IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING;
+ hmi_ctrl->hmi_setting = hmi_server_setting_create();
+
+ weston_layout_getScreens(&screen_length, &ppScreen);
+
+ iviscrn = ppScreen[0];
+
+ weston_layout_getScreenResolution(iviscrn, &screen_width, &screen_height);
+ assert(!ret);
+
+ /* init base layer*/
+ hmi_ctrl->base_layer.x = 0;
+ hmi_ctrl->base_layer.y = 0;
+ hmi_ctrl->base_layer.width = screen_width;
+ hmi_ctrl->base_layer.height = screen_height;
+ hmi_ctrl->base_layer.id_layer = hmi_ctrl->hmi_setting->base_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->base_layer);
+
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+
+
+ /* init application layer */
+ hmi_ctrl->application_layer.x = 0;
+ hmi_ctrl->application_layer.y = 0;
+ hmi_ctrl->application_layer.width = screen_width;
+ hmi_ctrl->application_layer.height = screen_height - panel_height;
+ hmi_ctrl->application_layer.id_layer = hmi_ctrl->hmi_setting->application_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->application_layer);
+
+ /* init workspace background layer */
+ hmi_ctrl->workspace_background_layer.x = 0;
+ hmi_ctrl->workspace_background_layer.y = 0;
+ hmi_ctrl->workspace_background_layer.width = screen_width;
+ hmi_ctrl->workspace_background_layer.height = screen_height - panel_height;
+
+ hmi_ctrl->workspace_background_layer.id_layer =
+ hmi_ctrl->hmi_setting->workspace_background_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->workspace_background_layer);
+ weston_layout_layerSetOpacity(hmi_ctrl->workspace_background_layer.ivilayer, 0);
+ weston_layout_layerSetVisibility(hmi_ctrl->workspace_background_layer.ivilayer, 0);
+
+ /* init workspace layer */
+ hmi_ctrl->workspace_layer.x = hmi_ctrl->workspace_background_layer.x;
+ hmi_ctrl->workspace_layer.y = hmi_ctrl->workspace_background_layer.y;
+ hmi_ctrl->workspace_layer.width = hmi_ctrl->workspace_background_layer.width;
+ hmi_ctrl->workspace_layer.height = hmi_ctrl->workspace_background_layer.height;
+ hmi_ctrl->workspace_layer.id_layer = hmi_ctrl->hmi_setting->workspace_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->workspace_layer);
+ weston_layout_layerSetOpacity(hmi_ctrl->workspace_layer.ivilayer, 0);
+ weston_layout_layerSetVisibility(hmi_ctrl->workspace_layer.ivilayer, 0);
+
+ /* set up animation to workspace background and workspace */
+ hmi_ctrl->anima_set = animation_set_create(ec);
+
+ wl_list_init(&hmi_ctrl->workspace_fade.layer_list);
+ tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer));
+ tmp_link_layer->layout_layer = hmi_ctrl->workspace_layer.ivilayer;
+ wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, &tmp_link_layer->link);
+ tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer));
+ tmp_link_layer->layout_layer = hmi_ctrl->workspace_background_layer.ivilayer;
+ wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, &tmp_link_layer->link);
+ hmi_ctrl->workspace_fade.anima_set = hmi_ctrl->anima_set;
+
+ weston_layout_setNotificationCreateSurface(set_notification_create_surface, hmi_ctrl);
+ weston_layout_setNotificationRemoveSurface(set_notification_remove_surface, hmi_ctrl);
+ weston_layout_setNotificationConfigureSurface(set_notification_configure_surface, hmi_ctrl);
+
+ free(ppScreen);
+ ppScreen = NULL;
+
+ return hmi_ctrl;
+}
+
+/**
+ * Implementations of ivi-hmi-controller.xml
+ */
+
+/**
+ * A surface drawing background is identified by id_surface.
+ * Properties of the surface is set by using weston_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_background(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface)
+
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const uint32_t dstx = hmi_ctrl->application_layer.x;
+ const uint32_t dsty = hmi_ctrl->application_layer.y;
+ const uint32_t width = hmi_ctrl->application_layer.width;
+ const uint32_t height = hmi_ctrl->application_layer.height;
+ uint32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = weston_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = weston_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf,
+ dstx, dsty, width, height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ weston_layout_commitChanges();
+}
+
+/**
+ * A surface drawing panel is identified by id_surface.
+ * Properties of the surface is set by using weston_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_panel(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const uint32_t width = hmi_ctrl->base_layer.width;
+ uint32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = weston_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = weston_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+ const uint32_t dstx = 0;
+ const uint32_t dsty = hmi_ctrl->base_layer.height - panel_height;
+
+ ret = weston_layout_surfaceSetDestinationRectangle(
+ ivisurf, dstx, dsty, width, panel_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ weston_layout_commitChanges();
+}
+
+/**
+ * A surface drawing buttons in panel is identified by id_surface. It can set
+ * several buttons. Properties of the surface is set by using weston_layout
+ * APIs according to the scene graph of UI defined in hmi_controller_create.
+ * Additionally, the position of it is shifted to right when new one is requested.
+ *
+ * UI layer is used to add these surfaces.
+ */
+static void
+ivi_hmi_controller_set_button(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface, uint32_t number)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const uint32_t width = 48;
+ const uint32_t height = 48;
+ uint32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = weston_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = weston_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+
+ const uint32_t dstx = (60 * number) + 15;
+ const uint32_t dsty = (hmi_ctrl->base_layer.height - panel_height) + 5;
+
+ ret = weston_layout_surfaceSetDestinationRectangle(
+ ivisurf,dstx, dsty, width, height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ weston_layout_commitChanges();
+}
+
+/**
+ * A surface drawing home button in panel is identified by id_surface.
+ * Properties of the surface is set by using weston_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add these surfaces.
+ */
+static void
+ivi_hmi_controller_set_home_button(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ uint32_t ret = 0;
+ uint32_t size = 48;
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+ const uint32_t dstx = (hmi_ctrl->base_layer.width - size) / 2;
+ const uint32_t dsty = (hmi_ctrl->base_layer.height - panel_height) + 5;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = weston_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = weston_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetDestinationRectangle(
+ ivisurf, dstx, dsty, size, size);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ weston_layout_commitChanges();
+ hmi_ctrl->is_initialized = 1;
+}
+
+/**
+ * A surface drawing background of workspace is identified by id_surface.
+ * Properties of the surface is set by using weston_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * A layer of workspace_background is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_workspacebackground(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_layer *ivilayer = NULL;
+ ivilayer = hmi_ctrl->workspace_background_layer.ivilayer;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ const uint32_t width = hmi_ctrl->workspace_background_layer.width;
+ const uint32_t height = hmi_ctrl->workspace_background_layer.height;
+ uint32_t ret = 0;
+
+ ivisurf = weston_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = weston_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf,
+ 0, 0, width, height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ weston_layout_commitChanges();
+}
+
+/**
+ * A list of surfaces drawing launchers in workspace is identified by id_surfaces.
+ * Properties of the surface is set by using weston_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * The workspace can have several pages to group surfaces of launcher. Each call
+ * of this interface increments a number of page to add a group of surfaces
+ */
+static void
+ivi_hmi_controller_add_launchers(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_array *surface_ids,
+ uint32_t icon_size)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ uint32_t minspace_x = 10;
+ uint32_t minspace_y = minspace_x;
+
+ uint32_t width = hmi_ctrl->workspace_layer.width;
+ uint32_t height = hmi_ctrl->workspace_layer.height;
+
+ uint32_t x_count = (width - minspace_x) / (minspace_x + icon_size);
+ uint32_t space_x = (uint32_t)((width - x_count * icon_size) / (1.0 + x_count));
+ float fcell_size_x = icon_size + space_x;
+
+ uint32_t y_count = (height - minspace_y) / (minspace_y + icon_size);
+ uint32_t space_y = (uint32_t)((height - y_count * icon_size) / (1.0 + y_count));
+ float fcell_size_y = icon_size + space_y;
+
+ if (0 == x_count) {
+ x_count = 1;
+ }
+
+ if (0 == y_count) {
+ y_count = 1;
+ }
+
+ hmi_ctrl->workspace_count++;
+
+ uint32_t *surface_id = NULL;
+ uint32_t nx = 0;
+ uint32_t ny = 0;
+
+ wl_array_for_each(surface_id, surface_ids) {
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = *surface_id;
+
+ if (y_count == ny) {
+ ny = 0;
+ hmi_ctrl->workspace_count++;
+ }
+
+ uint32_t x = (uint32_t)(nx * fcell_size_x + (hmi_ctrl->workspace_count - 1) * width + space_x);
+ uint32_t y = (uint32_t)(ny * fcell_size_y + space_y) ;
+
+ struct weston_layout_surface* layout_surface = NULL;
+ layout_surface = weston_layout_getSurfaceFromId(*surface_id);
+ assert(layout_surface);
+
+ uint32_t ret = 0;
+ ret = weston_layout_layerAddSurface(layer, layout_surface);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetDestinationRectangle(
+ layout_surface, x, y, icon_size, icon_size);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(layout_surface, 1);
+ assert(!ret);
+
+ nx++;
+
+ if (x_count == nx) {
+ ny++;
+ nx = 0;
+ }
+ }
+
+ weston_layout_commitChanges();
+}
+
+/**
+ * Implementation of request and event of ivi_hmi_controller_workspace_control
+ * and controlling workspace.
+ *
+ * When motion of input is detected in a surface of workspace background,
+ * ivi_hmi_controller_workspace_control shall be invoked and to start controlling of
+ * workspace. The workspace has several pages to show several groups of applications.
+ * The workspace is slid by using weston-layout to select a a page in layer_set_pos
+ * according to motion. When motion finished, e.g. touch up detected, control is
+ * terminated and event:ivi_hmi_controller_workspace_control is notified.
+ */
+struct pointer_grab {
+ struct weston_pointer_grab grab;
+ struct weston_layout_layer *layer;
+ struct wl_resource *resource;
+};
+
+struct touch_grab {
+ struct weston_touch_grab grab;
+ struct weston_layout_layer *layer;
+ struct wl_resource *resource;
+};
+
+struct move_grab {
+ wl_fixed_t dst[2];
+ wl_fixed_t rgn[2][2];
+ double v[2];
+ struct timespec start_time;
+ struct timespec pre_time;
+ wl_fixed_t start_pos[2];
+ wl_fixed_t pos[2];
+ int32_t is_moved;
+};
+
+struct pointer_move_grab {
+ struct pointer_grab base;
+ struct move_grab move;
+};
+
+struct touch_move_grab {
+ struct touch_grab base;
+ struct move_grab move;
+ int32_t is_active;
+};
+
+static void
+pointer_grab_start(struct pointer_grab *grab,
+ struct weston_layout_layer *layer,
+ const struct weston_pointer_grab_interface *interface,
+ struct weston_pointer *pointer)
+{
+ grab->grab.interface = interface;
+ grab->layer = layer;
+ weston_pointer_start_grab(pointer, &grab->grab);
+}
+
+static void
+touch_grab_start(struct touch_grab *grab,
+ struct weston_layout_layer *layer,
+ const struct weston_touch_grab_interface *interface,
+ struct weston_touch* touch)
+{
+ grab->grab.interface = interface;
+ grab->layer = layer;
+ weston_touch_start_grab(touch, &grab->grab);
+}
+
+static int32_t
+range_val(int32_t val, int32_t min, int32_t max)
+{
+ if (val < min) {
+ return min;
+ }
+
+ if (max < val) {
+ return max;
+ }
+
+ return val;
+}
+
+static void
+hmi_controller_move_animation_destroy(struct hmi_controller_animation *animation)
+{
+ struct move_animation_user_data *user_data = animation->user_data;
+ if (animation == &user_data->hmi_ctrl->workspace_swipe_animation->base) {
+ user_data->hmi_ctrl->workspace_swipe_animation = NULL;
+ }
+
+ animation_set_remove_animation(user_data->anima_set, animation);
+ free(animation->user_data);
+ animation->user_data = NULL;
+}
+
+static void
+move_workspace_grab_end(struct move_grab *move, struct wl_resource* resource,
+ wl_fixed_t grab_x, struct weston_layout_layer *layer)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ int32_t width = (int32_t)hmi_ctrl->workspace_background_layer.width;
+
+ struct timespec time = {0};
+ clock_gettime(CLOCK_MONOTONIC, &time);
+
+ double grab_time = 1e+3 * (time.tv_sec - move->start_time.tv_sec) +
+ 1e-6 * (time.tv_nsec - move->start_time.tv_nsec);
+
+ double from_motion_time = 1e+3 * (time.tv_sec - move->pre_time.tv_sec) +
+ 1e-6 * (time.tv_nsec - move->pre_time.tv_nsec);
+
+ double pointer_v = move->v[0];
+
+ if (200 < from_motion_time) {
+ pointer_v = 0.0;
+ }
+
+ int32_t is_flick = grab_time < 400 &&
+ 0.4 < fabs(pointer_v);
+
+ int32_t pos[2] = {0};
+ weston_layout_layerGetPosition(layer, pos);
+
+ int page_no = 0;
+
+ if (is_flick) {
+ int orgx = wl_fixed_to_int(move->dst[0] + grab_x);
+ page_no = (-orgx + width / 2) / width;
+
+ if (pointer_v < 0.0) {
+ page_no++;
+ }else {
+ page_no--;
+ }
+ }else {
+ page_no = (-pos[0] + width / 2) / width;
+ }
+
+ page_no = range_val(page_no, 0, hmi_ctrl->workspace_count - 1);
+ double end_pos = -page_no * width;
+
+ double dst = fabs(end_pos - pos[0]);
+ double max_time = 0.5 * 1e+3;
+ double v = dst / max_time;
+
+ double vmin = 1000 * 1e-3;
+ if (v < vmin ) {
+ v = vmin;
+ }
+
+ double v0 = 0.0;
+ if (pos[0] < end_pos) {
+ v0 = v;
+ } else {
+ v0 = -v;
+ }
+
+ struct move_animation_user_data *animation_user_data = NULL;
+ animation_user_data = MEM_ALLOC(sizeof(*animation_user_data));
+ animation_user_data->layer = layer;
+ animation_user_data->anima_set = hmi_ctrl->anima_set;
+ animation_user_data->hmi_ctrl = hmi_ctrl;
+
+ struct hmi_controller_animation_move* animation = NULL;
+ animation = hmi_controller_animation_move_create(
+ pos[0], end_pos, v0, v0,
+ (hmi_controller_animation_frame_user_func)hmi_controller_anima_move_user_frame,
+ animation_user_data, hmi_controller_move_animation_destroy);
+
+ hmi_ctrl->workspace_swipe_animation = animation;
+ animation_set_add_animation(hmi_ctrl->anima_set, &animation->base);
+
+ ivi_hmi_controller_send_workspace_end_control(resource, move->is_moved);
+}
+
+static void
+pointer_move_workspace_grab_end(struct pointer_grab *grab)
+{
+ struct pointer_move_grab *pnt_move_grab = (struct pointer_move_grab *) grab;
+ struct weston_layout_layer *layer = pnt_move_grab->base.layer;
+
+ move_workspace_grab_end(&pnt_move_grab->move, grab->resource,
+ grab->grab.pointer->grab_x, layer);
+
+ weston_pointer_end_grab(grab->grab.pointer);
+}
+
+static void
+touch_move_workspace_grab_end(struct touch_grab *grab)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *) grab;
+ struct weston_layout_layer *layer = tch_move_grab->base.layer;
+
+ move_workspace_grab_end(&tch_move_grab->move, grab->resource,
+ grab->grab.touch->grab_x, layer);
+
+ weston_touch_end_grab(grab->grab.touch);
+}
+
+static void
+pointer_noop_grab_focus(struct weston_pointer_grab *grab)
+{
+}
+
+static void
+move_grab_update(struct move_grab *move, wl_fixed_t pointer[2])
+{
+ struct timespec timestamp = {0};
+ clock_gettime(CLOCK_MONOTONIC, &timestamp);
+
+ double dt = (1e+3 * (timestamp.tv_sec - move->pre_time.tv_sec) +
+ 1e-6 * (timestamp.tv_nsec - move->pre_time.tv_nsec));
+
+ if (dt < 1e-6) {
+ dt = 1e-6;
+ }
+
+ move->pre_time = timestamp;
+
+ int32_t ii = 0;
+ for (ii = 0; ii < 2; ii++) {
+ wl_fixed_t prepos = move->pos[ii];
+ move->pos[ii] = pointer[ii] + move->dst[ii];
+
+ if (move->pos[ii] < move->rgn[0][ii]) {
+ move->pos[ii] = move->rgn[0][ii];
+ move->dst[ii] = move->pos[ii] - pointer[ii];
+ } else if (move->rgn[1][ii] < move->pos[ii]) {
+ move->pos[ii] = move->rgn[1][ii];
+ move->dst[ii] = move->pos[ii] - pointer[ii];
+ }
+
+ move->v[ii] = wl_fixed_to_double(move->pos[ii] - prepos) / dt;
+
+ if (!move->is_moved &&
+ 0 < wl_fixed_to_int(move->pos[ii] - move->start_pos[ii])) {
+ move->is_moved = 1;
+ }
+ }
+}
+
+static void
+layer_set_pos(struct weston_layout_layer *layer, wl_fixed_t pos[2])
+{
+ int32_t layout_pos[2] = {0};
+ layout_pos[0] = wl_fixed_to_int(pos[0]);
+ layout_pos[1] = wl_fixed_to_int(pos[1]);
+ weston_layout_layerSetPosition(layer, layout_pos);
+ weston_layout_commitChanges();
+}
+
+static void
+pointer_move_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ struct pointer_move_grab *pnt_move_grab = (struct pointer_move_grab *) grab;
+ wl_fixed_t pointer_pos[2] = {x, y};
+ move_grab_update(&pnt_move_grab->move, pointer_pos);
+ layer_set_pos(pnt_move_grab->base.layer, pnt_move_grab->move.pos);
+ weston_pointer_move(pnt_move_grab->base.grab.pointer, x, y);
+}
+
+static void
+touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
+ int touch_id, wl_fixed_t x, wl_fixed_t y)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *) grab;
+
+ if (!tch_move_grab->is_active) {
+ return;
+ }
+
+ wl_fixed_t pointer_pos[2] = {grab->touch->grab_x, grab->touch->grab_y};
+ move_grab_update(&tch_move_grab->move, pointer_pos);
+ layer_set_pos(tch_move_grab->base.layer, tch_move_grab->move.pos);
+}
+
+static void
+pointer_move_workspace_grab_button(struct weston_pointer_grab *grab,
+ uint32_t time, uint32_t button,
+ uint32_t state_w)
+{
+ if (BTN_LEFT == button &&
+ WL_POINTER_BUTTON_STATE_RELEASED == state_w) {
+ struct pointer_grab *pg = (struct pointer_grab *)grab;
+ pointer_move_workspace_grab_end(pg);
+ free(grab);
+ }
+}
+
+static void
+touch_nope_grab_down(struct weston_touch_grab *grab, uint32_t time,
+ int touch_id, wl_fixed_t sx, wl_fixed_t sy)
+{
+}
+
+static void
+touch_move_workspace_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *)grab;
+
+ if (0 == touch_id) {
+ tch_move_grab->is_active = 0;
+ }
+
+ if (0 == grab->touch->num_tp) {
+ touch_move_workspace_grab_end(&tch_move_grab->base);
+ free(grab);
+ }
+}
+
+static void
+pointer_move_workspace_grab_cancel(struct weston_pointer_grab *grab)
+{
+ struct pointer_grab *pg = (struct pointer_grab *)grab;
+ pointer_move_workspace_grab_end(pg);
+ free(grab);
+}
+
+static void
+touch_move_workspace_grab_cancel(struct weston_touch_grab *grab)
+{
+ struct touch_grab *tg = (struct touch_grab *)grab;
+ touch_move_workspace_grab_end(tg);
+ free(grab);
+}
+
+static const struct weston_pointer_grab_interface pointer_move_grab_workspace_interface = {
+ pointer_noop_grab_focus,
+ pointer_move_grab_motion,
+ pointer_move_workspace_grab_button,
+ pointer_move_workspace_grab_cancel
+};
+
+static const struct weston_touch_grab_interface touch_move_grab_workspace_interface = {
+ touch_nope_grab_down,
+ touch_move_workspace_grab_up,
+ touch_move_grab_motion,
+ touch_move_workspace_grab_cancel
+};
+
+enum HMI_GRAB_DEVICE
+{
+ HMI_GRAB_DEVICE_NONE,
+ HMI_GRAB_DEVICE_POINTER,
+ HMI_GRAB_DEVICE_TOUCH
+};
+
+static enum HMI_GRAB_DEVICE
+get_hmi_grab_device(struct weston_seat *seat, uint32_t serial)
+{
+ if (seat->pointer &&
+ seat->pointer->focus &&
+ seat->pointer->button_count &&
+ seat->pointer->grab_serial == serial) {
+ return HMI_GRAB_DEVICE_POINTER;
+ }
+
+ if (seat->touch &&
+ seat->touch->focus &&
+ seat->touch->grab_serial) {
+ return HMI_GRAB_DEVICE_TOUCH;
+ }
+
+ return HMI_GRAB_DEVICE_NONE;
+}
+
+static void
+move_grab_init(struct move_grab* move, wl_fixed_t start_pos[2],
+ wl_fixed_t grab_pos[2], wl_fixed_t rgn[2][2],
+ struct wl_resource* resource)
+{
+ clock_gettime(CLOCK_MONOTONIC, &move->start_time);
+ move->pre_time = move->start_time;
+ move->pos[0] = start_pos[0];
+ move->pos[1] = start_pos[1];
+ move->start_pos[0] = start_pos[0];
+ move->start_pos[1] = start_pos[1];
+ move->dst[0] = start_pos[0] - grab_pos[0];
+ move->dst[1] = start_pos[1] - grab_pos[1];
+ memcpy(move->rgn, rgn, sizeof(move->rgn));
+}
+
+static void
+move_grab_init_workspace(struct move_grab* move,
+ wl_fixed_t grab_x, wl_fixed_t grab_y,
+ struct wl_resource *resource)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ int32_t workspace_count = hmi_ctrl->workspace_count;
+ int32_t workspace_width = hmi_ctrl->workspace_background_layer.width;
+ int32_t layer_pos[2] = {0};
+ weston_layout_layerGetPosition(layer, layer_pos);
+
+ wl_fixed_t start_pos[2] = {0};
+ start_pos[0] = wl_fixed_from_int(layer_pos[0]);
+ start_pos[1] = wl_fixed_from_int(layer_pos[1]);
+
+ wl_fixed_t rgn[2][2] = {{0}};
+ rgn[0][0] = wl_fixed_from_int(-workspace_width * (workspace_count - 1));
+
+ rgn[0][1] = wl_fixed_from_int(0);
+ rgn[1][0] = wl_fixed_from_int(0);
+ rgn[1][1] = wl_fixed_from_int(0);
+
+ wl_fixed_t grab_pos[2] = {grab_x, grab_y};
+
+ move_grab_init(move, start_pos, grab_pos, rgn, resource);
+}
+
+static struct pointer_move_grab *
+create_workspace_pointer_move(struct weston_pointer *pointer, struct wl_resource* resource)
+{
+ struct pointer_move_grab *pnt_move_grab = MEM_ALLOC(sizeof(*pnt_move_grab));
+ pnt_move_grab->base.resource = resource;
+ move_grab_init_workspace(&pnt_move_grab->move, pointer->grab_x, pointer->grab_y, resource);
+ return pnt_move_grab;
+}
+
+static struct touch_move_grab *
+create_workspace_touch_move(struct weston_touch *touch, struct wl_resource* resource)
+{
+ struct touch_move_grab *tch_move_grab = MEM_ALLOC(sizeof(*tch_move_grab));
+ tch_move_grab->base.resource = resource;
+ tch_move_grab->is_active = 1;
+ move_grab_init_workspace(&tch_move_grab->move, touch->grab_x,touch->grab_y, resource);
+ return tch_move_grab;
+}
+
+static void
+ivi_hmi_controller_workspace_control(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *seat_resource,
+ uint32_t serial)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+
+ if (hmi_ctrl->workspace_count < 2) {
+ return;
+ }
+
+ struct weston_seat* seat = wl_resource_get_user_data(seat_resource);
+ enum HMI_GRAB_DEVICE device = get_hmi_grab_device(seat, serial);
+
+ if (HMI_GRAB_DEVICE_POINTER != device &&
+ HMI_GRAB_DEVICE_TOUCH != device) {
+ return;
+ }
+
+ if (hmi_ctrl->workspace_swipe_animation) {
+ hmi_controller_animation_destroy(&hmi_ctrl->workspace_swipe_animation->base);
+ }
+
+ struct weston_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ struct pointer_move_grab *pnt_move_grab = NULL;
+ struct touch_move_grab *tch_move_grab = NULL;
+
+ switch (device) {
+ case HMI_GRAB_DEVICE_POINTER:
+ pnt_move_grab = create_workspace_pointer_move(seat->pointer, resource);
+
+ pointer_grab_start(
+ &pnt_move_grab->base, layer, &pointer_move_grab_workspace_interface,
+ seat->pointer);
+ break;
+
+ case HMI_GRAB_DEVICE_TOUCH:
+ tch_move_grab = create_workspace_touch_move(seat->touch, resource);
+
+ touch_grab_start(
+ &tch_move_grab->base, layer, &touch_move_grab_workspace_interface,
+ seat->touch);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * Implementation of switch_mode
+ */
+static void
+ivi_hmi_controller_switch_mode(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t layout_mode)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ switch_mode(hmi_ctrl, layout_mode);
+}
+
+/**
+ * Implementation of on/off displaying workspace and workspace background layers.
+ */
+static void
+ivi_hmi_controller_home(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t home)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+
+ if ((IVI_HMI_CONTROLLER_HOME_ON == home && !hmi_ctrl->workspace_fade.isFadeIn) ||
+ (IVI_HMI_CONTROLLER_HOME_OFF == home && hmi_ctrl->workspace_fade.isFadeIn)) {
+
+ uint32_t isFadeIn = !hmi_ctrl->workspace_fade.isFadeIn;
+ hmi_controller_fade_run(isFadeIn, &hmi_ctrl->workspace_fade);
+ }
+}
+
+/**
+ * binding ivi-hmi-controller implementation
+ */
+static const struct ivi_hmi_controller_interface ivi_hmi_controller_implementation = {
+ ivi_hmi_controller_set_background,
+ ivi_hmi_controller_set_panel,
+ ivi_hmi_controller_set_button,
+ ivi_hmi_controller_set_home_button,
+ ivi_hmi_controller_set_workspacebackground,
+ ivi_hmi_controller_add_launchers,
+ ivi_hmi_controller_workspace_control,
+ ivi_hmi_controller_switch_mode,
+ ivi_hmi_controller_home
+};
+
+static void
+unbind_hmi_controller(struct wl_resource *resource)
+{
+}
+
+static void
+bind_hmi_controller(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource = NULL;
+
+ resource = wl_resource_create(
+ client, &ivi_hmi_controller_interface, 1, id);
+
+ wl_resource_set_implementation(
+ resource, &ivi_hmi_controller_implementation,
+ data, unbind_hmi_controller);
+}
+
+static void
+launch_hmi_client(void *data)
+{
+ hmi_client_start();
+}
+
+/*****************************************************************************
+ * exported functions
+ ****************************************************************************/
+
+WL_EXPORT int
+module_init(struct weston_compositor *ec,
+ int *argc, char *argv[])
+{
+ struct hmi_controller *hmi_ctrl = hmi_controller_create(ec);
+
+ if (wl_global_create(ec->wl_display,
+ &ivi_hmi_controller_interface, 1,
+ hmi_ctrl, bind_hmi_controller) == NULL) {
+ return -1;
+ }
+
+ struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
+ wl_event_loop_add_idle(loop, launch_hmi_client, ec);
+
+ return 0;
+}
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 10:03:03 UTC
Permalink
This is launched from hmi-controller by using hmi_client_start and create a
pthread.

The basic flow is as followed,
1/ create pthread
2/ read configuration from weston.ini.
3/ draw png file to surface according to configuration of weston.ini
4/ set up UI by using ivi-hmi-controller protocol
5/ Enter event loop
6/ If a surface receives touch/pointer event, followings are invoked according
to type of event and surface
6-1/ If a surface to launch ivi_application receive touch up, it execs
ivi-application configured in weston.ini.
6-2/ If a surface to switch layout mode receive touch up, it sends a request,
ivi_hmi_controller_switch_mode, to hmi-controller.
6-3/ If a surface to show workspace having launchers, it sends a request,
ivi_hmi_controller_home, to hmi-controller.
6-4/ If touch down events happens in workspace,
ivi_hmi_controller_workspace_control is sent to slide workspace.
When control finished, event: ivi_hmi_controller_workspace_end_control
is received.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
ivi-shell/hmi-controller-homescreen.c | 1370 +++++++++++++++++++++++++++++++++
ivi-shell/hmi-controller-homescreen.h | 36 +
2 files changed, 1406 insertions(+)
create mode 100644 ivi-shell/hmi-controller-homescreen.c
create mode 100644 ivi-shell/hmi-controller-homescreen.h

diff --git a/ivi-shell/hmi-controller-homescreen.c b/ivi-shell/hmi-controller-homescreen.c
new file mode 100644
index 0000000..51f6c75
--- /dev/null
+++ b/ivi-shell/hmi-controller-homescreen.c
@@ -0,0 +1,1370 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <wayland-cursor.h>
+#include "hmi-controller-homescreen.h"
+#include "../shared/cairo-util.h"
+#include "../shared/config-parser.h"
+#include "ivi-application-client-protocol.h"
+#include "ivi-hmi-controller-client-protocol.h"
+
+/**
+ * A reference implementation how to use ivi-hmi-controller interface to interact
+ * with hmi-controller. This is launched from hmi-controller by using
+ * hmi_client_start and create a pthread.
+ *
+ * The basic flow is as followed,
+ * 1/ create pthread
+ * 2/ read configuration from weston.ini.
+ * 3/ draw png file to surface according to configuration of weston.ini
+ * 4/ set up UI by using ivi-hmi-controller protocol
+ * 5/ Enter event loop
+ * 6/ If a surface receives touch/pointer event, followings are invoked according
+ * to type of event and surface
+ * 6-1/ If a surface to launch ivi_application receive touch up, it execs
+ * ivi-application configured in weston.ini.
+ * 6-2/ If a surface to switch layout mode receive touch up, it sends a request,
+ * ivi_hmi_controller_switch_mode, to hmi-controller.
+ * 6-3/ If a surface to show workspace having launchers, it sends a request,
+ * ivi_hmi_controller_home, to hmi-controller.
+ * 6-4/ If touch down events happens in workspace,
+ * ivi_hmi_controller_workspace_control is sent to slide workspace.
+ * When control finished, event: ivi_hmi_controller_workspace_end_control
+ * is received.
+ */
+
+/*****************************************************************************
+ * structure, globals
+ ****************************************************************************/
+enum cursor_type {
+ CURSOR_BOTTOM_LEFT,
+ CURSOR_BOTTOM_RIGHT,
+ CURSOR_BOTTOM,
+ CURSOR_DRAGGING,
+ CURSOR_LEFT_PTR,
+ CURSOR_LEFT,
+ CURSOR_RIGHT,
+ CURSOR_TOP_LEFT,
+ CURSOR_TOP_RIGHT,
+ CURSOR_TOP,
+ CURSOR_IBEAM,
+ CURSOR_HAND1,
+ CURSOR_WATCH,
+
+ CURSOR_BLANK
+};
+struct wlContextCommon {
+ struct wl_display *wlDisplay;
+ struct wl_registry *wlRegistry;
+ struct wl_compositor *wlCompositor;
+ struct wl_shm *wlShm;
+ struct wl_seat *wlSeat;
+ struct wl_pointer *wlPointer;
+ struct wl_touch *wlTouch;
+ struct ivi_application *iviApplication;
+ struct ivi_hmi_controller *hmiCtrl;
+ struct hmi_homescreen_setting *hmi_setting;
+ struct wl_list *list_wlContextStruct;
+ struct wl_surface *enterSurface;
+ int32_t is_home_on;
+ struct wl_cursor_theme *cursor_theme;
+ struct wl_cursor **cursors;
+ struct wl_surface *pointer_surface;
+ enum cursor_type current_cursor;
+ uint32_t enter_serial;
+};
+
+struct wlContextStruct {
+ struct wlContextCommon cmm;
+ struct wl_surface *wlSurface;
+ struct wl_buffer *wlBuffer;
+ uint32_t formats;
+ cairo_surface_t *ctx_image;
+ void *data;
+ uint32_t id_surface;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_srf {
+ uint32_t id;
+ char *filePath;
+ uint32_t color;
+};
+
+struct
+hmi_homescreen_workspace {
+ struct wl_array launcher_id_array;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_launcher {
+ uint32_t icon_surface_id;
+ uint32_t workspace_id;
+ char* icon;
+ char* path;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_setting {
+ struct hmi_homescreen_srf background;
+ struct hmi_homescreen_srf panel;
+ struct hmi_homescreen_srf tiling;
+ struct hmi_homescreen_srf sidebyside;
+ struct hmi_homescreen_srf fullscreen;
+ struct hmi_homescreen_srf random;
+ struct hmi_homescreen_srf home;
+ struct hmi_homescreen_srf workspace_background;
+
+ struct wl_list workspace_list;
+ struct wl_list launcher_list;
+
+ char *cursor_theme;
+ int32_t cursor_size;
+};
+
+volatile int gRun = 0;
+
+static void *
+fail_on_null(void *p, size_t size, char* file, int32_t line)
+{
+ if (size && !p) {
+ fprintf(stderr, "%s(%d) %zd: out of memory\n", file, line, size);
+ exit(EXIT_FAILURE);
+ }
+
+ return p;
+}
+
+static void *
+mem_alloc(size_t size, char* file, int32_t line)
+{
+ return fail_on_null(calloc(1, size), size, file, line);
+}
+
+#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+/*****************************************************************************
+ * Event Handler
+ ****************************************************************************/
+
+static void
+shm_format(void* data, struct wl_shm* pWlShm, uint32_t format)
+{
+ struct wlContextStruct* pDsp = data;
+ pDsp->formats |= (1 << format);
+}
+
+static struct wl_shm_listener shm_listenter = {
+ shm_format
+};
+
+static int32_t
+getIdOfWlSurface(struct wlContextCommon *pCtx, struct wl_surface *wlSurface)
+{
+ if (NULL == pCtx ||
+ NULL == wlSurface ) {
+ return 0;
+ }
+
+ struct wlContextStruct* pWlCtxSt = NULL;
+ wl_list_for_each(pWlCtxSt, pCtx->list_wlContextStruct, link) {
+ if (pWlCtxSt->wlSurface == wlSurface) {
+ return pWlCtxSt->id_surface;
+ }
+ continue;
+ }
+ return -1;
+}
+
+static void
+set_pointer_image(struct wlContextCommon *pCtx, uint32_t index)
+{
+ if (!pCtx->wlPointer ||
+ !pCtx->cursors) {
+ return;
+ }
+
+ if (CURSOR_BLANK == pCtx->current_cursor) {
+ wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
+ NULL, 0, 0);
+ return;
+ }
+
+ struct wl_cursor *cursor = pCtx->cursors[pCtx->current_cursor];
+ if (!cursor) {
+ return;
+ }
+
+ if (cursor->image_count <= index) {
+ fprintf(stderr, "cursor index out of range\n");
+ return;
+ }
+
+ struct wl_cursor_image *image = cursor->images[index];
+ struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
+
+ if (!buffer) {
+ return;
+ }
+
+ wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
+ pCtx->pointer_surface,
+ image->hotspot_x, image->hotspot_y);
+
+ wl_surface_attach(pCtx->pointer_surface, buffer, 0, 0);
+
+ wl_surface_damage(pCtx->pointer_surface, 0, 0,
+ image->width, image->height);
+
+ wl_surface_commit(pCtx->pointer_surface);
+}
+
+static void
+PointerHandleEnter(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ struct wl_surface* wlSurface, wl_fixed_t sx, wl_fixed_t sy)
+{
+ (void)wlPointer;
+ (void)serial;
+
+ struct wlContextCommon *pCtx = data;
+ pCtx->enter_serial = serial;
+ pCtx->enterSurface = wlSurface;
+ set_pointer_image(pCtx, 0);
+#ifdef _DEBUG
+ printf("ENTER PointerHandleEnter: x(%d), y(%d)\n", sx, sy);
+#endif
+}
+
+static void
+PointerHandleLeave(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ struct wl_surface* wlSurface)
+{
+ (void)wlPointer;
+ (void)wlSurface;
+
+ struct wlContextCommon *pCtx = data;
+ pCtx->enterSurface = NULL;
+
+#ifdef _DEBUG
+ printf("ENTER PointerHandleLeave: serial(%d)\n", serial);
+#endif
+}
+
+static void
+PointerHandleMotion(void* data, struct wl_pointer* wlPointer, uint32_t time,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ (void)data;
+ (void)wlPointer;
+ (void)time;
+
+#ifdef _DEBUG
+ printf("ENTER PointerHandleMotion: x(%d), y(%d)\n", gPointerX, gPointerY);
+#endif
+}
+
+/**
+ * if a surface assigned as launcher receives touch-off event, invoking
+ * ivi-application which configured in weston.ini with path to binary.
+ */
+extern char **environ; /*defied by libc */
+
+static pid_t execute_process(char* path, char *argv[])
+{
+ pid_t pid = fork();
+ if (pid < 0) {
+ fprintf(stderr, "Failed to fork\n");
+ }
+
+ if (pid) {
+ return pid;
+ }
+
+ if (-1 == execve(path, argv, environ)) {
+ fprintf(stderr, "Failed to execve %s\n", path);
+ exit(1);
+ }
+
+ return pid;
+}
+
+static int32_t
+launcher_button(uint32_t surfaceId, struct wl_list *launcher_list)
+{
+ struct hmi_homescreen_launcher *launcher = NULL;
+
+ wl_list_for_each(launcher, launcher_list, link) {
+ if (surfaceId != launcher->icon_surface_id) {
+ continue;
+ }
+
+ char *argv[] = {NULL};
+ execute_process(launcher->path, argv);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * is-method to identify a surface set as launcher in workspace or workspace
+ * itself. This is-method is used to decide whether request;
+ * ivi_hmi_controller_workspace_control is sent or not.
+ */
+static int32_t
+isWorkspaceSurface(uint32_t id, struct hmi_homescreen_setting *hmi_setting)
+{
+ if (id == hmi_setting->workspace_background.id) {
+ return 1;
+ }
+
+ struct hmi_homescreen_launcher *launcher = NULL;
+ wl_list_for_each(launcher, &hmi_setting->launcher_list, link) {
+ if (id == launcher->icon_surface_id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Decide which request is sent to hmi-controller
+ */
+static void
+touch_up(struct ivi_hmi_controller *hmi_ctrl, uint32_t id_surface,
+ int32_t *is_home_on, struct hmi_homescreen_setting* hmi_setting)
+{
+ if (launcher_button(id_surface, &hmi_setting->launcher_list)) {
+ *is_home_on = 0;
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ } else if (id_surface == hmi_setting->tiling.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING);
+ } else if (id_surface == hmi_setting->sidebyside.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE);
+ } else if (id_surface == hmi_setting->fullscreen.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN);
+ } else if (id_surface == hmi_setting->random.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM);
+ } else if (id_surface == hmi_setting->home.id) {
+ *is_home_on = !(*is_home_on);
+ if (*is_home_on) {
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_ON);
+ } else {
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ }
+ }
+}
+
+/**
+ * Even handler of Pointer event. IVI system is usually manipulated by touch
+ * screen. However, some systems also have pointer device.
+ * Release is the same behavior as touch off
+ * Pressed is the same behavior as touch on
+ */
+static void
+PointerHandleButton(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ uint32_t time, uint32_t button, uint32_t state)
+{
+ (void)wlPointer;
+ (void)serial;
+ (void)time;
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ if (BTN_RIGHT == button) {
+ return;
+ }
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ switch (state) {
+ case WL_POINTER_BUTTON_STATE_RELEASED:
+ touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, pCtx->hmi_setting);
+ break;
+
+ case WL_POINTER_BUTTON_STATE_PRESSED:
+
+ if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
+ ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, serial);
+ }
+
+ break;
+ }
+#ifdef _DEBUG
+ printf("ENTER PointerHandleButton: button(%d), state(%d)\n", button, state);
+#endif
+}
+
+static void
+PointerHandleAxis(void* data, struct wl_pointer* wlPointer, uint32_t time,
+ uint32_t axis, wl_fixed_t value)
+{
+ (void)data;
+ (void)wlPointer;
+ (void)time;
+#ifdef _DEBUG
+ printf("ENTER PointerHandleAxis: axis(%d), value(%d)\n", axis, value);
+#endif
+}
+
+static struct wl_pointer_listener pointer_listener = {
+ PointerHandleEnter,
+ PointerHandleLeave,
+ PointerHandleMotion,
+ PointerHandleButton,
+ PointerHandleAxis
+};
+
+/**
+ * Even handler of touch event
+ */
+static void
+TouchHandleDown(void *data, struct wl_touch *wlTouch, uint32_t serial, uint32_t time,
+ struct wl_surface *surface, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ if (0 == id){
+ pCtx->enterSurface = surface;
+ }
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * When touch down happens on surfaces of workspace, ask hmi-controller to start
+ * control workspace to select page of workspace.
+ * After sending seat to hmi-controller by ivi_hmi_controller_workspace_control,
+ * hmi-controller-homescreen doesn't receive any event till hmi-controller sends
+ * back it.
+ */
+ if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
+ ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, serial);
+ }
+}
+
+static void
+TouchHandleUp(void *data, struct wl_touch *wlTouch, uint32_t serial, uint32_t time,
+ int32_t id)
+{
+ (void)serial;
+ (void)time;
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * triggering event according to touch-up happening on which surface.
+ */
+ if (id == 0){
+ touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, pCtx->hmi_setting);
+ }
+}
+
+static void
+TouchHandleMotion(void *data, struct wl_touch *wlTouch, uint32_t time,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+}
+
+static void
+TouchHandleFrame(void *data, struct wl_touch *wlTouch)
+{
+}
+
+static void
+TouchHandleCancel(void *data, struct wl_touch *wlTouch)
+{
+}
+
+static struct wl_touch_listener touch_listener = {
+ TouchHandleDown,
+ TouchHandleUp,
+ TouchHandleMotion,
+ TouchHandleFrame,
+ TouchHandleCancel,
+};
+
+/**
+ * Handler of capabilities
+ */
+static void
+seat_handle_capabilities(void* data, struct wl_seat* seat, uint32_t caps)
+{
+ (void)seat;
+ struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
+ struct wl_seat* wlSeat = p_wlCtx->wlSeat;
+ struct wl_pointer* wlPointer = p_wlCtx->wlPointer;
+ struct wl_touch* wlTouch = p_wlCtx->wlTouch;
+
+ if (p_wlCtx->hmi_setting->cursor_theme) {
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wlPointer){
+ wlPointer = wl_seat_get_pointer(wlSeat);
+ wl_pointer_set_user_data(wlPointer, data);
+ wl_pointer_add_listener(wlPointer, &pointer_listener, data);
+ } else
+ if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wlPointer){
+ wl_pointer_destroy(wlPointer);
+ wlPointer = NULL;
+ }
+ p_wlCtx->wlPointer = wlPointer;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wlTouch){
+ wlTouch = wl_seat_get_touch(wlSeat);
+ wl_touch_set_user_data(wlTouch, data);
+ wl_touch_add_listener(wlTouch, &touch_listener, data);
+ } else
+ if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wlTouch){
+ wl_touch_destroy(wlTouch);
+ wlTouch = NULL;
+ }
+ p_wlCtx->wlTouch = wlTouch;
+}
+
+static struct wl_seat_listener seat_Listener = {
+ seat_handle_capabilities,
+};
+
+/**
+ * Registration of event
+ * This event is received when hmi-controller server finished controlling
+ * workspace.
+ */
+static void
+ivi_hmi_controller_workspace_end_control(void *data,
+ struct ivi_hmi_controller *hmi_ctrl,
+ int32_t is_controlled)
+{
+ if (is_controlled) {
+ return;
+ }
+
+ struct wlContextCommon *pCtx = data;
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * During being controlled by hmi-controller, any input event is not
+ * notified. So when control ends with touch up, it invokes launcher
+ * if up event happens on a launcher surface.
+ *
+ */
+ if (launcher_button(id_surface, &pCtx->hmi_setting->launcher_list)) {
+ pCtx->is_home_on = 0;
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ }
+}
+
+static const struct ivi_hmi_controller_listener hmi_controller_listener = {
+ ivi_hmi_controller_workspace_end_control
+};
+
+/**
+ * Registration of interfaces
+ */
+static void
+registry_handle_global(void* data, struct wl_registry* registry, uint32_t name,
+ const char *interface, uint32_t version)
+{
+ (void)version;
+ struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
+
+ do {
+ if (!strcmp(interface, "wl_compositor")) {
+ p_wlCtx->wlCompositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+ break;
+ }
+ if (!strcmp(interface, "wl_shm")) {
+ p_wlCtx->wlShm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
+ wl_shm_add_listener(p_wlCtx->wlShm, &shm_listenter, p_wlCtx);
+ break;
+ }
+ if (!strcmp(interface, "wl_seat")) {
+ p_wlCtx->wlSeat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
+ wl_seat_add_listener(p_wlCtx->wlSeat, &seat_Listener, data);
+ break;
+ }
+ if (!strcmp(interface, "ivi_application")) {
+ p_wlCtx->iviApplication = wl_registry_bind(registry, name, &ivi_application_interface, 1);
+ break;
+ }
+ if (!strcmp(interface, "ivi_hmi_controller")) {
+ p_wlCtx->hmiCtrl = wl_registry_bind(registry, name, &ivi_hmi_controller_interface, 1);
+
+ if (p_wlCtx->hmiCtrl) {
+ ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl, &hmi_controller_listener, p_wlCtx);
+ }
+ break;
+ }
+
+ } while(0);
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ NULL
+};
+
+static void
+frame_listener_func(void *data, struct wl_callback *callback, uint32_t time)
+{
+ if (callback) {
+ wl_callback_destroy(callback);
+ }
+}
+
+static const struct wl_callback_listener frame_listener = {
+ frame_listener_func
+};
+
+/*
+ * The following correspondences between file names and cursors was copied
+ * from: https://bugs.kde.org/attachment.cgi?id=67313
+ */
+static const char *bottom_left_corners[] = {
+ "bottom_left_corner",
+ "sw-resize",
+ "size_bdiag"
+};
+
+static const char *bottom_right_corners[] = {
+ "bottom_right_corner",
+ "se-resize",
+ "size_fdiag"
+};
+
+static const char *bottom_sides[] = {
+ "bottom_side",
+ "s-resize",
+ "size_ver"
+};
+
+static const char *grabbings[] = {
+ "grabbing",
+ "closedhand",
+ "208530c400c041818281048008011002"
+};
+
+static const char *left_ptrs[] = {
+ "left_ptr",
+ "default",
+ "top_left_arrow",
+ "left-arrow"
+};
+
+static const char *left_sides[] = {
+ "left_side",
+ "w-resize",
+ "size_hor"
+};
+
+static const char *right_sides[] = {
+ "right_side",
+ "e-resize",
+ "size_hor"
+};
+
+static const char *top_left_corners[] = {
+ "top_left_corner",
+ "nw-resize",
+ "size_fdiag"
+};
+
+static const char *top_right_corners[] = {
+ "top_right_corner",
+ "ne-resize",
+ "size_bdiag"
+};
+
+static const char *top_sides[] = {
+ "top_side",
+ "n-resize",
+ "size_ver"
+};
+
+static const char *xterms[] = {
+ "xterm",
+ "ibeam",
+ "text"
+};
+
+static const char *hand1s[] = {
+ "hand1",
+ "pointer",
+ "pointing_hand",
+ "e29285e634086352946a0e7090d73106"
+};
+
+static const char *watches[] = {
+ "watch",
+ "wait",
+ "0426c94ea35c87780ff01dc239897213"
+};
+
+struct cursor_alternatives {
+ const char **names;
+ size_t count;
+};
+
+static const struct cursor_alternatives cursors[] = {
+ {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
+ {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
+ {bottom_sides, ARRAY_LENGTH(bottom_sides)},
+ {grabbings, ARRAY_LENGTH(grabbings)},
+ {left_ptrs, ARRAY_LENGTH(left_ptrs)},
+ {left_sides, ARRAY_LENGTH(left_sides)},
+ {right_sides, ARRAY_LENGTH(right_sides)},
+ {top_left_corners, ARRAY_LENGTH(top_left_corners)},
+ {top_right_corners, ARRAY_LENGTH(top_right_corners)},
+ {top_sides, ARRAY_LENGTH(top_sides)},
+ {xterms, ARRAY_LENGTH(xterms)},
+ {hand1s, ARRAY_LENGTH(hand1s)},
+ {watches, ARRAY_LENGTH(watches)},
+};
+
+static void
+create_cursors(struct wlContextCommon *cmm)
+{
+ uint32_t i = 0;
+ uint32_t j = 0;
+ struct wl_cursor *cursor = NULL;
+ char* cursor_theme = cmm->hmi_setting->cursor_theme;
+ int32_t cursor_size = cmm->hmi_setting->cursor_size;
+
+ cmm->cursor_theme = wl_cursor_theme_load(cursor_theme, cursor_size, cmm->wlShm);
+
+ cmm->cursors = MEM_ALLOC(ARRAY_LENGTH(cursors) * sizeof(cmm->cursors[0]));
+
+ for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
+ cursor = NULL;
+
+ for (j = 0; !cursor && j < cursors[i].count; ++j) {
+ cursor = wl_cursor_theme_get_cursor(
+ cmm->cursor_theme, cursors[i].names[j]);
+ }
+
+ if (!cursor) {
+ fprintf(stderr, "could not load cursor '%s'\n",
+ cursors[i].names[0]);
+ }
+
+ cmm->cursors[i] = cursor;
+ }
+}
+
+static void
+destroy_cursors(struct wlContextCommon *cmm)
+{
+ if (cmm->cursor_theme) {
+ wl_cursor_theme_destroy(cmm->cursor_theme);
+ }
+
+ free(cmm->cursors);
+}
+
+/**
+ * Internal method to prepare parts of UI
+ */
+static void
+createShmBuffer(struct wlContextStruct *p_wlCtx)
+{
+ struct wl_shm_pool *pool;
+
+ char filename[] = "/tmp/wayland-shm-XXXXXX";
+ int fd = -1;
+ int size = 0;
+ int width = 0;
+ int height = 0;
+ int stride = 0;
+
+ fd = mkstemp(filename);
+ if (fd < 0) {
+ fprintf(stderr, "open %s failed: %m\n", filename);
+ return;
+ }
+
+ width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
+ height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
+ stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
+
+ size = stride * height;
+ if (ftruncate(fd, size) < 0) {
+ fprintf(stderr, "ftruncate failed: %m\n");
+ close(fd);
+ return;
+ }
+
+ p_wlCtx->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ if (MAP_FAILED == p_wlCtx->data) {
+ fprintf(stderr, "mmap failed: %m\n");
+ close(fd);
+ return;
+ }
+
+ pool = wl_shm_create_pool(p_wlCtx->cmm.wlShm, fd, size);
+ p_wlCtx->wlBuffer = wl_shm_pool_create_buffer(pool, 0,
+ width,
+ height,
+ stride,
+ WL_SHM_FORMAT_ARGB8888);
+
+ if (NULL == p_wlCtx->wlBuffer) {
+ fprintf(stderr, "wl_shm_create_buffer failed: %m\n");
+ close(fd);
+ return;
+ }
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ return;
+}
+
+static void
+destroyWLContextCommon(struct wlContextCommon *p_wlCtx)
+{
+ destroy_cursors(p_wlCtx);
+
+ if (p_wlCtx->pointer_surface) {
+ wl_surface_destroy(p_wlCtx->pointer_surface);
+ }
+
+ if (p_wlCtx->wlCompositor) {
+ wl_compositor_destroy(p_wlCtx->wlCompositor);
+ }
+}
+
+static void
+destroyWLContextStruct(struct wlContextStruct *p_wlCtx)
+{
+ if (p_wlCtx->wlSurface) {
+ wl_surface_destroy(p_wlCtx->wlSurface);
+ }
+
+ if (p_wlCtx->ctx_image) {
+ cairo_surface_destroy(p_wlCtx->ctx_image);
+ p_wlCtx->ctx_image = NULL;
+ }
+}
+
+static int
+createWLContext(struct wlContextStruct *p_wlCtx)
+{
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+
+ p_wlCtx->wlSurface = wl_compositor_create_surface(p_wlCtx->cmm.wlCompositor);
+ if (NULL == p_wlCtx->wlSurface) {
+ printf("Error: wl_compositor_create_surface failed.\n");
+ destroyWLContextCommon(&p_wlCtx->cmm);
+ abort();
+ }
+
+
+ createShmBuffer(p_wlCtx);
+
+ wl_display_flush(p_wlCtx->cmm.wlDisplay);
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+
+ return 0;
+}
+
+static void
+drawImage(struct wlContextStruct *p_wlCtx)
+{
+ struct wl_callback *callback;
+
+ int width = 0;
+ int height = 0;
+ int stride = 0;
+ void *data = NULL;
+
+ width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
+ height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
+ stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
+ data = cairo_image_surface_get_data(p_wlCtx->ctx_image);
+
+ memcpy(p_wlCtx->data, data, stride * height);
+
+ wl_surface_attach(p_wlCtx->wlSurface, p_wlCtx->wlBuffer, 0, 0);
+ wl_surface_damage(p_wlCtx->wlSurface, 0, 0, width, height);
+
+ callback = wl_surface_frame(p_wlCtx->wlSurface);
+ wl_callback_add_listener(callback, &frame_listener, NULL);
+
+ wl_surface_commit(p_wlCtx->wlSurface);
+
+ wl_display_flush(p_wlCtx->cmm.wlDisplay);
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+}
+
+static void
+create_ivisurface(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ cairo_surface_t* surface)
+{
+ struct ivi_surface *ivisurf = NULL;
+
+ p_wlCtx->ctx_image = surface;
+
+ p_wlCtx->id_surface = id_surface;
+ wl_list_init(&p_wlCtx->link);
+ wl_list_insert(p_wlCtx->cmm.list_wlContextStruct, &p_wlCtx->link);
+
+ createWLContext(p_wlCtx);
+
+ ivisurf = ivi_application_surface_create(p_wlCtx->cmm.iviApplication,
+ id_surface, p_wlCtx->wlSurface);
+ if (ivisurf == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ return;
+ }
+
+ drawImage(p_wlCtx);
+
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+}
+
+static void
+create_ivisurfaceFromFile(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ const char* imageFile)
+{
+ cairo_surface_t* surface = load_cairo_surface(imageFile);
+
+ if (NULL == surface) {
+ fprintf(stderr, "Failed to load_cairo_surface %s\n", imageFile);
+ return;
+ }
+
+ create_ivisurface(p_wlCtx, id_surface, surface);
+}
+
+static void
+set_hex_color(cairo_t *cr, uint32_t color)
+{
+ cairo_set_source_rgba(cr,
+ ((color >> 16) & 0xff) / 255.0,
+ ((color >> 8) & 0xff) / 255.0,
+ ((color >> 0) & 0xff) / 255.0,
+ ((color >> 24) & 0xff) / 255.0);
+}
+
+static void
+create_ivisurfaceFromColor(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ uint32_t width, uint32_t height,
+ uint32_t color)
+{
+ cairo_surface_t *surface = NULL;
+ cairo_t *cr = NULL;
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+
+ cr = cairo_create(surface);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle(cr, 0, 0, width, height);
+ set_hex_color(cr, color);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+
+ create_ivisurface(p_wlCtx, id_surface, surface);
+}
+
+/**
+ * Internal method to set up UI by using ivi-hmi-controller
+ */
+static void
+create_background(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_background(p_wlCtx->cmm.hmiCtrl, id_surface);
+}
+
+static void
+create_panel(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_panel(p_wlCtx->cmm.hmiCtrl, id_surface);
+}
+
+static void
+create_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile, uint32_t number)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_button(p_wlCtx->cmm.hmiCtrl, id_surface, number);
+}
+
+static void
+create_home_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_home_button(p_wlCtx->cmm.hmiCtrl, id_surface);
+}
+
+static void
+create_workspace_background(
+ struct wlContextStruct *p_wlCtx, struct hmi_homescreen_srf *srf)
+{
+ create_ivisurfaceFromColor(p_wlCtx, srf->id, 1, 1, srf->color);
+ ivi_hmi_controller_set_workspacebackground(p_wlCtx->cmm.hmiCtrl, srf->id);
+}
+
+static int compare_launcher(const void* data1, const void* data2)
+{
+ struct hmi_homescreen_launcher *launcher1 = *(struct hmi_homescreen_launcher**)data1;
+ struct hmi_homescreen_launcher *launcher2 = *(struct hmi_homescreen_launcher**)data2;
+ return launcher1->workspace_id - launcher2->workspace_id;
+}
+
+static void
+create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list)
+{
+ int launcher_count = wl_list_length(launcher_list);
+
+ if (0 == launcher_count) {
+ return;
+ }
+
+ struct hmi_homescreen_launcher** launchers;
+ launchers = MEM_ALLOC(launcher_count * sizeof(*launchers));
+
+ int ii = 0;
+ struct hmi_homescreen_launcher *launcher = NULL;
+
+ wl_list_for_each(launcher, launcher_list, link) {
+ launchers[ii] = launcher;
+ ii++;
+ }
+
+ qsort(launchers, launcher_count, sizeof(*launchers), compare_launcher);
+
+ int start = 0;
+
+ for (ii = 0; ii < launcher_count; ii++) {
+
+ if (ii != launcher_count -1 &&
+ launchers[ii]->workspace_id == launchers[ii + 1]->workspace_id) {
+ continue;
+ }
+
+ struct wl_array surface_ids;
+ wl_array_init(&surface_ids);
+
+ int jj = 0;
+ for (jj = start; jj <= ii; jj++) {
+ uint32_t *id = wl_array_add(&surface_ids, sizeof(*id));
+ *id = launchers[jj]->icon_surface_id;
+
+ struct wlContextStruct *p_wlCtx = MEM_ALLOC(sizeof(*p_wlCtx));
+ p_wlCtx->cmm = *cmm;
+
+ create_ivisurfaceFromFile(p_wlCtx, *id, launchers[jj]->icon);
+ }
+
+ ivi_hmi_controller_add_launchers(cmm->hmiCtrl, &surface_ids, 256);
+ wl_array_release(&surface_ids);
+ start = ii + 1;
+ }
+
+ free(launchers);
+}
+
+static void sigFunc(int signum)
+{
+ gRun = 0;
+}
+
+/**
+ * Internal method to read out weston.ini to get configuration
+ */
+static struct hmi_homescreen_setting*
+hmi_homescreen_setting_create(void)
+{
+ struct hmi_homescreen_setting* setting = MEM_ALLOC(sizeof(*setting));
+
+ wl_list_init(&setting->workspace_list);
+ wl_list_init(&setting->launcher_list);
+
+ struct weston_config *config = NULL;
+ config = weston_config_parse("weston.ini");
+
+ struct weston_config_section *shellSection = NULL;
+ shellSection = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ weston_config_section_get_string(
+ shellSection, "cursor-theme", &setting->cursor_theme, NULL);
+
+ weston_config_section_get_int(shellSection, "cursor-size", &setting->cursor_size, 32);
+
+ uint32_t workspace_layer_id;
+ weston_config_section_get_uint(
+ shellSection, "workspace-layer-id", &workspace_layer_id, 3000);
+
+ weston_config_section_get_string(
+ shellSection, "background-image", &setting->background.filePath,
+ DATADIR "/weston/background.png");
+
+ weston_config_section_get_uint(
+ shellSection, "background-id", &setting->background.id, 1001);
+
+ weston_config_section_get_string(
+ shellSection, "panel-image", &setting->panel.filePath,
+ DATADIR "/weston/panel.png");
+
+ weston_config_section_get_uint(
+ shellSection, "panel-id", &setting->panel.id, 1002);
+
+ weston_config_section_get_string(
+ shellSection, "tiling-image", &setting->tiling.filePath,
+ DATADIR "/weston/tiling.png");
+
+ weston_config_section_get_uint(
+ shellSection, "tiling-id", &setting->tiling.id, 1003);
+
+ weston_config_section_get_string(
+ shellSection, "sidebyside-image", &setting->sidebyside.filePath,
+ DATADIR "/weston/sidebyside.png");
+
+ weston_config_section_get_uint(
+ shellSection, "sidebyside-id", &setting->sidebyside.id, 1004);
+
+ weston_config_section_get_string(
+ shellSection, "fullscreen-image", &setting->fullscreen.filePath,
+ DATADIR "/weston/fullscreen.png");
+
+ weston_config_section_get_uint(
+ shellSection, "fullscreen-id", &setting->fullscreen.id, 1005);
+
+ weston_config_section_get_string(
+ shellSection, "random-image", &setting->random.filePath,
+ DATADIR "/weston/random.png");
+
+ weston_config_section_get_uint(
+ shellSection, "random-id", &setting->random.id, 1006);
+
+ weston_config_section_get_string(
+ shellSection, "home-image", &setting->home.filePath,
+ DATADIR "/weston/home.png");
+
+ weston_config_section_get_uint(
+ shellSection, "home-id", &setting->home.id, 1007);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-color",
+ &setting->workspace_background.color, 0x99000000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-id",
+ &setting->workspace_background.id, 2001);
+
+ struct weston_config_section *section = NULL;
+ const char *name = NULL;
+
+ uint32_t icon_surface_id = workspace_layer_id + 1;
+
+ while (weston_config_next_section(config, &section, &name)) {
+
+ if (0 == strcmp(name, "ivi-launcher")) {
+
+ struct hmi_homescreen_launcher *launcher = NULL;
+ launcher = MEM_ALLOC(sizeof(*launcher));
+ wl_list_init(&launcher->link);
+ launcher->icon_surface_id = icon_surface_id;
+ icon_surface_id++;
+
+ weston_config_section_get_string(section, "icon", &launcher->icon, NULL);
+ weston_config_section_get_string(section, "path", &launcher->path, NULL);
+ weston_config_section_get_uint(section, "workspace-id", &launcher->workspace_id, 0);
+
+ wl_list_insert(setting->launcher_list.prev, &launcher->link);
+ }
+ }
+
+ weston_config_destroy(config);
+ return setting;
+}
+
+/**
+ * Main thread
+ *
+ * The basic flow are as followed,
+ * 1/ read configuration from weston.ini by hmi_homescreen_setting_create
+ * 2/ draw png file to surface according to configuration of weston.ini and
+ * set up UI by using ivi-hmi-controller protocol by each create_* method
+ */
+static void*
+client_thread(void *p_ret)
+{
+ struct wlContextCommon wlCtxCommon;
+ struct wlContextStruct wlCtx_BackGround;
+ struct wlContextStruct wlCtx_Panel;
+ struct wlContextStruct wlCtx_Button_1;
+ struct wlContextStruct wlCtx_Button_2;
+ struct wlContextStruct wlCtx_Button_3;
+ struct wlContextStruct wlCtx_Button_4;
+ struct wlContextStruct wlCtx_HomeButton;
+ struct wlContextStruct wlCtx_WorkSpaceBackGround;
+ struct wl_list launcher_wlCtxList;
+
+ memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon));
+ memset(&wlCtx_BackGround, 0x00, sizeof(wlCtx_BackGround));
+ memset(&wlCtx_Panel, 0x00, sizeof(wlCtx_Panel));
+ memset(&wlCtx_Button_1, 0x00, sizeof(wlCtx_Button_1));
+ memset(&wlCtx_Button_2, 0x00, sizeof(wlCtx_Button_2));
+ memset(&wlCtx_Button_3, 0x00, sizeof(wlCtx_Button_3));
+ memset(&wlCtx_Button_4, 0x00, sizeof(wlCtx_Button_4));
+ memset(&wlCtx_HomeButton, 0x00, sizeof(wlCtx_HomeButton));
+ memset(&wlCtx_WorkSpaceBackGround, 0x00, sizeof(wlCtx_WorkSpaceBackGround));
+ wl_list_init(&launcher_wlCtxList);
+ wlCtxCommon.list_wlContextStruct = MEM_ALLOC(sizeof(struct wl_list));
+ assert(wlCtxCommon.list_wlContextStruct);
+ wl_list_init(wlCtxCommon.list_wlContextStruct);
+
+ struct hmi_homescreen_setting *hmi_setting = hmi_homescreen_setting_create();
+ wlCtxCommon.hmi_setting = hmi_setting;
+
+ gRun = 1;
+
+ wlCtxCommon.wlDisplay = wl_display_connect(NULL);
+ if (NULL == wlCtxCommon.wlDisplay) {
+ printf("Error: wl_display_connect failed.\n");
+ return NULL;
+ }
+
+ /* get wl_registry */
+ wlCtxCommon.wlRegistry = wl_display_get_registry(wlCtxCommon.wlDisplay);
+ wl_registry_add_listener(wlCtxCommon.wlRegistry,
+ &registry_listener, &wlCtxCommon);
+ wl_display_dispatch(wlCtxCommon.wlDisplay);
+ wl_display_roundtrip(wlCtxCommon.wlDisplay);
+
+ if (wlCtxCommon.hmi_setting->cursor_theme) {
+ create_cursors(&wlCtxCommon);
+
+ wlCtxCommon.pointer_surface =
+ wl_compositor_create_surface(wlCtxCommon.wlCompositor);
+
+ wlCtxCommon.current_cursor = CURSOR_LEFT_PTR;
+ }
+
+ wlCtx_BackGround.cmm = wlCtxCommon;
+ wlCtx_Panel.cmm = wlCtxCommon;
+ wlCtx_Button_1.cmm = wlCtxCommon;
+ wlCtx_Button_2.cmm = wlCtxCommon;
+ wlCtx_Button_3.cmm = wlCtxCommon;
+ wlCtx_Button_4.cmm = wlCtxCommon;
+ wlCtx_HomeButton.cmm = wlCtxCommon;
+ wlCtx_WorkSpaceBackGround.cmm = wlCtxCommon;
+
+ /* create desktop widgets */
+ create_background(&wlCtx_BackGround, hmi_setting->background.id,
+ hmi_setting->background.filePath);
+
+ create_panel(&wlCtx_Panel, hmi_setting->panel.id,
+ hmi_setting->panel.filePath);
+
+ create_button(&wlCtx_Button_1, hmi_setting->tiling.id,
+ hmi_setting->tiling.filePath, 0);
+
+ create_button(&wlCtx_Button_2, hmi_setting->sidebyside.id,
+ hmi_setting->sidebyside.filePath, 1);
+
+ create_button(&wlCtx_Button_3, hmi_setting->fullscreen.id,
+ hmi_setting->fullscreen.filePath, 2);
+
+ create_button(&wlCtx_Button_4, hmi_setting->random.id,
+ hmi_setting->random.filePath, 3);
+
+ create_workspace_background(&wlCtx_WorkSpaceBackGround,
+ &hmi_setting->workspace_background);
+
+ create_launchers(&wlCtxCommon, &hmi_setting->launcher_list);
+
+ create_home_button(&wlCtx_HomeButton, hmi_setting->home.id,
+ hmi_setting->home.filePath);
+ /* signal handling */
+ signal(SIGINT, sigFunc);
+ signal(SIGKILL, sigFunc);
+
+ while(gRun) {
+ wl_display_roundtrip(wlCtxCommon.wlDisplay);
+ usleep(5000);
+ }
+
+ struct wlContextStruct* pWlCtxSt = NULL;
+ wl_list_for_each(pWlCtxSt, wlCtxCommon.list_wlContextStruct, link) {
+ destroyWLContextStruct(pWlCtxSt);
+ }
+
+ destroyWLContextCommon(&wlCtxCommon);
+ free(wlCtxCommon.list_wlContextStruct);
+
+ return NULL;
+}
+
+/*****************************************************************************
+ * exported functions
+ ****************************************************************************/
+int
+hmi_client_start(void)
+{
+ pthread_attr_t thread_attrs;
+ uint32_t ret = 0;
+ pthread_t thread;
+
+ pthread_attr_init(&thread_attrs);
+ pthread_attr_setdetachstate(&thread_attrs, PTHREAD_CREATE_JOINABLE);
+ ret = pthread_create(&thread, &thread_attrs, client_thread, NULL);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to start internal receive \
+ thread. returned %d\n", ret);
+ }
+
+ return 0;
+}
diff --git a/ivi-shell/hmi-controller-homescreen.h b/ivi-shell/hmi-controller-homescreen.h
new file mode 100644
index 0000000..31416de
--- /dev/null
+++ b/ivi-shell/hmi-controller-homescreen.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _HMI_CONTROLLER_HOMESCREEN_H_
+#define _HMI_CONTROLLER_HOMESCREEN_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+int hmi_client_start(void);
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _HMI_CONTROLLER_HOMESCREEN_H_ */
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 10:03:53 UTC
Permalink
to build references;ivi-hmi-controller protocol, hmi-controller,
and hmi-controller-homescreen.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
ivi-shell/.gitignore | 7 +++++++
ivi-shell/Makefile.am | 21 +++++++++++++++++++--
2 files changed, 26 insertions(+), 2 deletions(-)
create mode 100644 ivi-shell/.gitignore

diff --git a/ivi-shell/.gitignore b/ivi-shell/.gitignore
new file mode 100644
index 0000000..9f31bfd
--- /dev/null
+++ b/ivi-shell/.gitignore
@@ -0,0 +1,7 @@
+ivi-application-client-protocol.h
+ivi-application-protocol.c
+ivi-application-server-protocol.h
+ivi-hmi-controller-client-protocol.h
+ivi-hmi-controller-protocol.c
+ivi-hmi-controller-server-protocol.h
+weston.ini
diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
index d0c0d62..afaa5e3 100644
--- a/ivi-shell/Makefile.am
+++ b/ivi-shell/Makefile.am
@@ -2,7 +2,8 @@ moduledir = $(libdir)/weston

module_LTLIBRARIES = \
$(libweston_layout) \
- $(ivi_shell)
+ $(ivi_shell) \
+ $(hmi_controller)

AM_CPPFLAGS = \
-I$(top_srcdir)/shared \
@@ -39,12 +40,28 @@ ivi_shell_la_SOURCES = \
ivi-application-protocol.c \
ivi-application-server-protocol.h

+hmi_controller = hmi-controller.la
+hmi_controller_la_LDFLAGS = -module -avoid-version
+hmi_controller_la_LIBADD = $(CLIENT_LIBS) $(IVI_SHELL_LIBS) ./libweston-layout.la ../shared/libshared-cairo.la
+hmi_controller_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
+hmi_controller_la_SOURCES = \
+ hmi-controller.c \
+ hmi-controller-homescreen.h \
+ hmi-controller-homescreen.c \
+ ivi-application-protocol.c \
+ ivi-application-client-protocol.h \
+ ivi-hmi-controller-protocol.c \
+ ivi-hmi-controller-client-protocol.h \
+ ivi-hmi-controller-server-protocol.h
endif

BUILT_SOURCES = \
ivi-application-protocol.c \
ivi-application-server-protocol.h \
- ivi-application-client-protocol.h
+ ivi-application-client-protocol.h \
+ ivi-hmi-controller-protocol.c \
+ ivi-hmi-controller-client-protocol.h \
+ ivi-hmi-controller-server-protocol.h

CLEANFILES = $(BUILT_SOURCES)

--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 10:05:35 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
data/Makefile.am | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/data/Makefile.am b/data/Makefile.am
index a7cc944..2aa6e5c 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -9,7 +9,19 @@ dist_westondata_DATA = \
icon_window.png \
sign_close.png \
sign_maximize.png \
- sign_minimize.png
+ sign_minimize.png \
+ background.png \
+ tiling.png \
+ fullscreen.png \
+ panel.png \
+ random.png \
+ sidebyside.png \
+ home.png \
+ icon_ivi_clickdot.png \
+ icon_ivi_flower.png \
+ icon_ivi_simple-egl.png \
+ icon_ivi_simple-shm.png \
+ icon_ivi_smoke.png

if HAVE_RSVG_CONVERT
wayland_icon_png = wayland.png
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 10:06:13 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
ivi-shell/Makefile.am | 12 ++++++++
ivi-shell/weston.ini.in | 79 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+)
create mode 100644 ivi-shell/weston.ini.in

diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
index afaa5e3..333abb7 100644
--- a/ivi-shell/Makefile.am
+++ b/ivi-shell/Makefile.am
@@ -67,3 +67,15 @@ CLEANFILES = $(BUILT_SOURCES)

wayland_protocoldir = $(top_srcdir)/protocol
include $(top_srcdir)/wayland-scanner.mk
+
+
+weston.ini : $(srcdir)/weston.ini.in
+ $(AM_V_GEN)$(SED) \
+ -e 's|@bindir[@]|$(bindir)|g' \
+ -e 's|@abs_top_builddir[@]|$(abs_top_builddir)|g' \
+ -e 's|@libexecdir[@]|$(libexecdir)|g' \
+ $< > $@
+
+all-local : weston.ini
+
+CLEANFILES += weston.ini
diff --git a/ivi-shell/weston.ini.in b/ivi-shell/weston.ini.in
new file mode 100644
index 0000000..c9a6861
--- /dev/null
+++ b/ivi-shell/weston.ini.in
@@ -0,0 +1,79 @@
+[core]
+shell=ivi-shell.so
+modules=hmi-controller.so
+
+[ivi-shell]
+cursor-theme=default
+cursor-size=32
+
+base-layer-id=1000
+workspace-background-layer-id=2000
+workspace-layer-id=3000
+application-layer-id=4000
+
+background-image=@abs_top_builddir@/data/background.png
+background-id=1001
+panel-image=@abs_top_builddir@/data/panel.png
+panel-id=1002
+tiling-image=@abs_top_builddir@/data/tiling.png
+tiling-id=1003
+sidebyside-image=@abs_top_builddir@/data/sidebyside.png
+sidebyside-id=1004
+fullscreen-image=@abs_top_builddir@/data/fullscreen.png
+fullscreen-id=1005
+random-image=@abs_top_builddir@/data/random.png
+random-id=1006
+home-image=@abs_top_builddir@/data/home.png
+home-id=1007
+workspace-background-color=0x99000000
+workspace-background-id=2001
+
+[ivi-launcher]
+workspace-id=0
+icon=@abs_top_builddir@/data/icon_ivi_flower.png
+path=@abs_top_builddir@/clients/weston-flower-ivi
+
+[ivi-launcher]
+workspace-id=0
+icon=@abs_top_builddir@/data/icon_ivi_clickdot.png
+path=@abs_top_builddir@/clients/weston-clickdot-ivi
+
+[ivi-launcher]
+workspace-id=1
+icon=@abs_top_builddir@/data/icon_ivi_simple-egl.png
+path=@abs_top_builddir@/clients/weston-simple-egl-ivi
+
+[ivi-launcher]
+workspace-id=1
+icon=@abs_top_builddir@/data/icon_ivi_simple-shm.png
+path=@abs_top_builddir@/clients/weston-simple-shm-ivi
+
+[ivi-launcher]
+workspace-id=2
+icon=@abs_top_builddir@/data/icon_ivi_smoke.png
+path=@abs_top_builddir@/clients/weston-smoke-ivi
+
+[ivi-launcher]
+workspace-id=3
+icon=@abs_top_builddir@/data/icon_ivi_flower.png
+path=@abs_top_builddir@/clients/weston-flower-ivi
+
+[ivi-launcher]
+workspace-id=3
+icon=@abs_top_builddir@/data/icon_ivi_clickdot.png
+path=@abs_top_builddir@/clients/weston-clickdot-ivi
+
+[ivi-launcher]
+workspace-id=3
+icon=@abs_top_builddir@/data/icon_ivi_simple-egl.png
+path=@abs_top_builddir@/clients/weston-simple-egl-ivi
+
+[ivi-launcher]
+workspace-id=3
+icon=@abs_top_builddir@/data/icon_ivi_simple-shm.png
+path=@abs_top_builddir@/clients/weston-simple-shm-ivi
+
+[ivi-launcher]
+workspace-id=3
+icon=@abs_top_builddir@/data/icon_ivi_smoke.png
+path=@abs_top_builddir@/clients/weston-smoke-ivi
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 10:07:10 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
clients/.gitignore | 5 ++++
clients/Makefile.am | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
clients/simple-egl.c | 67 ++++++++++++++++++++++++++++++++++++++++++++--------
clients/simple-shm.c | 50 ++++++++++++++++++++++++++++++++++-----
clients/window.c | 42 ++++++++++++++++++++++++++++++--
5 files changed, 211 insertions(+), 18 deletions(-)

diff --git a/clients/.gitignore b/clients/.gitignore
index d23027c..41b3be3 100644
--- a/clients/.gitignore
+++ b/clients/.gitignore
@@ -20,6 +20,11 @@ weston-stacking
weston-subsurfaces
weston-transformed
weston-view
+weston-clickdot-ivi
+weston-flower-ivi
+weston-simple-egl-ivi
+weston-simple-shm-ivi
+weston-smoke-ivi

desktop-shell-client-protocol.h
desktop-shell-protocol.c
diff --git a/clients/Makefile.am b/clients/Makefile.am
index 4f8d4a6..4bbacb3 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -7,6 +7,11 @@ demo_clients = \
$(simple_clients_programs) \
$(simple_egl_clients_programs)

+if ENABLE_IVI_SHELL
+demo_clients += \
+ $(ivi_shell_clients_programs)
+endif
+
if INSTALL_DEMO_CLIENTS
bin_PROGRAMS += $(demo_clients)
else
@@ -246,6 +251,66 @@ endif

endif

+if ENABLE_IVI_SHELL
+noinst_LTLIBRARIES = libivitoytoolkit.la
+
+libivitoytoolkit_la_SOURCES = \
+ window.c \
+ window.h \
+ text-cursor-position-protocol.c \
+ text-cursor-position-client-protocol.h \
+ scaler-protocol.c \
+ scaler-client-protocol.h \
+ workspaces-protocol.c \
+ workspaces-client-protocol.h
+
+libivitoytoolkit_la_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+
+libivitoytoolkit_la_LIBADD = \
+ $(CLIENT_LIBS) \
+ $(CAIRO_EGL_LIBS) \
+ ../shared/libshared-cairo.la -lrt -lm
+
+ivi_shell_clients_programs = \
+ weston-simple-egl-ivi \
+ weston-simple-shm-ivi \
+ weston-flower-ivi \
+ weston-smoke-ivi \
+ weston-clickdot-ivi
+
+weston_simple_egl_ivi_SOURCES = simple-egl.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_simple_egl_ivi_CPPFLAGS = $(SIMPLE_EGL_CLIENT_CFLAGS) -DENABLE_IVI_CLIENT
+weston_simple_egl_ivi_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
+
+weston_simple_shm_ivi_SOURCES = simple-shm.c \
+ ../shared/os-compatibility.c \
+ ../shared/os-compatibility.h \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_simple_shm_ivi_CPPFLAGS = $(SIMPLE_CLIENT_CFLAGS) -DENABLE_IVI_CLIENT
+weston_simple_shm_ivi_LDADD = $(SIMPLE_CLIENT_LIBS)
+
+weston_flower_ivi_SOURCES = flower.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_flower_ivi_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+weston_flower_ivi_LDADD = libivitoytoolkit.la
+
+weston_smoke_ivi_SOURCES = smoke.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_smoke_ivi_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+weston_smoke_ivi_LDADD = libivitoytoolkit.la
+
+weston_clickdot_ivi_SOURCES = clickdot.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_clickdot_ivi_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+weston_clickdot_ivi_LDADD = libivitoytoolkit.la
+endif
+
wayland_protocoldir = $(top_srcdir)/protocol
include $(top_srcdir)/wayland-scanner.mk

diff --git a/clients/simple-egl.c b/clients/simple-egl.c
index 2c009ee..b06742f 100644
--- a/clients/simple-egl.c
+++ b/clients/simple-egl.c
@@ -38,6 +38,13 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>

+#ifdef ENABLE_IVI_CLIENT
+#include <sys/types.h>
+#include <unistd.h>
+#include "../ivi-shell/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+#endif
+
#ifndef EGL_EXT_swap_buffers_with_damage
#define EGL_EXT_swap_buffers_with_damage 1
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
@@ -70,6 +77,9 @@ struct display {
EGLConfig conf;
} egl;
struct window *window;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_application *ivi_application;
+#endif

PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
};
@@ -91,6 +101,9 @@ struct window {
struct wl_egl_window *native;
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_surface *ivi_surface;
+#endif
EGLSurface egl_surface;
struct wl_callback *callback;
int fullscreen, configured, opaque, buffer_size, frame_sync;
@@ -250,7 +263,7 @@ init_gl(struct window *window)
}

glUseProgram(program);
-
+
window->gl.pos = 0;
window->gl.col = 1;

@@ -318,6 +331,12 @@ set_fullscreen(struct window *window, int fullscreen)
window->fullscreen = fullscreen;
window->configured = 0;

+ if (!window->shell_surface) {
+ handle_configure(window, NULL, 0, 250, 250);
+ window->configured = 1;
+ return;
+ }
+
if (fullscreen) {
wl_shell_surface_set_fullscreen(window->shell_surface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
@@ -341,13 +360,15 @@ create_surface(struct window *window)
{
struct display *display = window->display;
EGLBoolean ret;
-
+
window->surface = wl_compositor_create_surface(display->compositor);
- window->shell_surface = wl_shell_get_shell_surface(display->shell,
- window->surface);
+ if (display->shell)
+ window->shell_surface = wl_shell_get_shell_surface(display->shell,
+ window->surface);

- wl_shell_surface_add_listener(window->shell_surface,
- &shell_surface_listener, window);
+ if (window->shell_surface)
+ wl_shell_surface_add_listener(window->shell_surface,
+ &shell_surface_listener, window);

window->native =
wl_egl_window_create(window->surface,
@@ -357,8 +378,18 @@ create_surface(struct window *window)
eglCreateWindowSurface(display->egl.dpy,
display->egl.conf,
window->native, NULL);
+#ifdef ENABLE_IVI_CLIENT
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ window->ivi_surface = ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ if (window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+#endif

- wl_shell_surface_set_title(window->shell_surface, "simple-egl");
+ if (window->shell_surface)
+ wl_shell_surface_set_title(window->shell_surface, "simple-egl");

ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
window->egl_surface, window->display->egl.ctx);
@@ -381,7 +412,8 @@ destroy_surface(struct window *window)
eglDestroySurface(window->display->egl.dpy, window->egl_surface);
wl_egl_window_destroy(window->native);

- wl_shell_surface_destroy(window->shell_surface);
+ if (window->shell_surface)
+ wl_shell_surface_destroy(window->shell_surface);
wl_surface_destroy(window->surface);

if (window->callback)
@@ -542,7 +574,8 @@ pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
{
struct display *display = data;

- if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
+ if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED &&
+ display->window->shell_surface)
wl_shell_surface_move(display->window->shell_surface,
display->seat, serial);
}
@@ -568,7 +601,8 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
{
struct display *d = (struct display *)data;

- wl_shell_surface_move(d->window->shell_surface, d->seat, serial);
+ if (d->window->shell_surface)
+ wl_shell_surface_move(d->window->shell_surface, d->seat, serial);
}

static void
@@ -709,6 +743,11 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->default_cursor =
wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
}
+#ifdef ENABLE_IVI_CLIENT
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application = wl_registry_bind(registry, name, &ivi_application_interface, 1);
+ }
+#endif
}

static void
@@ -805,6 +844,11 @@ main(int argc, char **argv)

fprintf(stderr, "simple-egl exiting\n");

+#ifdef ENABLE_IVI_CLIENT
+ ivi_surface_destroy(window.ivi_surface);
+ ivi_application_destroy(window.display->ivi_application);
+#endif
+
destroy_surface(&window);
fini_egl(&display);

@@ -819,6 +863,9 @@ main(int argc, char **argv)
wl_compositor_destroy(display.compositor);

wl_registry_destroy(display.registry);
+#ifdef ENABLE_IVI_CLIENT
+ wl_display_roundtrip(display.display);
+#endif
wl_display_flush(display.display);
wl_display_disconnect(display.display);

diff --git a/clients/simple-shm.c b/clients/simple-shm.c
index 81bb54e..10acf5d 100644
--- a/clients/simple-shm.c
+++ b/clients/simple-shm.c
@@ -35,6 +35,12 @@
#include <wayland-client.h>
#include "../shared/os-compatibility.h"

+#ifdef ENABLE_IVI_CLIENT
+#include <sys/types.h>
+#include "../ivi-shell/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+#endif
+
struct display {
struct wl_display *display;
struct wl_registry *registry;
@@ -42,6 +48,9 @@ struct display {
struct wl_shell *shell;
struct wl_shm *shm;
uint32_t formats;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_application *ivi_application;
+#endif
};

struct buffer {
@@ -55,6 +64,9 @@ struct window {
int width, height;
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_surface *ivi_surface;
+#endif
struct buffer buffers[2];
struct buffer *prev_buffer;
struct wl_callback *callback;
@@ -148,16 +160,29 @@ create_window(struct display *display, int width, int height)
window->width = width;
window->height = height;
window->surface = wl_compositor_create_surface(display->compositor);
- window->shell_surface = wl_shell_get_shell_surface(display->shell,
- window->surface);
+ if (display->shell)
+ window->shell_surface = wl_shell_get_shell_surface(display->shell,
+ window->surface);

if (window->shell_surface)
wl_shell_surface_add_listener(window->shell_surface,
&shell_surface_listener, window);

- wl_shell_surface_set_title(window->shell_surface, "simple-shm");
+#ifdef ENABLE_IVI_CLIENT
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ window->ivi_surface = ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ if (window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+#endif

- wl_shell_surface_set_toplevel(window->shell_surface);
+ if (window->shell_surface) {
+ wl_shell_surface_set_title(window->shell_surface, "simple-shm");
+
+ wl_shell_surface_set_toplevel(window->shell_surface);
+ }

return window;
}
@@ -173,7 +198,8 @@ destroy_window(struct window *window)
if (window->buffers[1].buffer)
wl_buffer_destroy(window->buffers[1].buffer);

- wl_shell_surface_destroy(window->shell_surface);
+ if (window->shell_surface)
+ wl_shell_surface_destroy(window->shell_surface);
wl_surface_destroy(window->surface);
free(window);
}
@@ -318,6 +344,11 @@ registry_handle_global(void *data, struct wl_registry *registry,
id, &wl_shm_interface, 1);
wl_shm_add_listener(d->shm, &shm_listener, d);
}
+#ifdef ENABLE_IVI_CLIENT
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application = wl_registry_bind(registry, id, &ivi_application_interface, 1);
+ }
+#endif
}

static void
@@ -362,7 +393,7 @@ create_display(void)
}

wl_display_get_fd(display->display);
-
+
return display;
}

@@ -379,6 +410,9 @@ destroy_display(struct display *display)
wl_compositor_destroy(display->compositor);

wl_registry_destroy(display->registry);
+#ifdef ENABLE_IVI_CLIENT
+ wl_display_roundtrip(display->display);
+#endif
wl_display_flush(display->display);
wl_display_disconnect(display->display);
free(display);
@@ -420,6 +454,10 @@ main(int argc, char **argv)
ret = wl_display_dispatch(display->display);

fprintf(stderr, "simple-shm exiting\n");
+#ifdef ENABLE_IVI_CLIENT
+ ivi_surface_destroy(window->ivi_surface);
+ ivi_application_destroy(window->display->ivi_application);
+#endif
destroy_window(window);
destroy_display(display);

diff --git a/clients/window.c b/clients/window.c
index d8d79d0..928e405 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -71,6 +71,12 @@ typedef void *EGLContext;

#include "window.h"

+#ifdef ENABLE_IVI_CLIENT
+#include <sys/types.h>
+#include "../ivi-shell/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+#endif
+
struct shm_pool;

struct global {
@@ -132,6 +138,9 @@ struct display {

int has_rgb565;
int seat_version;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_application *ivi_application;
+#endif
};

enum {
@@ -252,6 +261,9 @@ struct window {

struct surface *main_surface;
struct wl_shell_surface *shell_surface;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_surface *ivi_surface;
+#endif

struct window_frame *frame;

@@ -1403,6 +1415,18 @@ surface_create_surface(struct surface *surface, int dx, int dy, uint32_t flags)
struct display *display = surface->window->display;
struct rectangle allocation = surface->allocation;

+#ifdef ENABLE_IVI_CLIENT
+ if (!surface->toysurface) {
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ surface->window->ivi_surface = ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, surface->surface);
+ if (surface->window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+ }
+#endif
+
if (!surface->toysurface && display->dpy &&
surface->buffer_type == WINDOW_BUFFER_TYPE_EGL_WINDOW) {
surface->toysurface =
@@ -1518,6 +1542,11 @@ surface_destroy(struct surface *surface)
if (surface->toysurface)
surface->toysurface->destroy(surface->toysurface);

+#ifdef ENABLE_IVI_CLIENT
+ ivi_surface_destroy(surface->window->ivi_surface);
+ ivi_application_destroy(surface->window->display->ivi_application);
+#endif
+
wl_list_remove(&surface->link);
free(surface);
}
@@ -1532,7 +1561,7 @@ window_destroy(struct window *window)

wl_list_remove(&window->redraw_task.link);

- wl_list_for_each(input, &display->input_list, link) {
+ wl_list_for_each(input, &display->input_list, link) {
if (input->touch_focus == window)
input->touch_focus = NULL;
if (input->pointer_focus == window)
@@ -3039,7 +3068,7 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
wl_list_insert(&input->touch_point_list, &tp->link);

if (widget->touch_down_handler)
- (*widget->touch_down_handler)(widget, input,
+ (*widget->touch_down_handler)(widget, input,
serial, time, id,
sx, sy,
widget->user_data);
@@ -5017,6 +5046,11 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
wl_registry_bind(registry, id,
&wl_subcompositor_interface, 1);
}
+#ifdef ENABLE_IVI_CLIENT
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application = wl_registry_bind(registry, id, &ivi_application_interface, 1);
+ }
+#endif

if (d->global_handler)
d->global_handler(d, id, interface, version, d->user_data);
@@ -5326,6 +5360,10 @@ display_destroy(struct display *display)

close(display->epoll_fd);

+#ifdef ENABLE_IVI_CLIENT
+ wl_display_roundtrip(display->display);
+#endif
+
if (!(display->display_fd_events & EPOLLERR) &&
!(display->display_fd_events & EPOLLHUP))
wl_display_flush(display->display);
--
1.8.3.1
Nobuhiko Tanibata
2014-03-06 10:27:30 UTC
Permalink
Hi,

This will add the following reference png files but I don't know whether I can send huge size of patch, around 650KB, to mailing list. These pngs file can be downloaded from here,

https://review.tizen.org/git/?p=profile/ivi/weston-ivi-shell.git;a=tree;f=data;h=600a549d874d7a54c16c3def09a4dad0853532a3;hb=e0f2e11fd31fd8b1201254a6c638c1e21d505ced

BR,
Nobuhiko

----------------------------------------

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
data/background.png | Bin 0 -> 245579 bytes
data/fullscreen.png | Bin 0 -> 3406 bytes
data/home.png | Bin 0 -> 4629 bytes
data/icon_ivi_clickdot.png | Bin 0 -> 39523 bytes
data/icon_ivi_flower.png | Bin 0 -> 24475 bytes
data/icon_ivi_simple-egl.png | Bin 0 -> 29316 bytes
data/icon_ivi_simple-shm.png | Bin 0 -> 71120 bytes
data/icon_ivi_smoke.png | Bin 0 -> 46577 bytes
data/panel.png | Bin 0 -> 41955 bytes
data/random.png | Bin 0 -> 4891 bytes
data/sidebyside.png | Bin 0 -> 3929 bytes
data/tiling.png | Bin 0 -> 5620 bytes
12 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 data/background.png
create mode 100644 data/fullscreen.png
create mode 100644 data/home.png
create mode 100644 data/icon_ivi_clickdot.png
create mode 100644 data/icon_ivi_flower.png
create mode 100644 data/icon_ivi_simple-egl.png
create mode 100644 data/icon_ivi_simple-shm.png
create mode 100644 data/icon_ivi_smoke.png
create mode 100644 data/panel.png
create mode 100644 data/random.png
create mode 100644 data/sidebyside.png
create mode 100644 data/tiling.png
Nobuhiko Tanibata
2014-03-17 06:17:38 UTC
Permalink
Hi,

Thanks to review comments from mainling list. I refine patch series to
view them clearly.
I think some review comments remained there to be fixed. I will use this
thread.

BR,
Nobuhiko

2014-03-06 18:19 ? nobuhiko_tanibata ????????:
> Hi,
>
> This patch series adds a reference implementation of a shell for
> In-Vehicle Infotainment system; IVI, libraries on the shell to manage
> layout of User interface; UI, and samples how to use them. Before
> stepping in overview of patches, please let me explain background and
> purpose of this contribution.
>
> Background)
> I am working for prototyping a shell for In-Vehicle Infotainment; IVI
> in TIZEN IVI. This prototyping is being integrated to the TIZEN IVI.
>
> https://review.tizen.org/git/?p=profile/ivi/weston-ivi-shell.git;a=summary
>
> I am also working for GENIVI wayland-ivi-extension and several private
> projects with several Car Makers to apply a shell to its use case. The
> main use case on them is very similar with each other, which is based
> on a concept of Layer Management.
>
> http://projects.genivi.org/ivi-layer-management/node/13
>
> Purpose)
> I am contributing a reference for common use case of IVI mentioned in
> Background to avoid implementing same one for each user. The main use
> case is Layer Management to manage properties of surfaces and layer.
> Layer is used for grouping surfaces. In this patch series, I am
> contributing libweston-layout.so to support Layer management features
> with a set of interfaces which are defined based on
> ivi-layer-management from GENIVI. With libweston-layout.so, each shell
> developer of IVI can easily implement own shell.
>
> Overview)
> This patch series are mainly applied to new folder ?ivi-shell? like
> ?desktop-shell?. This patch series consists of 5 major parts,
>
> - ivi-shell.so : support ivi-application.xml protocol and
> initialization of libweston-layout.so. The ivi-application.xml defines
> simple interfaces; ?ivi_application::surface_create?. An interface
> ivi_application::surface_create? is used to tie ID to wl_surface from
> application. In IVI use case, such IDs are predefined at system design
> phase to control surface with business logic. For example, TV
> application shall be invisible in case of speed restriction.
>
> - libweston-layout.so: this shall be linked to ivi-shell.so to support
> layer management APIs internally. These APIs allows us to manage
> surfaces and layer by e.g. setting properties; position, visibility,
> opacity and rectangle of source to crop, and so on. This APIs
> internally uses weston_view as abstraction layer of compositor.
>
> - hmi-controller.so: a reference implementation how to use
> libweston-layout.so. It implement several protocols defined by
> ivi-hmi-controller.xml,
>
> 1/Requesting which surface is a part of User interfaces, e.g. a
> surface draw an icon from PNG files. According to request,
> hmi-controller layouts specified surfaces on a Screen by using
> libweston-layout.so.
> 2/Requesting layout change. There are 4 types of layout for a
> reference; tiling, side by side, full screen, and random.
> 3/Requesting displaying launchers. There are several pages to group
> icons which can be selected by motion of input.
> 4/Requesting animation moving from one page to another by motion of
> input.
> A reference how to use these protocols are implemented in
> hmi-controller-homescreen. A pthread sets up parts of UI and triggers
> layout change, showing launchers, and allowing hmi-controller to
> select pages of launchers by using ivi-hmi-controller.xml. This can be
> implemented in separated process, e.g. desktop-shell.c, as well.
>
> - Supporting ivi-application protocol to example in ?clients? folder.
> Add macro to compile ivi-application separately. Basically it uses the
> same code. For example, add macro: ENABLE_IVI_CLIENT to simple-egl.c
> for compiling weston-simple-egl-ivi at the same time.
>
> - Add reference weston.ini.in for ivi-shell in ivi-shell folder as
> well. It is referred by ivi-shell and hmi-controller.so to define
> several configurations. E.g. setting cursor, ID of surfaces and layers
> to be used by hmi-controller-homescreen, launchers; path to icons,
> binary, ID which page they are located.
>
>
> I am enclosing a pdf for overview of ivi-shell related parts. The pdf
> also mentions ivi-controller.so maintained here to keep compatibility
> with IVI layer manager.
>
> http://git.projects.genivi.org/?p=wayland-ivi-extension.git;a=summary
>
> It allow GENIVI graphic application to manage surfaces/layer outside
> of Weston process. However it is not purpose to do animation. Ideally,
> business logic shall be implemented inside of Weston process to reduce
> dispatch of process as much as possible.
>
>
> Best regards,
> Nobuhiko
Nobuhiko Tanibata
2014-03-17 06:21:42 UTC
Permalink
Hi,

Thanks to review comments from mainling list. I refine patch series to
view them clearly as v4.
I think some review comments remained there to be fixed. I will use this
thread.

BR,
Nobuhiko

2014-03-06 18:19 ? nobuhiko_tanibata ????????:
> Hi,
>
> This patch series adds a reference implementation of a shell for
> In-Vehicle Infotainment system; IVI, libraries on the shell to manage
> layout of User interface; UI, and samples how to use them. Before
> stepping in overview of patches, please let me explain background and
> purpose of this contribution.
>
> Background)
> I am working for prototyping a shell for In-Vehicle Infotainment; IVI
> in TIZEN IVI. This prototyping is being integrated to the TIZEN IVI.
>
> https://review.tizen.org/git/?p=profile/ivi/weston-ivi-shell.git;a=summary
>
> I am also working for GENIVI wayland-ivi-extension and several private
> projects with several Car Makers to apply a shell to its use case. The
> main use case on them is very similar with each other, which is based
> on a concept of Layer Management.
>
> http://projects.genivi.org/ivi-layer-management/node/13
>
> Purpose)
> I am contributing a reference for common use case of IVI mentioned in
> Background to avoid implementing same one for each user. The main use
> case is Layer Management to manage properties of surfaces and layer.
> Layer is used for grouping surfaces. In this patch series, I am
> contributing libweston-layout.so to support Layer management features
> with a set of interfaces which are defined based on
> ivi-layer-management from GENIVI. With libweston-layout.so, each shell
> developer of IVI can easily implement own shell.
>
> Overview)
> This patch series are mainly applied to new folder ?ivi-shell? like
> ?desktop-shell?. This patch series consists of 5 major parts,
>
> - ivi-shell.so : support ivi-application.xml protocol and
> initialization of libweston-layout.so. The ivi-application.xml defines
> simple interfaces; ?ivi_application::surface_create?. An interface
> ivi_application::surface_create? is used to tie ID to wl_surface from
> application. In IVI use case, such IDs are predefined at system design
> phase to control surface with business logic. For example, TV
> application shall be invisible in case of speed restriction.
>
> - libweston-layout.so: this shall be linked to ivi-shell.so to support
> layer management APIs internally. These APIs allows us to manage
> surfaces and layer by e.g. setting properties; position, visibility,
> opacity and rectangle of source to crop, and so on. This APIs
> internally uses weston_view as abstraction layer of compositor.
>
> - hmi-controller.so: a reference implementation how to use
> libweston-layout.so. It implement several protocols defined by
> ivi-hmi-controller.xml,
>
> 1/Requesting which surface is a part of User interfaces, e.g. a
> surface draw an icon from PNG files. According to request,
> hmi-controller layouts specified surfaces on a Screen by using
> libweston-layout.so.
> 2/Requesting layout change. There are 4 types of layout for a
> reference; tiling, side by side, full screen, and random.
> 3/Requesting displaying launchers. There are several pages to group
> icons which can be selected by motion of input.
> 4/Requesting animation moving from one page to another by motion of
> input.
> A reference how to use these protocols are implemented in
> hmi-controller-homescreen. A pthread sets up parts of UI and triggers
> layout change, showing launchers, and allowing hmi-controller to
> select pages of launchers by using ivi-hmi-controller.xml. This can be
> implemented in separated process, e.g. desktop-shell.c, as well.
>
> - Supporting ivi-application protocol to example in ?clients? folder.
> Add macro to compile ivi-application separately. Basically it uses the
> same code. For example, add macro: ENABLE_IVI_CLIENT to simple-egl.c
> for compiling weston-simple-egl-ivi at the same time.
>
> - Add reference weston.ini.in for ivi-shell in ivi-shell folder as
> well. It is referred by ivi-shell and hmi-controller.so to define
> several configurations. E.g. setting cursor, ID of surfaces and layers
> to be used by hmi-controller-homescreen, launchers; path to icons,
> binary, ID which page they are located.
>
>
> I am enclosing a pdf for overview of ivi-shell related parts. The pdf
> also mentions ivi-controller.so maintained here to keep compatibility
> with IVI layer manager.
>
> http://git.projects.genivi.org/?p=wayland-ivi-extension.git;a=summary
>
> It allow GENIVI graphic application to manage surfaces/layer outside
> of Weston process. However it is not purpose to do animation. Ideally,
> business logic shall be implemented inside of Weston process to reduce
> dispatch of process as much as possible.
>
>
> Best regards,
> Nobuhiko
Nobuhiko Tanibata
2014-03-17 06:23:22 UTC
Permalink
Add interface ivi_application, which creates ivi_surface objects tied
to a given wl_surface with a given id. The given id can be used in a
shell to identify which application is assigned to a wl_surface and
layout the surface wherever the shell wants. ivi_surface objects can
be used to receive status of wl_surface in the scenegraph of the
compositor.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- Rename "error" to "warning" because meaning of "error" in wayland is fatal.

Changes for v3:
- Move "warning" from ivi_application to ivi_surface.
- Squash Makefile.
- Add description to ivi_surface:destroy.
- Update description of ivi_application:surface_create.

Changes for v4:
- Remove detail description of server side from ivi_surface::destroy
- Add clear discripton what client shall do if it encounters warning in ivi_surface
::warning.
- Add decription what happens when client tries to tie a wl_surface to multiple
ivi_surfaces.

protocol/Makefile.am | 3 +-
protocol/ivi-application.xml | 99 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 101 insertions(+), 1 deletion(-)
create mode 100644 protocol/ivi-application.xml

diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 5e331a7..9913f16 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -8,7 +8,8 @@ protocol_sources = \
text-cursor-position.xml \
wayland-test.xml \
xdg-shell.xml \
- scaler.xml
+ scaler.xml \
+ ivi-application.xml

if HAVE_XMLLINT
.PHONY: validate
diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml
new file mode 100644
index 0000000..37ad489
--- /dev/null
+++ b/protocol/ivi-application.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ivi_application">
+
+ <copyright>
+ Copyright (C) 2013 DENSO CORPORATION
+ Copyright (c) 2013 BMW Car IT GmbH
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ </copyright>
+
+ <interface name="ivi_surface" version="1">
+ <description summary="application interface to surface in ivi compositor"/>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy ivi_surface">
+ This removes link from surface_id to wl_surface and destroys ivi_surface.
+ </description>
+ </request>
+
+ <event name="visibility">
+ <description summary="visibility of surface in ivi compositor has changed">
+ The new visibility state is provided in argument visibility.
+ If visibility is 0, the surface has become invisible.
+ If visibility is not 0, the surface has become visible.
+ </description>
+ <arg name="visibility" type="int"/>
+ </event>
+
+ <enum name="warning_code">
+ <description summary="possible warning codes returned by ivi compositor">
+ These warning codes define all possible warning codes returned by ivi compositor
+ on server-side warnings.
+ invalid_wl_surface: invalid wl_surface is set. This happens if wl_surface is destroyed before this.
+ surface_id_in_use: surface_id is already assigned by another application.
+ </description>
+ <entry name="invalid_wl_surface" value="1" summary="wl_surface is invalid"/>
+ <entry name="surface_id_in_use" value="2" summary="surface_id is in use and can not be shared"/>
+ </enum>
+
+ <event name="warning">
+ <description summary="server-side warning detected">
+ The ivi compositor encountered warning while processing a request by this
+ application. The warning is defined by argument warning_code and optional
+ warning_text. If the warning is detected, client shall destroy the ivi_surface
+ object.
+
+ When ivi compositor encounters warnings, a request is canceled and there is no
+ mapping from id_surface/wl_surface to this ivi_surface. Even if there is no
+ mapping but destroying this ivi_surface is recommended.
+ </description>
+ <arg name="warning_code" type="int"/>
+ <arg name="warning_text" type="string" allow-null="true"/>
+ </event>
+
+ </interface>
+
+ <interface name="ivi_application" version="1">
+ <description summary="interface for ivi applications to use ivi compositor features"/>
+
+ <request name="surface_create">
+ <description summary="create ivi_surface with numeric ID in ivi compositor">
+ surface_create will create a interface:ivi_surface with numeric ID; surface_id in
+ ivi compositor. These surface_ids are defined as unique in the system to identify
+ it inside of ivi compositor. The ivi compositor implements business logic how to
+ set properties of the surface with surface_id according to status of the system.
+ E.g. a unique ID for Car Navigation application is used for implementing special
+ logic of the application about where it shall be located.
+
+ Created ivi_surface notifies warnings when following situation happens,
+ - Invalid wl_surface is set. This happen if wl_surface is destroy before this.
+ - surface_id is already assigned by another application.
+ If a client sets a wl_surface to multiple id_surfaces, no warning is issued. Property
+ of the surface can be controlled by multiple ivi_surface. However this case shall
+ be avoided by a client.
+ </description>
+ <arg name="id_surface" type="uint"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="id" type="new_id" interface="ivi_surface"/>
+ </request>
+
+ </interface>
+
+</protocol>
--
1.8.3.1
Pekka Paalanen
2014-04-23 10:40:37 UTC
Permalink
Hi,

it's been a long while since I have looked at this, but I got a bit of
time to come back. I hope you haven't abandoned this effort yet. :-)

I looked at the PDF from your post on March 6th, 2014, and some of my
own comments I gave at that time to recall what this was about, but I
probably still forgot something.

New comments below. I started by reading the global interface, and
moved on to ivi_surface after it, so the comments might seem
temporally strange if you read just top-down.


On Mon, 17 Mar 2014 15:23:22 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> Add interface ivi_application, which creates ivi_surface objects tied
> to a given wl_surface with a given id. The given id can be used in a
> shell to identify which application is assigned to a wl_surface and
> layout the surface wherever the shell wants. ivi_surface objects can
> be used to receive status of wl_surface in the scenegraph of the
> compositor.
>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - Rename "error" to "warning" because meaning of "error" in wayland is fatal.
>
> Changes for v3:
> - Move "warning" from ivi_application to ivi_surface.
> - Squash Makefile.
> - Add description to ivi_surface:destroy.
> - Update description of ivi_application:surface_create.
>
> Changes for v4:
> - Remove detail description of server side from ivi_surface::destroy
> - Add clear discripton what client shall do if it encounters warning in ivi_surface
> ::warning.
> - Add decription what happens when client tries to tie a wl_surface to multiple
> ivi_surfaces.
>
> protocol/Makefile.am | 3 +-
> protocol/ivi-application.xml | 99 ++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 101 insertions(+), 1 deletion(-)
> create mode 100644 protocol/ivi-application.xml
>
> diff --git a/protocol/Makefile.am b/protocol/Makefile.am
> index 5e331a7..9913f16 100644
> --- a/protocol/Makefile.am
> +++ b/protocol/Makefile.am
> @@ -8,7 +8,8 @@ protocol_sources = \
> text-cursor-position.xml \
> wayland-test.xml \
> xdg-shell.xml \
> - scaler.xml
> + scaler.xml \
> + ivi-application.xml
>
> if HAVE_XMLLINT
> .PHONY: validate
> diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml
> new file mode 100644
> index 0000000..37ad489
> --- /dev/null
> +++ b/protocol/ivi-application.xml
> @@ -0,0 +1,99 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<protocol name="ivi_application">
> +
> + <copyright>
> + Copyright (C) 2013 DENSO CORPORATION
> + Copyright (c) 2013 BMW Car IT GmbH
> +
> + Permission is hereby granted, free of charge, to any person obtaining a copy
> + of this software and associated documentation files (the "Software"), to deal
> + in the Software without restriction, including without limitation the rights
> + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + copies of the Software, and to permit persons to whom the Software is
> + furnished to do so, subject to the following conditions:
> +
> + The above copyright notice and this permission notice shall be included in
> + all copies or substantial portions of the Software.
> +
> + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + THE SOFTWARE.
> + </copyright>
> +
> + <interface name="ivi_surface" version="1">
> + <description summary="application interface to surface in ivi compositor"/>
> +
> + <request name="destroy" type="destructor">
> + <description summary="destroy ivi_surface">
> + This removes link from surface_id to wl_surface and destroys ivi_surface.
> + </description>
> + </request>
> +
> + <event name="visibility">
> + <description summary="visibility of surface in ivi compositor has changed">
> + The new visibility state is provided in argument visibility.
> + If visibility is 0, the surface has become invisible.
> + If visibility is not 0, the surface has become visible.
> + </description>
> + <arg name="visibility" type="int"/>
> + </event>
> +
> + <enum name="warning_code">
> + <description summary="possible warning codes returned by ivi compositor">
> + These warning codes define all possible warning codes returned by ivi compositor

Codes define codes? :-)

> + on server-side warnings.
> + invalid_wl_surface: invalid wl_surface is set. This happens if wl_surface is destroyed before this.

Ooh, does this mean that invalid_wl_surface is emitted if wl_surface is
destroyed before the ivi_surface? Try to use more nouns and less
pronouns in specification language to keep things explicit.

I was about ask what happens if the wl_surface gets destroyed first.

> + surface_id_in_use: surface_id is already assigned by another application.
> + </description>
> + <entry name="invalid_wl_surface" value="1" summary="wl_surface is invalid"/>
> + <entry name="surface_id_in_use" value="2" summary="surface_id is in use and can not be shared"/>
> + </enum>
> +
> + <event name="warning">
> + <description summary="server-side warning detected">
> + The ivi compositor encountered warning while processing a request by this
> + application. The warning is defined by argument warning_code and optional
> + warning_text. If the warning is detected, client shall destroy the ivi_surface
> + object.
> +
> + When ivi compositor encounters warnings, a request is canceled and there is no
> + mapping from id_surface/wl_surface to this ivi_surface. Even if there is no
> + mapping but destroying this ivi_surface is recommended.

I would propose a slightly different wording here, which may or may not
be what you intended above.

"When a warning event is sent, the compositor turns the ivi_surface
object inert. The ivi_surface will not deliver further events, all
requests on it are ignored except 'destroy', and the association to the
surface_id is removed. The client should destroy the ivi_surface
object. If an inert ivi_surface object is used as an argument to any
other object's request, that request will [produce a fatal error /
produce a warning / be ignored]."

There are no requests other than 'destroy' on ivi_surface, but it is
better to be explicit just in case later someone adds a new request. On
the final part, you can pick what suits best, or say that the effect is
undefined.

> + </description>
> + <arg name="warning_code" type="int"/>
> + <arg name="warning_text" type="string" allow-null="true"/>
> + </event>
> +
> + </interface>
> +
> + <interface name="ivi_application" version="1">
> + <description summary="interface for ivi applications to use ivi compositor features"/>

Could mention that this is a global interface, isn't it?

> + <request name="surface_create">
> + <description summary="create ivi_surface with numeric ID in ivi compositor">
> + surface_create will create a interface:ivi_surface with numeric ID; surface_id in
> + ivi compositor. These surface_ids are defined as unique in the system to identify
> + it inside of ivi compositor. The ivi compositor implements business logic how to
> + set properties of the surface with surface_id according to status of the system.
> + E.g. a unique ID for Car Navigation application is used for implementing special
> + logic of the application about where it shall be located.
> +
> + Created ivi_surface notifies warnings when following situation happens,
> + - Invalid wl_surface is set. This happen if wl_surface is destroy before this.

How is it possible to destroy the wl_surface before issuing a
ivi_application.surface_create request? IOW, I cannot understand when a
wl_surface could be invalid due to "destroy". But it could be if the
wl_surface already has a role.

> + - surface_id is already assigned by another application.
> + If a client sets a wl_surface to multiple id_surfaces, no warning is issued. Property
> + of the surface can be controlled by multiple ivi_surface. However this case shall
> + be avoided by a client.

By id_surface, do you mean creating multiple ivi_surface objects with
the same or different surface_id for a single wl_surface? Would it ever
make any sense to do that?

Is it legal or illegal to do that? If it is illegal, there should be a
fatal protocol error. I know you prefer non-fatal warnings, but even
Wayland core has fatal errors like for invalid object id. I would think
that creating several ivi_surfaces for the same wl_surface would be a
similar problem as use-after-free producing an invalid object id, if it
really is illegal.

Also, if ivi_application.surface_create assigns a role to a wl_surface,
then you cannot have several ivi_surfaces referencing the same
wl_surface.

In Weston, a role is identified by weston_surface::configure function
pointer. More conceptually, a role defines how the surface behaves on
screen: cursor surface moves with the pointer, ivi_surface is
controlled by your... ivi-controller or something. In principle,
without a role, a surface cannot be shown at all because the compositor
does not know how or when to show it.

> + </description>
> + <arg name="id_surface" type="uint"/>

id_surface here, surface_id in the doc; maybe pick one form, and use
that everywhere?

I wonder, could we use a more specific term for the ID? Would "ivi_id"
be unambiguous? So we could talk about surface's ivi_id, as opposed to
surface_id which is not obviously an IVI concept. Every Wayland protocol
object has an id, and I would like avoid any chances of confusing
wl_surface id with ivi_id.

> + <arg name="surface" type="object" interface="wl_surface"/>
> + <arg name="id" type="new_id" interface="ivi_surface"/>
> + </request>
> +
> + </interface>
> +
> +</protocol>

This is looking good, mostly just some details in the wording to be
tuned. :-)

I will see if I can review more of the patches, but I would also
suggest the following, in case you are still interested in pushing this
upstream.

Wait for Weston 1.5 to be released. We are currently in freeze, so
there is no point in re-sending until that is done. Check that the 1.5
stable branch has been created, or at least the release has been made,
before you rebase and re-send this series.


Thanks,
pq
Nobuhiko Tanibata
2014-04-25 13:34:27 UTC
Permalink
2014-04-23 19:40 ? Pekka Paalanen ????????:
> Hi,
>
> it's been a long while since I have looked at this, but I got a bit of
> time to come back. I hope you haven't abandoned this effort yet. :-)
>
> I looked at the PDF from your post on March 6th, 2014, and some of my
> own comments I gave at that time to recall what this was about, but I
> probably still forgot something.
>
> New comments below. I started by reading the global interface, and
> moved on to ivi_surface after it, so the comments might seem
> temporally strange if you read just top-down.
>
>
> On Mon, 17 Mar 2014 15:23:22 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> Add interface ivi_application, which creates ivi_surface objects tied
>> to a given wl_surface with a given id. The given id can be used in a
>> shell to identify which application is assigned to a wl_surface and
>> layout the surface wherever the shell wants. ivi_surface objects can
>> be used to receive status of wl_surface in the scenegraph of the
>> compositor.
>>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2:
>> - Rename "error" to "warning" because meaning of "error" in wayland
>> is fatal.
>>
>> Changes for v3:
>> - Move "warning" from ivi_application to ivi_surface.
>> - Squash Makefile.
>> - Add description to ivi_surface:destroy.
>> - Update description of ivi_application:surface_create.
>>
>> Changes for v4:
>> - Remove detail description of server side from
>> ivi_surface::destroy
>> - Add clear discripton what client shall do if it encounters
>> warning in ivi_surface
>> ::warning.
>> - Add decription what happens when client tries to tie a wl_surface
>> to multiple
>> ivi_surfaces.
>>
>> protocol/Makefile.am | 3 +-
>> protocol/ivi-application.xml | 99
>> ++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 101 insertions(+), 1 deletion(-)
>> create mode 100644 protocol/ivi-application.xml
>>
>> diff --git a/protocol/Makefile.am b/protocol/Makefile.am
>> index 5e331a7..9913f16 100644
>> --- a/protocol/Makefile.am
>> +++ b/protocol/Makefile.am
>> @@ -8,7 +8,8 @@ protocol_sources = \
>> text-cursor-position.xml \
>> wayland-test.xml \
>> xdg-shell.xml \
>> - scaler.xml
>> + scaler.xml \
>> + ivi-application.xml
>>
>> if HAVE_XMLLINT
>> .PHONY: validate
>> diff --git a/protocol/ivi-application.xml
>> b/protocol/ivi-application.xml
>> new file mode 100644
>> index 0000000..37ad489
>> --- /dev/null
>> +++ b/protocol/ivi-application.xml
>> @@ -0,0 +1,99 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<protocol name="ivi_application">
>> +
>> + <copyright>
>> + Copyright (C) 2013 DENSO CORPORATION
>> + Copyright (c) 2013 BMW Car IT GmbH
>> +
>> + Permission is hereby granted, free of charge, to any person
>> obtaining a copy
>> + of this software and associated documentation files (the
>> "Software"), to deal
>> + in the Software without restriction, including without limitation
>> the rights
>> + to use, copy, modify, merge, publish, distribute, sublicense,
>> and/or sell
>> + copies of the Software, and to permit persons to whom the
>> Software is
>> + furnished to do so, subject to the following conditions:
>> +
>> + The above copyright notice and this permission notice shall be
>> included in
>> + all copies or substantial portions of the Software.
>> +
>> + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS OR
>> + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> MERCHANTABILITY,
>> + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
>> SHALL THE
>> + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> OTHER
>> + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> ARISING FROM,
>> + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> DEALINGS IN
>> + THE SOFTWARE.
>> + </copyright>
>> +
>> + <interface name="ivi_surface" version="1">
>> + <description summary="application interface to surface in ivi
>> compositor"/>
>> +
>> + <request name="destroy" type="destructor">
>> + <description summary="destroy ivi_surface">
>> + This removes link from surface_id to wl_surface and
>> destroys ivi_surface.
>> + </description>
>> + </request>
>> +
>> + <event name="visibility">
>> + <description summary="visibility of surface in ivi
>> compositor has changed">
>> + The new visibility state is provided in argument
>> visibility.
>> + If visibility is 0, the surface has become invisible.
>> + If visibility is not 0, the surface has become
>> visible.
>> + </description>
>> + <arg name="visibility" type="int"/>
>> + </event>
>> +
>> + <enum name="warning_code">
>> + <description summary="possible warning codes returned by
>> ivi compositor">
>> + These warning codes define all possible warning codes
>> returned by ivi compositor
>
> Codes define codes? :-)
>
>> + on server-side warnings.
>> + invalid_wl_surface: invalid wl_surface is set. This
>> happens if wl_surface is destroyed before this.
>
> Ooh, does this mean that invalid_wl_surface is emitted if wl_surface is
> destroyed before the ivi_surface? Try to use more nouns and less
> pronouns in specification language to keep things explicit.
>
> I was about ask what happens if the wl_surface gets destroyed first.
>
>> + surface_id_in_use: surface_id is already assigned by
>> another application.
>> + </description>
>> + <entry name="invalid_wl_surface" value="1"
>> summary="wl_surface is invalid"/>
>> + <entry name="surface_id_in_use" value="2"
>> summary="surface_id is in use and can not be shared"/>
>> + </enum>
>> +
>> + <event name="warning">
>> + <description summary="server-side warning detected">
>> + The ivi compositor encountered warning while
>> processing a request by this
>> + application. The warning is defined by argument
>> warning_code and optional
>> + warning_text. If the warning is detected, client
>> shall destroy the ivi_surface
>> + object.
>> +
>> + When ivi compositor encounters warnings, a request is
>> canceled and there is no
>> + mapping from id_surface/wl_surface to this
>> ivi_surface. Even if there is no
>> + mapping but destroying this ivi_surface is
>> recommended.
>
> I would propose a slightly different wording here, which may or may not
> be what you intended above.
>
> "When a warning event is sent, the compositor turns the ivi_surface
> object inert. The ivi_surface will not deliver further events, all
> requests on it are ignored except 'destroy', and the association to the
> surface_id is removed. The client should destroy the ivi_surface
> object. If an inert ivi_surface object is used as an argument to any
> other object's request, that request will [produce a fatal error /
> produce a warning / be ignored]."
>
> There are no requests other than 'destroy' on ivi_surface, but it is
> better to be explicit just in case later someone adds a new request. On
> the final part, you can pick what suits best, or say that the effect is
> undefined.
>
>> + </description>
>> + <arg name="warning_code" type="int"/>
>> + <arg name="warning_text" type="string"
>> allow-null="true"/>
>> + </event>
>> +
>> + </interface>
>> +
>> + <interface name="ivi_application" version="1">
>> + <description summary="interface for ivi applications to use
>> ivi compositor features"/>
>
> Could mention that this is a global interface, isn't it?
>
>> + <request name="surface_create">
>> + <description summary="create ivi_surface with numeric ID
>> in ivi compositor">
>> + surface_create will create a interface:ivi_surface
>> with numeric ID; surface_id in
>> + ivi compositor. These surface_ids are defined as
>> unique in the system to identify
>> + it inside of ivi compositor. The ivi compositor
>> implements business logic how to
>> + set properties of the surface with surface_id
>> according to status of the system.
>> + E.g. a unique ID for Car Navigation application is
>> used for implementing special
>> + logic of the application about where it shall be
>> located.
>> +
>> + Created ivi_surface notifies warnings when following
>> situation happens,
>> + - Invalid wl_surface is set. This happen if
>> wl_surface is destroy before this.
>
> How is it possible to destroy the wl_surface before issuing a
> ivi_application.surface_create request? IOW, I cannot understand when a
> wl_surface could be invalid due to "destroy". But it could be if the
> wl_surface already has a role.
>
>> + - surface_id is already assigned by another
>> application.
>> + If a client sets a wl_surface to multiple
>> id_surfaces, no warning is issued. Property
>> + of the surface can be controlled by multiple
>> ivi_surface. However this case shall
>> + be avoided by a client.
>
> By id_surface, do you mean creating multiple ivi_surface objects with
> the same or different surface_id for a single wl_surface? Would it ever
> make any sense to do that?
>
> Is it legal or illegal to do that? If it is illegal, there should be a
> fatal protocol error. I know you prefer non-fatal warnings, but even
> Wayland core has fatal errors like for invalid object id. I would think
> that creating several ivi_surfaces for the same wl_surface would be a
> similar problem as use-after-free producing an invalid object id, if it
> really is illegal.
>
> Also, if ivi_application.surface_create assigns a role to a wl_surface,
> then you cannot have several ivi_surfaces referencing the same
> wl_surface.
>
> In Weston, a role is identified by weston_surface::configure function
> pointer. More conceptually, a role defines how the surface behaves on
> screen: cursor surface moves with the pointer, ivi_surface is
> controlled by your... ivi-controller or something. In principle,
> without a role, a surface cannot be shown at all because the compositor
> does not know how or when to show it.
>
>> + </description>
>> + <arg name="id_surface" type="uint"/>
>
> id_surface here, surface_id in the doc; maybe pick one form, and use
> that everywhere?
>
> I wonder, could we use a more specific term for the ID? Would "ivi_id"
> be unambiguous? So we could talk about surface's ivi_id, as opposed to
> surface_id which is not obviously an IVI concept. Every Wayland
> protocol
> object has an id, and I would like avoid any chances of confusing
> wl_surface id with ivi_id.
>
>> + <arg name="surface" type="object"
>> interface="wl_surface"/>
>> + <arg name="id" type="new_id" interface="ivi_surface"/>
>> + </request>
>> +
>> + </interface>
>> +
>> +</protocol>
>
> This is looking good, mostly just some details in the wording to be
> tuned. :-)
>
> I will see if I can review more of the patches, but I would also
> suggest the following, in case you are still interested in pushing this
> upstream.
>
> Wait for Weston 1.5 to be released. We are currently in freeze, so
> there is no point in re-sending until that is done. Check that the 1.5
> stable branch has been created, or at least the release has been made,
> before you rebase and re-send this series.
>
Hi pq,

Yes, I am still interested in pushing them. I will rabase them and
re-send them after weston 1.5 branch has been created.
I am also confirming your comments for other patches as well. Btw, do
you have a date when the branch is made?

BR,
Nobuhiko
>
> Thanks,
> pq
Pekka Paalanen
2014-04-25 16:05:38 UTC
Permalink
On Fri, 25 Apr 2014 22:34:27 +0900
Nobuhiko Tanibata <nobuhiko_tanibata at xddp.denso.co.jp> wrote:

> 2014-04-23 19:40 ? Pekka Paalanen ????????:
> > This is looking good, mostly just some details in the wording
> > to be tuned. :-)
> >
> > I will see if I can review more of the patches, but I would also
> > suggest the following, in case you are still interested in
> > pushing this upstream.
> >
> > Wait for Weston 1.5 to be released. We are currently in freeze,
> > so there is no point in re-sending until that is done. Check
> > that the 1.5 stable branch has been created, or at least the
> > release has been made, before you rebase and re-send this
> > series.
> >
> Hi pq,
>
> Yes, I am still interested in pushing them. I will rabase them
> and re-send them after weston 1.5 branch has been created.
> I am also confirming your comments for other patches as well.
> Btw, do you have a date when the branch is made?

Hi,

good to hear. :-)

I don't know of a date, but I suppose early May, perhaps.


Thanks,
pq
Nobuhiko Tanibata
2014-05-20 04:13:14 UTC
Permalink
2014-04-26 01:05 ? Pekka Paalanen ????????:
> On Fri, 25 Apr 2014 22:34:27 +0900
> Nobuhiko Tanibata <nobuhiko_tanibata at xddp.denso.co.jp> wrote:
>
>> 2014-04-23 19:40 ? Pekka Paalanen ????????:
>> > This is looking good, mostly just some details in the wording
>> > to be tuned. :-)
>> >
>> > I will see if I can review more of the patches, but I would also
>> > suggest the following, in case you are still interested in
>> > pushing this upstream.
>> >
>> > Wait for Weston 1.5 to be released. We are currently in freeze,
>> > so there is no point in re-sending until that is done. Check
>> > that the 1.5 stable branch has been created, or at least the
>> > release has been made, before you rebase and re-send this
>> > series.
>> >
>> Hi pq,
>>
>> Yes, I am still interested in pushing them. I will rabase them
>> and re-send them after weston 1.5 branch has been created.
>> I am also confirming your comments for other patches as well.
>> Btw, do you have a date when the branch is made?
>
> Hi,
>
> good to hear. :-)
>
> I don't know of a date, but I suppose early May, perhaps.
>

Hi,

I am re-sending them which are re-based based on Weston 1.5.
Additionally, I applied review comments from pq. Thank you for many
comments.
They are very use full for me!

BR,
Nobuhiko

>
> Thanks,
> pq
Nobuhiko Tanibata
2014-05-20 04:26:23 UTC
Permalink
ivi_applicatoin extension creates ivi_surface objects tied
to a given wl_surface with a given id. The given id can be used in a
shell to identify which application is assigned to a wl_surface and
layout the surface wherever the shell wants. ivi_surface objects can
be used to receive status of wl_surface in the scenegraph of the
compositor.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- Rename "error" to "warning" because meaning of "error" in wayland is fatal.

Changes for v3:
- Move "warning" from ivi_application to ivi_surface.
- Squash Makefile.
- Add description to ivi_surface:destroy.
- Update description of ivi_application:surface_create.

Changes for v4:
- Remove detail description of server side from ivi_surface::destroy
- Add clear discripton what client shall do if it encounters warning in ivi_surface
::warning.
- Add decription what happens when client tries to tie a wl_surface to multiple
ivi_surfaces.

Changes for v5:
- apply review comments from mailing list

protocol/Makefile.am | 3 +-
protocol/ivi-application.xml | 101 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 103 insertions(+), 1 deletion(-)
create mode 100644 protocol/ivi-application.xml

diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 5e331a7..9913f16 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -8,7 +8,8 @@ protocol_sources = \
text-cursor-position.xml \
wayland-test.xml \
xdg-shell.xml \
- scaler.xml
+ scaler.xml \
+ ivi-application.xml

if HAVE_XMLLINT
.PHONY: validate
diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml
new file mode 100644
index 0000000..833fd38
--- /dev/null
+++ b/protocol/ivi-application.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ivi_application">
+
+ <copyright>
+ Copyright (C) 2013 DENSO CORPORATION
+ Copyright (c) 2013 BMW Car IT GmbH
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ </copyright>
+
+ <interface name="ivi_surface" version="1">
+ <description summary="application interface to surface in ivi compositor"/>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy ivi_surface">
+ This removes link from ivi_id to wl_surface and destroys ivi_surface.
+ </description>
+ </request>
+
+ <event name="visibility">
+ <description summary="visibility of surface in ivi compositor has changed">
+ The new visibility state is provided in argument visibility.
+ If visibility is 0, the surface has become invisible.
+ If visibility is not 0, the surface has become visible.
+ </description>
+ <arg name="visibility" type="int"/>
+ </event>
+
+ <enum name="warning_code">
+ <description summary="possible warning codes returned by ivi compositor">
+ These define all possible warning codes returned by ivi compositor on server-side warnings.
+ invalid_wl_surface:
+ - wl_surface already has a another role.
+ - wl_surface is destroyed before the ivi_surface is destroyed.
+ ivi_id_in_use: ivi_id is already assigned by another application.
+ </description>
+ <entry name="invalid_wl_surface" value="1" summary="wl_surface is invalid"/>
+ <entry name="ivi_id_in_use" value="2" summary="ivi_id is in use and can not be shared"/>
+ </enum>
+
+ <event name="warning">
+ <description summary="server-side warning detected">
+ The ivi compositor encountered warning while processing a request by this
+ application. The warning is defined by argument warning_code and optional
+ warning_text. If the warning is detected, client shall destroy the ivi_surface
+ object.
+
+ When a warning event is sent, the compositor turns the ivi_surface object inert.
+ The ivi_surface will not deliver further events, all requests on it are ignored
+ except 'destroy', and the association to the ivi_id is removed. The client
+ should destroy the ivi_surface object. If an inert ivi_surface object is used as
+ an argument to any other object's request, that request will [produce a fatal
+ error / produce a warning / be ignored].
+ </description>
+ <arg name="warning_code" type="int"/>
+ <arg name="warning_text" type="string" allow-null="true"/>
+ </event>
+
+ </interface>
+
+ <interface name="ivi_application" version="1">
+ <description summary="create ivi-style surfaces">
+ This interface is implemented by servers that provide desktop-style user interfaces.
+ It allows clients to associate a ivi_surface with a basic surface.
+ </description>
+
+ <request name="surface_create">
+ <description summary="create ivi_surface with numeric ID in ivi compositor">
+ surface_create will create a interface:ivi_surface with numeric ID; ivi_id in
+ ivi compositor. These ivi_ids are defined as unique in the system to identify
+ it inside of ivi compositor. The ivi compositor implements business logic how to
+ set properties of the surface with ivi_id according to status of the system.
+ E.g. a unique ID for Car Navigation application is used for implementing special
+ logic of the application about where it shall be located.
+ if a wl_surface which already has another role is set, the server regards this as
+ error and disconnects the client.
+ </description>
+ <arg name="ivi_id" type="uint"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="id" type="new_id" interface="ivi_surface"/>
+ </request>
+
+ </interface>
+
+</protocol>
--
1.8.3.1
Nobuhiko Tanibata
2014-05-20 04:28:51 UTC
Permalink
In-Vehicle Infotainment system traditionally manages surfaces with global
identification. A protocol, ivi_application, supports such a feature by
implementing a request, ivi_application::surface_creation defined in
ivi_application.xml.

The ivi-shell explicitly loads ivi-layout.so and a module to add business
logic like how to layout surfaces by using ivi-layout APIs.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- apply review comments of mailing list.
- squash update of Makefile into this patch.
- move this patch after patch of weston-layout.
- support inherit propoerties of id_surface when client attaches another
wl_surface with id_surface after destroying ivi_surface once.

Changes for v3:
- squash internal method, configure, to ivi_shell_surface_configure.

Changes for v4:
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- apply review comments from mailing list

Makefile.am | 22 +++
configure.ac | 12 ++
ivi-shell/ivi-layout.h | 75 +++++++++
ivi-shell/ivi-shell.c | 414 +++++++++++++++++++++++++++++++++++++++++++++++++
ivi-shell/ivi-shell.h | 35 +++++
5 files changed, 558 insertions(+)
create mode 100644 ivi-shell/ivi-layout.h
create mode 100644 ivi-shell/ivi-shell.c
create mode 100644 ivi-shell/ivi-shell.h

diff --git a/Makefile.am b/Makefile.am
index 343adc6..279fffc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -700,6 +700,28 @@ nodist_fullscreen_shell_la_SOURCES = \
BUILT_SOURCES += $(nodist_fullscreen_shell_la_SOURCES)
endif

+if ENABLE_IVI_SHELL
+
+module_LTLIBRARIES += \
+ $(ivi_shell)
+
+ivi_shell = ivi-shell.la
+ivi_shell_la_LDFLAGS = -module -avoid-version
+ivi_shell_la_LIBADD = $(COMPOSITOR_LIBS) $(IVI_SHELL_LIBS) libshared.la
+ivi_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(IVI_SHELL_CFLAGS)
+ivi_shell_la_SOURCES = \
+ ivi-shell/ivi-shell.h \
+ ivi-shell/ivi-shell.c \
+ ivi-shell/ivi-layout.h
+nodist_ivi_shell_la_SOURCES = \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-server-protocol.h
+
+BUILT_SOURCES += $(nodist_ivi_shell_la_SOURCES)
+
+endif
+
+
if ENABLE_SCREEN_SHARING

module_LTLIBRARIES += screen-share.la
diff --git a/configure.ac b/configure.ac
index 031a26f..23e6ba5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -433,6 +433,16 @@ if test "x$enable_dbus" != "xno"; then
fi
AM_CONDITIONAL(ENABLE_DBUS, test "x$enable_dbus" = "xyes")

+# ivi-shell support
+AC_ARG_ENABLE(ivi-shell,
+ AS_HELP_STRING([--disable-ivi-shell],
+ [do not build ivi-shell server plugin and client]),,
+ enable_ivi_shell=yes)
+AM_CONDITIONAL(ENABLE_IVI_SHELL, test "x$enable_ivi_shell" = "xyes")
+if test x$enable_ivi_shell = xyes; then
+ PKG_CHECK_MODULES(IVI_SHELL, [cairo])
+fi
+
AC_ARG_ENABLE(wcap-tools, [ --disable-wcap-tools],, enable_wcap_tools=yes)
AM_CONDITIONAL(BUILD_WCAP_TOOLS, test x$enable_wcap_tools = xyes)
if test x$enable_wcap_tools = xyes; then
@@ -522,6 +532,8 @@ AC_MSG_RESULT([
XWayland ${enable_xwayland}
dbus ${enable_dbus}

+ ivi-shell ${enable_ivi_shell}
+
Build wcap utility ${enable_wcap_tools}
Build Fullscreen Shell ${enable_fullscreen_shell}

diff --git a/ivi-shell/ivi-layout.h b/ivi-shell/ivi-layout.h
new file mode 100644
index 0000000..a949b4c
--- /dev/null
+++ b/ivi-shell/ivi-layout.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * The ivi-layout library supports API set of controlling properties of
+ * surface and layer which groups surfaces. An unique ID whose type is integer
+ * is required to create surface and layer. With the unique ID, surface and
+ * layer are identified to control them. The API set consists of APIs to control
+ * properties of surface and layers about followings,
+ * - visibility.
+ * - opacity.
+ * - clipping (x,y,width,height).
+ * - position and size of it to be displayed.
+ * - orientation per 90 degree.
+ * - add or remove surfaces to a layer.
+ * - order of surfaces/layers in layer/screen to be displayed.
+ * - commit to apply property changes.
+ * - notifications of property change.
+ *
+ * Management of surfaces and layers grouping these surfaces are common way in
+ * In-Vehicle Infotainment system, which integrate several domains in one system.
+ * A layer is allocated to a domain in order to control application surfaces
+ * grouped to the layer all together.
+ */
+
+#ifndef _IVI_LAYOUT_H_
+#define _IVI_LAYOUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "compositor.h"
+
+struct ivi_layout_surface;
+
+struct ivi_layout_interface {
+ struct weston_view* (*get_weston_view)(struct ivi_layout_surface *surface);
+ void (*surfaceConfigure)(struct ivi_layout_surface *ivisurf,
+ uint32_t width, uint32_t height);
+ int32_t (*surfaceSetNativeContent)(struct weston_surface *wl_surface,
+ uint32_t width,
+ uint32_t height,
+ uint32_t id_surface);
+ struct ivi_layout_surface* (*surfaceCreate)(struct weston_surface *wl_surface,
+ uint32_t id_surface);
+ void (*initWithCompositor)(struct weston_compositor *ec);
+};
+
+WL_EXPORT struct ivi_layout_interface ivi_layout_interface;
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _IVI_LAYOUT_H_ */
diff --git a/ivi-shell/ivi-shell.c b/ivi-shell/ivi-shell.c
new file mode 100644
index 0000000..13bb1ed
--- /dev/null
+++ b/ivi-shell/ivi-shell.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/**
+ * ivi-shell supports a type of shell for In-Vehicle Infotainment system.
+ * In-Vehicle Infotainment system traditionally manages surfaces with global
+ * identification. A protocol, ivi_application, supports such a feature
+ * by implementing a request, ivi_application::surface_creation defined in
+ * ivi_application.xml.
+ *
+ * The ivi-shell explicitly loads a module to add business logic like how to
+ * layout surfaces by using internal ivi-layout APIs.
+ */
+#include "config.h"
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <dlfcn.h>
+#include <limits.h>
+
+#include "ivi-shell.h"
+#include "ivi-application-server-protocol.h"
+#include "ivi-layout.h"
+
+#include "../shared/os-compatibility.h"
+
+struct ivi_shell_surface
+{
+ struct ivi_shell *shell;
+ struct ivi_layout_surface *layout_surface;
+
+ struct weston_surface *surface;
+ uint32_t id_surface;
+
+ int32_t width;
+ int32_t height;
+
+ struct wl_list link;
+};
+
+struct ivi_shell_setting
+{
+ char *ivi_module;
+};
+
+static struct ivi_layout_interface *ivi_layout;
+
+/* ------------------------------------------------------------------------- */
+
+ /* common functions */
+/* ------------------------------------------------------------------------- */
+
+/**
+ * Implementation of ivi_surface
+ */
+
+static void
+ivi_shell_surface_configure(struct weston_surface *, int32_t, int32_t);
+
+static struct ivi_shell_surface *
+get_ivi_shell_surface(struct weston_surface *surface)
+{
+ if (surface->configure == ivi_shell_surface_configure) {
+ return surface->configure_private;
+ } else {
+ return NULL;
+ }
+}
+
+static void
+ivi_shell_surface_configure(struct weston_surface *surface,
+ int32_t sx, int32_t sy)
+{
+ struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(surface);
+ struct weston_view *view = NULL;
+ float from_x = 0.0f;
+ float from_y = 0.0f;
+ float to_x = 0.0f;
+ float to_y = 0.0f;
+
+ if ((surface->width == 0) || (surface->height == 0) || (ivisurf == NULL)) {
+ return;
+ }
+
+ view = ivi_layout->get_weston_view(ivisurf->layout_surface);
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->width != surface->width || ivisurf->height != surface->height) {
+
+ ivisurf->width = surface->width;
+ ivisurf->height = surface->height;
+
+ weston_view_to_global_float(view, 0, 0, &from_x, &from_y);
+ weston_view_to_global_float(view, sx, sy, &to_x, &to_y);
+
+ weston_view_set_position(view,
+ view->geometry.x + to_x - from_x,
+ view->geometry.y + to_y - from_y);
+ weston_view_update_transform(view);
+
+ ivi_layout->surfaceConfigure(ivisurf->layout_surface, surface->width, surface->height);
+ }
+}
+
+static void
+surface_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource);
+
+ if (ivisurf != NULL) {
+ ivisurf->surface->configure = NULL;
+ ivisurf->surface->configure_private = NULL;
+ ivisurf->surface = NULL;
+ ivi_layout->surfaceSetNativeContent(NULL, 0, 0, ivisurf->id_surface);
+ }
+
+ wl_resource_destroy(resource);
+}
+
+static const struct ivi_surface_interface surface_implementation = {
+ surface_destroy,
+};
+
+static struct ivi_shell_surface *
+is_surf_in_surfaces(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct ivi_shell_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+static const struct {
+ uint32_t warning_code; /* enum ivi_surface_warning_code */
+ const char *msg;
+} warning_strings[] = {
+ {IVI_SURFACE_WARNING_CODE_INVALID_WL_SURFACE, "wl_surface is invalid"},
+ {IVI_SURFACE_WARNING_CODE_IVI_ID_IN_USE, "surface_id is already assigned by another app"}
+};
+
+/**
+ * Implementation of ivi_application::surface_create.
+ * Creating new ivi_shell_surface with identification to identify the surface
+ * in the system.
+ */
+static void
+application_surface_create(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface,
+ struct wl_resource *surface_resource,
+ uint32_t id)
+{
+ struct ivi_shell *shell = wl_resource_get_user_data(resource);
+ struct ivi_shell_surface *ivisurf = NULL;
+ struct ivi_layout_surface *layout_surface = NULL;
+ struct weston_surface *weston_surface = wl_resource_get_user_data(surface_resource);
+ struct wl_resource *res;
+ int32_t warn_idx = -1;
+
+ if (weston_surface != NULL) {
+
+ /* check if a surface already has another role*/
+ if (weston_surface->configure) {
+ wl_resource_post_error(weston_surface->resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "surface->configure already "
+ "set");
+ return;
+ }
+
+ layout_surface = ivi_layout->surfaceCreate(weston_surface, id_surface);
+
+ if (layout_surface == NULL)
+ warn_idx = 1;
+ } else {
+ warn_idx = 0;
+ }
+
+ res = wl_resource_create(client, &ivi_surface_interface, 1, id);
+ if (res == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ if (warn_idx >= 0) {
+ wl_resource_set_implementation(res, &surface_implementation,
+ NULL, NULL);
+ ivi_surface_send_warning(res,
+ warning_strings[warn_idx].warning_code,
+ warning_strings[warn_idx].msg);
+ return;
+ }
+
+ ivisurf = is_surf_in_surfaces(&shell->ivi_surface_list, id_surface);
+ if (ivisurf == NULL) {
+ ivisurf = zalloc(sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ wl_resource_post_no_memory(res);
+ return;
+ }
+
+ wl_list_init(&ivisurf->link);
+ wl_list_insert(&shell->ivi_surface_list, &ivisurf->link);
+
+ ivisurf->shell = shell;
+ ivisurf->id_surface = id_surface;
+ }
+
+ ivisurf->width = 0;
+ ivisurf->height = 0;
+ ivisurf->layout_surface = layout_surface;
+ ivisurf->surface = weston_surface;
+
+ weston_surface->configure = ivi_shell_surface_configure;
+ weston_surface->configure_private = ivisurf;
+
+ wl_resource_set_implementation(res, &surface_implementation,
+ ivisurf, NULL);
+}
+
+static const struct ivi_application_interface application_implementation = {
+ application_surface_create
+};
+
+static void
+bind_ivi_application(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct ivi_shell *shell = data;
+ struct wl_resource *resource = NULL;
+
+ resource = wl_resource_create(client, &ivi_application_interface, 1, id);
+
+ wl_resource_set_implementation(resource,
+ &application_implementation,
+ shell, NULL);
+}
+
+/**
+ * Initialization/destruction method of ivi-shell
+ */
+static void
+shell_destroy(struct wl_listener *listener, void *data)
+{
+ struct ivi_shell *shell =
+ container_of(listener, struct ivi_shell, destroy_listener);
+ struct ivi_shell_surface *ivisurf, *next;
+
+ wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) {
+ wl_list_remove(&ivisurf->link);
+ free(ivisurf);
+ }
+
+ free(shell);
+}
+
+static void
+init_ivi_shell(struct weston_compositor *compositor, struct ivi_shell *shell)
+{
+ shell->compositor = compositor;
+
+ wl_list_init(&shell->ivi_surface_list);
+}
+
+static int
+ivi_shell_setting_create(struct ivi_shell_setting *dest)
+{
+ int result = 0;
+ struct weston_config *config = NULL;
+ struct weston_config_section *section = NULL;
+
+ if (NULL == dest) {
+ return -1;
+ }
+
+ config = weston_config_parse("weston.ini");
+ section = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ if (weston_config_section_get_string(
+ section, "ivi-module", (char **)&dest->ivi_module, NULL) != 0)
+ {
+ result = -1;
+ }
+
+ weston_config_destroy(config);
+ return result;
+}
+
+/**
+ * Initialization of ivi-shell.
+ */
+static int
+ivi_load_modules(struct weston_compositor *compositor, const char *modules,
+ int *argc, char *argv[])
+{
+ const char *p, *end;
+ char buffer[256];
+ int (*module_init)(struct weston_compositor *compositor,
+ int *argc, char *argv[]);
+
+ if (modules == NULL)
+ return 0;
+
+ p = modules;
+ while (*p) {
+ end = strchrnul(p, ',');
+ snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p);
+ module_init = weston_load_module(buffer, "module_init");
+ if (module_init)
+ module_init(compositor, argc, argv);
+ p = end;
+ while (*p == ',')
+ p++;
+
+ }
+
+ return 0;
+}
+
+WL_EXPORT int
+module_init(struct weston_compositor *compositor,
+ int *argc, char *argv[])
+{
+ struct ivi_shell *shell = NULL;
+ char ivi_layout_path[PATH_MAX];
+ void *module;
+ struct ivi_shell_setting setting = { };
+
+ shell = zalloc(sizeof *shell);
+ if (shell == NULL) {
+ return -1;
+ }
+
+ init_ivi_shell(compositor, shell);
+
+ shell->destroy_listener.notify = shell_destroy;
+ wl_signal_add(&compositor->destroy_signal, &shell->destroy_listener);
+
+ if (wl_global_create(compositor->wl_display, &ivi_application_interface, 1,
+ shell, bind_ivi_application) == NULL) {
+ return -1;
+ }
+
+ if (ivi_shell_setting_create(&setting) != 0) {
+ return 0;
+ }
+
+ /*load module:ivi-layout*/
+ /*ivi_layout_interface is referred by ivi-shell to use ivi-layout*/
+ snprintf(ivi_layout_path, sizeof ivi_layout_path, "%s/%s", MODULEDIR, "ivi-layout.so");
+ module = dlopen(ivi_layout_path, RTLD_NOW | RTLD_NOLOAD);
+ if (module) {
+ weston_log("ivi-shell: Module '%s' already loaded\n", ivi_layout_path);
+ dlclose(module);
+ return -1;
+ }
+
+ weston_log("ivi-shell: Loading module '%s'\n", ivi_layout_path);
+ module = dlopen(ivi_layout_path, RTLD_NOW | RTLD_GLOBAL);
+ if (!module) {
+ weston_log("ivi-shell: Failed to load module: %s\n", dlerror());
+ return -1;
+ }
+
+ ivi_layout = dlsym(module,"ivi_layout_interface");
+ if (!ivi_layout){
+ weston_log("ivi-shell: couldn't find ivi_layout_interface in '%s'\n", ivi_layout_path);
+ free(setting.ivi_module);
+ return -1;
+ }
+ else{
+ ivi_layout->initWithCompositor(compositor);
+ }
+
+ /*Call module_init of ivi-modules which are defined in weston.ini*/
+ if (ivi_load_modules(compositor,setting.ivi_module,argc,argv) < 0){
+ free(setting.ivi_module);
+ return -1;
+ }
+
+ free(setting.ivi_module);
+ return 0;
+}
diff --git a/ivi-shell/ivi-shell.h b/ivi-shell/ivi-shell.h
new file mode 100644
index 0000000..157c5ae
--- /dev/null
+++ b/ivi-shell/ivi-shell.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+
+#include "compositor.h"
+
+struct ivi_shell
+{
+ struct wl_resource *resource;
+ struct wl_listener destroy_listener;
+
+ struct weston_compositor *compositor;
+
+ struct wl_list ivi_surface_list; /* struct ivi_shell_surface::link */
+};
--
1.8.3.1
Nobuhiko Tanibata
2014-05-20 04:29:14 UTC
Permalink
API set of controlling properties of surface and layer which groups
surfaces. An unique ID whose type is integer is required to create
surface and layer. With the unique ID, surface and layer are identified
to control them. The API set consists of APIs to control properties of
surface and layers about followings,

- visibility.
- opacity.
- clipping (x,y,width,height).
- position and size of it to be displayed.
- orientation per 90 degree.
- add or remove surfaces to a layer.
- order of surfaces/layers in layer/screen to be displayed.
- commit to apply property changes.
- notifications of property change.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- move this patch in front of ivi-shell patch to be compiled successfully.
- unsupport weston_layout_takeSurfaceScreenshot because implementation needs to
be discussed more. It is pending.
- support inherit propoerties of id_surface when client attaches another
wl_surface with id_surface after destroying ivi_surface once.
- bug fix of https://bugs.tizen.org/jira/browse/TIVI-2882

Changes for v3 and v4
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- apply review comments from mailing list

Makefile.am | 17 +-
ivi-shell/ivi-layout-export.h | 964 ++++++++++++++
ivi-shell/ivi-layout.c | 2798 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 3778 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/ivi-layout-export.h
create mode 100644 ivi-shell/ivi-layout.c

diff --git a/Makefile.am b/Makefile.am
index 279fffc..e8bcb1b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -703,7 +703,8 @@ endif
if ENABLE_IVI_SHELL

module_LTLIBRARIES += \
- $(ivi_shell)
+ $(ivi_shell) \
+ $(ivi_layout)

ivi_shell = ivi-shell.la
ivi_shell_la_LDFLAGS = -module -avoid-version
@@ -719,6 +720,20 @@ nodist_ivi_shell_la_SOURCES = \

BUILT_SOURCES += $(nodist_ivi_shell_la_SOURCES)

+ivi_layout = ivi-layout.la
+ivi_layout_la_LDFLAGS = -module -avoid-version
+ivi_layout_la_LIBADD = $(COMPOSITOR_LIBS) $(IVI_SHELL_LIBS) libshared.la
+ivi_layout_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(IVI_SHELL_CFLAGS)
+ivi_layout_la_SOURCES = \
+ ivi-shell/ivi-layout.h \
+ ivi-shell/ivi-layout-export.h \
+ ivi-shell/ivi-layout.c
+nodist_ivi_layout_la_SOURCES = \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-server-protocol.h
+
+BUILT_SOURCES += $(nodist_ivi_layout_la_SOURCES)
+
endif


diff --git a/ivi-shell/ivi-layout-export.h b/ivi-shell/ivi-layout-export.h
new file mode 100644
index 0000000..0f95f53
--- /dev/null
+++ b/ivi-shell/ivi-layout-export.h
@@ -0,0 +1,964 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * The ivi-layout library supports API set of controlling properties of
+ * surface and layer which groups surfaces. An unique ID whose type is integer
+ * is required to create surface and layer. With the unique ID, surface and
+ * layer are identified to control them. The API set consists of APIs to control
+ * properties of surface and layers about followings,
+ * - visibility.
+ * - opacity.
+ * - clipping (x,y,width,height).
+ * - position and size of it to be displayed.
+ * - orientation per 90 degree.
+ * - add or remove surfaces to a layer.
+ * - order of surfaces/layers in layer/screen to be displayed.
+ * - commit to apply property changes.
+ * - notifications of property change.
+ *
+ * Management of surfaces and layers grouping these surfaces are common way in
+ * In-Vehicle Infotainment system, which integrate several domains in one system.
+ * A layer is allocated to a domain in order to control application surfaces
+ * grouped to the layer all together.
+ */
+
+#ifndef _IVI_LAYOUT_EXPORT_H_
+#define _IVI_LAYOUT_EXPORT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "compositor.h"
+#include "ivi-layout.h"
+
+struct ivi_layout_SurfaceProperties
+{
+ float opacity;
+ uint32_t sourceX;
+ uint32_t sourceY;
+ uint32_t sourceWidth;
+ uint32_t sourceHeight;
+ uint32_t origSourceWidth;
+ uint32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ uint32_t destWidth;
+ uint32_t destHeight;
+ uint32_t orientation;
+ uint32_t visibility;
+ uint32_t frameCounter;
+ uint32_t drawCounter;
+ uint32_t updateCounter;
+ uint32_t pixelformat;
+ uint32_t nativeSurface;
+ uint32_t inputDevicesAcceptance;
+ uint32_t chromaKeyEnabled;
+ uint32_t chromaKeyRed;
+ uint32_t chromaKeyGreen;
+ uint32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct ivi_layout_LayerProperties
+{
+ float opacity;
+ uint32_t sourceX;
+ uint32_t sourceY;
+ uint32_t sourceWidth;
+ uint32_t sourceHeight;
+ uint32_t origSourceWidth;
+ uint32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ uint32_t destWidth;
+ uint32_t destHeight;
+ uint32_t orientation;
+ uint32_t visibility;
+ uint32_t type;
+ uint32_t chromaKeyEnabled;
+ uint32_t chromaKeyRed;
+ uint32_t chromaKeyGreen;
+ uint32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct ivi_layout_layer;
+struct ivi_layout_screen;
+
+typedef struct ivi_layout_surface* ivi_layout_surface_ptr;
+typedef struct ivi_layout_layer* ivi_layout_layer_ptr;
+typedef struct ivi_layout_screen* ivi_layout_screen_ptr;
+
+enum ivi_layout_notification_mask {
+ IVI_NOTIFICATION_NONE = 0,
+ IVI_NOTIFICATION_OPACITY = (1 << 1),
+ IVI_NOTIFICATION_SOURCE_RECT = (1 << 2),
+ IVI_NOTIFICATION_DEST_RECT = (1 << 3),
+ IVI_NOTIFICATION_DIMENSION = (1 << 4),
+ IVI_NOTIFICATION_POSITION = (1 << 5),
+ IVI_NOTIFICATION_ORIENTATION = (1 << 6),
+ IVI_NOTIFICATION_VISIBILITY = (1 << 7),
+ IVI_NOTIFICATION_PIXELFORMAT = (1 << 8),
+ IVI_NOTIFICATION_ADD = (1 << 9),
+ IVI_NOTIFICATION_REMOVE = (1 << 10),
+ IVI_NOTIFICATION_ALL = 0xFFFF
+};
+
+typedef void(*layerPropertyNotificationFunc)(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_LayerProperties*,
+ enum ivi_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*surfacePropertyNotificationFunc)(struct ivi_layout_surface *ivisurf,
+ struct ivi_layout_SurfaceProperties*,
+ enum ivi_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*layerCreateNotificationFunc)(struct ivi_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*layerRemoveNotificationFunc)(struct ivi_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*surfaceCreateNotificationFunc)(struct ivi_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceRemoveNotificationFunc)(struct ivi_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceConfigureNotificationFunc)(struct ivi_layout_surface *ivisurf,
+ void *userdata);
+
+/**
+ * \brief to be called by ivi-shell in order to set initail view of
+ * weston_surface.
+ */
+/*
+struct weston_view *
+ivi_layout_get_weston_view(struct ivi_layout_surface *surface);
+*/
+
+/**
+ * \brief initialize ivi-layout
+ */
+/*
+void
+ivi_layout_initWithCompositor(struct weston_compositor *ec);
+*/
+
+/**
+ * \brief register for notification when layer is created
+ */
+int32_t
+ivi_layout_addNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata);
+
+void
+ivi_layout_removeNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when layer is removed
+ */
+int32_t
+ivi_layout_addNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata);
+
+void
+ivi_layout_removeNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is created
+ */
+int32_t
+ivi_layout_addNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata);
+
+void
+ivi_layout_removeNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is removed
+ */
+int32_t
+ivi_layout_addNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata);
+
+void
+ivi_layout_removeNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is configured
+ */
+int32_t
+ivi_layout_addNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata);
+
+void
+ivi_layout_removeNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief get id of surface from ivi_layout_surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+uint32_t
+ivi_layout_getIdOfSurface(struct ivi_layout_surface *ivisurf);
+
+/**
+ * \brief get id of layer from ivi_layout_layer
+ *
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+uint32_t
+ivi_layout_getIdOfLayer(struct ivi_layout_layer *ivilayer);
+
+/**
+ * \brief get ivi_layout_layer from id of layer
+ *
+ * \return (struct ivi_layout_layer *)
+ * if the method call was successful
+ * \return NULL if the method call was failed
+ */
+struct ivi_layout_layer *
+ivi_layout_getLayerFromId(uint32_t id_layer);
+
+/**
+ * \brief get ivi_layout_surface from id of surface
+ *
+ * \return (struct ivi_layout_surface *)
+ * if the method call was successful
+ * \return NULL if the method call was failed
+ */
+struct ivi_layout_surface *
+ivi_layout_getSurfaceFromId(uint32_t id_surface);
+
+/**
+ * \brief get ivi_layout_screen from id of screen
+ *
+ * \return (struct ivi_layout_screen *)
+ * if the method call was successful
+ * \return NULL if the method call was failed
+ */
+struct ivi_layout_screen *
+ivi_layout_getScreenFromId(uint32_t id_screen);
+
+/**
+ * \brief Get the screen resolution of a specific screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getScreenResolution(struct ivi_layout_screen *iviscrn,
+ uint32_t *pWidth,
+ uint32_t *pHeight);
+
+/**
+ * \brief register for notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceAddNotification(struct ivi_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceRemoveNotification(struct ivi_layout_surface *ivisurf);
+
+/**
+ * \brief Create a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+/*
+struct ivi_layout_surface *
+ivi_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface);
+*/
+
+/**
+ * \brief Set the native content of an application to be used as surface content.
+ * If wl_surface is NULL, remove the native content of a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+/*
+int32_t
+ivi_layout_surfaceSetNativeContent(struct weston_surface *wl_surface,
+ uint32_t width,
+ uint32_t height,
+ uint32_t id_surface);
+*/
+
+/**
+ * \brief initialize ivi_layout_surface dest/source width and height
+ */
+/*
+void
+ivi_layout_surfaceConfigure(struct ivi_layout_surface *ivisurf,
+ uint32_t width, uint32_t height);
+*/
+
+/**
+ * \brief Remove a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceRemove(struct ivi_layout_surface *ivisurf);
+
+/**
+ * \brief Set from which kind of devices the surface can accept input events.
+ * By default, a surface accept input events from all kind of devices (keyboards, pointer, ...)
+ * By calling this function, you can adjust surface preferences. Note that this function only
+ * adjust the acceptance for the specified devices. Non specified are keept untouched.
+ *
+ * Typicall use case for this function is when dealing with pointer or touch events.
+ * Those are normally dispatched to the first visible surface below the coordinate.
+ * If you want a different behavior (i.e. forward events to an other surface below the coordinate,
+ * you can set all above surfaces to refuse input events)
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_UpdateInputEventAcceptanceOn(struct ivi_layout_surface *ivisurf,
+ uint32_t devices,
+ uint32_t acceptance);
+
+/**
+ * \brief Get the layer properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getPropertiesOfLayer(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_LayerProperties *pLayerProperties);
+
+/**
+ * \brief Get the number of hardware layers of a screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ uint32_t *pNumberOfHardwareLayers);
+
+/**
+ * \brief Get the screens
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getScreens(uint32_t *pLength, ivi_layout_screen_ptr **ppArray);
+
+/**
+ * \brief Get the screens under the given layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getScreensUnderLayer(struct ivi_layout_layer *ivilayer,
+ uint32_t *pLength,
+ ivi_layout_screen_ptr **ppArray);
+
+/**
+ * \brief Get all Layers which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getLayers(uint32_t *pLength, ivi_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Layers of the given screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getLayersOnScreen(struct ivi_layout_screen *iviscrn,
+ uint32_t *pLength,
+ ivi_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Layers under the given surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getLayersUnderSurface(struct ivi_layout_surface *ivisurf,
+ uint32_t *pLength,
+ ivi_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getSurfaces(uint32_t *pLength, ivi_layout_surface_ptr **ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered to a given layer and are managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getSurfacesOnLayer(struct ivi_layout_layer *ivilayer,
+ uint32_t *pLength,
+ ivi_layout_surface_ptr **ppArray);
+
+/**
+ * \brief Create a layer which should be managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+struct ivi_layout_layer *
+ivi_layout_layerCreateWithDimension(uint32_t id_layer,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Removes a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerRemove(struct ivi_layout_layer *ivilayer);
+
+/**
+ * \brief Get the current type of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetType(struct ivi_layout_layer *ivilayer,
+ uint32_t *pLayerType);
+
+/**
+ * \brief Set the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetVisibility(struct ivi_layout_layer *ivilayer,
+ uint32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetVisibility(struct ivi_layout_layer *ivilayer,
+ uint32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetOpacity(struct ivi_layout_layer *ivilayer, float opacity);
+
+/**
+ * \brief Get the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetOpacity(struct ivi_layout_layer *ivilayer, float *pOpacity);
+
+/**
+ * \brief Set the area of a layer which should be used for the rendering.
+ * Only this part will be visible.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetSourceRectangle(struct ivi_layout_layer *ivilayer,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Set the destination area on the display for a layer.
+ * The layer will be scaled and positioned to this rectangle for rendering
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetDestinationRectangle(struct ivi_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetDimension(struct ivi_layout_layer *ivilayer,
+ uint32_t *pDimension);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetDimension(struct ivi_layout_layer *ivilayer,
+ uint32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetPosition(struct ivi_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetPosition(struct ivi_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetOrientation(struct ivi_layout_layer *ivilayer,
+ uint32_t orientation);
+
+/**
+ * \brief Gets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetOrientation(struct ivi_layout_layer *ivilayer,
+ uint32_t *pOrientation);
+
+/**
+ * \brief Sets the color value which defines the transparency value.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetChromaKey(struct ivi_layout_layer *ivilayer,
+ uint32_t* pColor);
+
+/**
+ * \brief Sets render order of surfaces within one layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetRenderOrder(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface **pSurface,
+ uint32_t number);
+
+/**
+ * \brief Get the capabilities of a layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetCapabilities(struct ivi_layout_layer *ivilayer,
+ uint32_t *pCapabilities);
+
+/**
+ * \brief Get the possible capabilities of a layertype
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerTypeGetCapabilities(uint32_t layerType,
+ uint32_t *pCapabilities);
+
+/**
+ * \brief Create the logical surface, which has no native buffer associated
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceInitialize(struct ivi_layout_surface **pSurface);
+
+/**
+ * \brief Set the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetVisibility(struct ivi_layout_surface *ivisurf,
+ uint32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetVisibility(struct ivi_layout_surface *ivisurf,
+ uint32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetOpacity(struct ivi_layout_surface *ivisurf,
+ float opacity);
+
+/**
+ * \brief Get the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetOpacity(struct ivi_layout_surface *ivisurf,
+ float *pOpacity);
+
+/**
+ * \brief Set the keyboard focus on a certain surface
+ * To receive keyboard events, 2 conditions must be fulfilled:
+ * 1- The surface must accept events from keyboard. See ilm_UpdateInputEventAcceptanceOn
+ * 2- The keyboard focus must be set on that surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_SetKeyboardFocusOn(struct ivi_layout_surface *ivisurf);
+
+/**
+ * \brief Get the indentifier of the surface which hold the keyboard focus
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_GetKeyboardFocusSurfaceId(struct ivi_layout_surface **pSurfaceId);
+
+/**
+ * \brief Set the destination area of a surface within a layer for rendering.
+ * The surface will be scaled to this rectangle for rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetDestinationRectangle(struct ivi_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetDimension(struct ivi_layout_surface *ivisurf,
+ uint32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetDimension(struct ivi_layout_surface *ivisurf,
+ uint32_t *pDimension);
+
+/**
+ * \brief Sets the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetPosition(struct ivi_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Get the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetPosition(struct ivi_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetOrientation(struct ivi_layout_surface *ivisurf,
+ uint32_t orientation);
+
+/**
+ * \brief Gets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetOrientation(struct ivi_layout_surface *ivisurf,
+ uint32_t *pOrientation);
+
+/**
+ * \brief Gets the pixelformat of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetPixelformat(struct ivi_layout_layer *ivisurf,
+ uint32_t *pPixelformat);
+
+/**
+ * \brief Sets the color value which defines the transparency value of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetChromaKey(struct ivi_layout_surface *ivisurf,
+ uint32_t* pColor);
+
+/**
+ * \brief Add a layer to a screen which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_screenAddLayer(struct ivi_layout_screen *iviscrn,
+ struct ivi_layout_layer *addlayer);
+
+/**
+ * \brief Sets render order of layers on a display
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_screenSetRenderOrder(struct ivi_layout_screen *iviscrn,
+ struct ivi_layout_layer **pLayer,
+ const uint32_t number);
+
+/**
+ * \brief Take a screenshot from the current displayed layer scene.
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_takeScreenshot(struct ivi_layout_screen *iviscrn,
+ const char *filename);
+
+/**
+ * \brief Take a screenshot of a certain layer
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_takeLayerScreenshot(const char *filename,
+ struct ivi_layout_layer *ivilayer);
+
+/**
+ * \brief Take a screenshot of a certain surface
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_takeSurfaceScreenshot(const char *filename,
+ struct ivi_layout_surface *ivisurf);
+
+/**
+ * \brief Enable or disable a rendering optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_SetOptimizationMode(uint32_t id, uint32_t mode);
+
+/**
+ * \brief Get the current enablement for an optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_GetOptimizationMode(uint32_t id, uint32_t *pMode);
+
+/**
+ * \brief register for notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerAddNotification(struct ivi_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerRemoveNotification(struct ivi_layout_layer *ivilayer);
+
+/**
+ * \brief Get the surface properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getPropertiesOfSurface(struct ivi_layout_surface *ivisurf,
+ struct ivi_layout_SurfaceProperties *pSurfaceProperties);
+
+/**
+ * \brief Add a surface to a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerAddSurface(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *addsurf);
+
+/**
+ * \brief Removes a surface from a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerRemoveSurface(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *remsurf);
+
+/**
+ * \brief Set the area of a surface which should be used for the rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetSourceRectangle(struct ivi_layout_surface *ivisurf,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Commit all changes and execute all enqueued commands since last commit.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_commitChanges(void);
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _IVI_LAYOUT_EXPORT_H_ */
diff --git a/ivi-shell/ivi-layout.c b/ivi-shell/ivi-layout.c
new file mode 100644
index 0000000..68f9b52
--- /dev/null
+++ b/ivi-shell/ivi-layout.c
@@ -0,0 +1,2798 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * Implementation of ivi-layout library. The actual view on screen is
+ * not updated till calling ivi_layout_commitChanges. A overview from
+ * calling API for updating properties of surfaces/layer to asking compositor
+ * to compose them by using weston_compositor_schedule_repaint,
+ * 0/ initialize this library by ivi_layout_initWithCompositor
+ * with (struct weston_compositor *ec) from ivi-shell.
+ * 1/ When a API for updating properties of surface/layer, it updates
+ * pending prop of ivi_layout_surface/layer/screen which are structure to
+ * store properties.
+ * 2/ Before calling commitChanges, in case of calling a API to get a property,
+ * return current property, not pending property.
+ * 3/ At the timing of calling ivi_layout_commitChanges, pending properties
+ * are applied
+ * to properties.
+ * 4/ According properties, set transformation by using weston_matrix and
+ * weston_view per surfaces and layers in while loop.
+ * 5/ Set damage and trigger transform by using weston_view_geometry_dirty and
+ * weston_view_geometry_dirty.
+ * 6/ Notify update of properties.
+ * 7/ Trigger composition by weston_compositor_schedule_repaint.
+ *
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <cairo.h>
+
+#include "compositor.h"
+#include "ivi-layout.h"
+#include "ivi-layout-export.h"
+
+enum ivi_layout_surface_orientation {
+ IVI_LAYOUT_SURFACE_ORIENTATION_0_DEGREES = 0,
+ IVI_LAYOUT_SURFACE_ORIENTATION_90_DEGREES = 1,
+ IVI_LAYOUT_SURFACE_ORIENTATION_180_DEGREES = 2,
+ IVI_LAYOUT_SURFACE_ORIENTATION_270_DEGREES = 3,
+};
+
+enum ivi_layout_surface_pixelformat {
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_R_8 = 0,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGB_888 = 1,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888 = 2,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGB_565 = 3,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_5551 = 4,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_6661 = 5,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_4444 = 6,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_UNKNOWN = 7,
+};
+
+struct link_layer {
+ struct ivi_layout_layer *ivilayer;
+ struct wl_list link;
+ struct wl_list link_to_layer;
+};
+
+struct link_screen {
+ struct ivi_layout_screen *iviscrn;
+ struct wl_list link;
+ struct wl_list link_to_screen;
+};
+
+struct link_layerPropertyNotification {
+ layerPropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfacePropertyNotification {
+ surfacePropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerCreateNotification {
+ layerCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerRemoveNotification {
+ layerRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceCreateNotification {
+ surfaceCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceRemoveNotification {
+ surfaceRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceConfigureNotification {
+ surfaceConfigureNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct ivi_layout;
+
+struct ivi_layout_surface {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_layer;
+ uint32_t update_count;
+ uint32_t id_surface;
+
+ struct ivi_layout *layout;
+ struct weston_surface *surface;
+ struct weston_view *view;
+
+ uint32_t buffer_width;
+ uint32_t buffer_height;
+
+ struct wl_listener surface_destroy_listener;
+ struct weston_transform surface_rotation;
+ struct weston_transform layer_rotation;
+ struct weston_transform surface_pos;
+ struct weston_transform layer_pos;
+ struct weston_transform scaling;
+ struct ivi_layout_SurfaceProperties prop;
+ int32_t pixelformat;
+ uint32_t event_mask;
+
+ struct {
+ struct ivi_layout_SurfaceProperties prop;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list link;
+ struct wl_list list_layer;
+ } order;
+};
+
+struct ivi_layout_layer {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_screen;
+ struct wl_list link_to_surface;
+ uint32_t id_layer;
+
+ struct ivi_layout *layout;
+
+ struct ivi_layout_LayerProperties prop;
+ uint32_t event_mask;
+
+ struct {
+ struct ivi_layout_LayerProperties prop;
+ struct wl_list list_surface;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_surface;
+ struct wl_list link;
+ } order;
+};
+
+struct ivi_layout_screen {
+ struct wl_list link;
+ struct wl_list link_to_layer;
+ uint32_t id_screen;
+
+ struct ivi_layout *layout;
+ struct weston_output *output;
+
+ uint32_t event_mask;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } order;
+};
+
+struct ivi_layout {
+ struct weston_compositor *compositor;
+
+ struct wl_list list_surface;
+ struct wl_list list_layer;
+ struct wl_list list_screen;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ } layer_notification;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ struct wl_list list_configure;
+ } surface_notification;
+
+ struct weston_layer layout_layer;
+};
+
+static struct ivi_layout ivilayout = {0};
+
+static struct ivi_layout *
+get_instance(void)
+{
+ return &ivilayout;
+}
+
+/**
+ * Internal API to add/remove a link to surface from layer.
+ */
+static void
+add_link_to_surface(struct ivi_layout_layer *ivilayer,
+ struct link_layer *link_layer)
+{
+ wl_list_init(&link_layer->link_to_layer);
+ wl_list_insert(&ivilayer->link_to_surface, &link_layer->link_to_layer);
+}
+
+static void
+remove_link_to_surface(struct ivi_layout_layer *ivilayer)
+{
+ struct link_layer *link = NULL;
+ struct link_layer *next = NULL;
+
+ wl_list_for_each_safe(link, next, &ivilayer->link_to_surface, link_to_layer) {
+ if (!wl_list_empty(&link->link_to_layer)) {
+ wl_list_remove(&link->link_to_layer);
+ }
+ free(link);
+ }
+
+ wl_list_init(&ivilayer->link_to_surface);
+}
+
+/**
+ * Internal API to add a link to layer from screen.
+ */
+static void
+add_link_to_layer(struct ivi_layout_screen *iviscrn,
+ struct link_screen *link_screen)
+{
+ wl_list_init(&link_screen->link_to_screen);
+ wl_list_insert(&iviscrn->link_to_layer, &link_screen->link_to_screen);
+}
+
+/**
+ * Internal API to add/remove a surface from layer.
+ */
+static void
+add_ordersurface_to_layer(struct ivi_layout_surface *ivisurf,
+ struct ivi_layout_layer *ivilayer)
+{
+ struct link_layer *link_layer = NULL;
+
+ link_layer = malloc(sizeof *link_layer);
+ if (link_layer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_layer->ivilayer = ivilayer;
+ wl_list_init(&link_layer->link);
+ wl_list_insert(&ivisurf->list_layer, &link_layer->link);
+ add_link_to_surface(ivilayer, link_layer);
+}
+
+static void
+remove_ordersurface_from_layer(struct ivi_layout_surface *ivisurf)
+{
+ struct link_layer *link_layer = NULL;
+ struct link_layer *next = NULL;
+
+ wl_list_for_each_safe(link_layer, next, &ivisurf->list_layer, link) {
+ if (!wl_list_empty(&link_layer->link)) {
+ wl_list_remove(&link_layer->link);
+ }
+ free(link_layer);
+ }
+ wl_list_init(&ivisurf->list_layer);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static void
+add_orderlayer_to_screen(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_screen *iviscrn)
+{
+ struct link_screen *link_scrn = NULL;
+
+ link_scrn = malloc(sizeof *link_scrn);
+ if (link_scrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_scrn->iviscrn = iviscrn;
+ wl_list_init(&link_scrn->link);
+ wl_list_insert(&ivilayer->list_screen, &link_scrn->link);
+ add_link_to_layer(iviscrn, link_scrn);
+}
+
+static void
+remove_orderlayer_from_screen(struct ivi_layout_layer *ivilayer)
+{
+ struct link_screen *link_scrn = NULL;
+ struct link_screen *next = NULL;
+
+ wl_list_for_each_safe(link_scrn, next, &ivilayer->list_screen, link) {
+ if (!wl_list_empty(&link_scrn->link)) {
+ wl_list_remove(&link_scrn->link);
+ }
+ free(link_scrn);
+ }
+ wl_list_init(&ivilayer->list_screen);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static struct ivi_layout_surface *
+get_surface(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct ivi_layout_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+static struct ivi_layout_layer *
+get_layer(struct wl_list *list_layer, uint32_t id_layer)
+{
+ struct ivi_layout_layer *ivilayer;
+
+ wl_list_for_each(ivilayer, list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Called at destruction of ivi_surface
+ */
+static void
+westonsurface_destroy_from_ivisurface(struct wl_listener *listener, void *data)
+{
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ ivisurf = container_of(listener, struct ivi_layout_surface,
+ surface_destroy_listener);
+ ivisurf->surface = NULL;
+ ivisurf->view = NULL;
+ ivi_layout_surfaceRemove(ivisurf);
+}
+
+/**
+ * Internal API to check layer/surface already added in layer/screen.
+ * Called by ivi_layout_layerAddSurface/ivi_layout_screenAddLayer
+ */
+static int
+is_surface_in_layer(struct ivi_layout_surface *ivisurf,
+ struct ivi_layout_layer *ivilayer)
+{
+ struct ivi_layout_surface *surf = NULL;
+
+ wl_list_for_each(surf, &ivilayer->pending.list_surface, pending.link) {
+ if (surf->id_surface == ivisurf->id_surface) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+is_layer_in_screen(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_screen *iviscrn)
+{
+ struct ivi_layout_layer *layer = NULL;
+
+ wl_list_for_each(layer, &iviscrn->pending.list_layer, pending.link) {
+ if (layer->id_layer == ivilayer->id_layer) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Internal API to initialize screens found from output_list of weston_compositor.
+ * Called by ivi_layout_initWithCompositor.
+ */
+static void
+create_screen(struct weston_compositor *ec)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_screen *iviscrn = NULL;
+ struct weston_output *output = NULL;
+ int32_t count = 0;
+
+ wl_list_for_each(output, &ec->output_list, link) {
+ iviscrn = calloc(1, sizeof *iviscrn);
+ if (iviscrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ continue;
+ }
+
+ wl_list_init(&iviscrn->link);
+ iviscrn->layout = layout;
+
+ iviscrn->id_screen = count;
+ count++;
+
+ iviscrn->output = output;
+ iviscrn->event_mask = 0;
+
+ wl_list_init(&iviscrn->pending.list_layer);
+ wl_list_init(&iviscrn->pending.link);
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_init(&iviscrn->order.link);
+
+ wl_list_init(&iviscrn->link_to_layer);
+
+ wl_list_insert(&layout->list_screen, &iviscrn->link);
+ }
+}
+
+/**
+ * Internal APIs to initialize properties of surface/layer when they are created.
+ */
+static void
+init_layerProperties(struct ivi_layout_LayerProperties *prop,
+ int32_t width, int32_t height)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+ prop->destWidth = width;
+ prop->destHeight = height;
+}
+
+static void
+init_surfaceProperties(struct ivi_layout_SurfaceProperties *prop)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+}
+
+/**
+ * Internal APIs to be called from ivi_layout_commitChanges.
+ */
+static void
+update_opacity(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ double layer_alpha = wl_fixed_to_double(ivilayer->prop.opacity);
+ double surf_alpha = wl_fixed_to_double(ivisurf->prop.opacity);
+
+ if ((ivilayer->event_mask & IVI_NOTIFICATION_OPACITY) ||
+ (ivisurf->event_mask & IVI_NOTIFICATION_OPACITY)) {
+ if (ivisurf->view == NULL) {
+ return;
+ }
+ ivisurf->view->alpha = layer_alpha * surf_alpha;
+ }
+}
+
+static void
+update_surface_orientation(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->surface_rotation.matrix;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ if (view == NULL) {
+ return;
+ }
+
+ if ((ivilayer->prop.destWidth == 0) ||
+ (ivilayer->prop.destHeight == 0)) {
+ return;
+ }
+ width = (float)ivilayer->prop.destWidth;
+ height = (float)ivilayer->prop.destHeight;
+
+ switch (ivisurf->prop.orientation) {
+ case IVI_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->surface_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_layer_orientation(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ struct weston_surface *es = ivisurf->surface;
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->layer_rotation.matrix;
+ struct weston_output *output = NULL;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ if (es == NULL || view == NULL) {
+ return;
+ }
+
+ output = es->output;
+ if (output == NULL) {
+ return;
+ }
+ if ((output->width == 0) || (output->height == 0)) {
+ return;
+ }
+ width = (float)output->width;
+ height = (float)output->height;
+
+ switch (ivilayer->prop.orientation) {
+ case IVI_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->layer_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->layer_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_surface_position(struct ivi_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ float tx = (float)ivisurf->prop.destX;
+ float ty = (float)ivisurf->prop.destY;
+ struct weston_matrix *matrix = &ivisurf->surface_pos.matrix;
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->surface_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+
+#if 0
+ /* disable zoom animation */
+ weston_zoom_run(es, 0.0, 1.0, NULL, NULL);
+#endif
+
+}
+
+static void
+update_layer_position(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->layer_pos.matrix;
+ float tx = (float)ivilayer->prop.destX;
+ float ty = (float)ivilayer->prop.destY;
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->layer_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(
+ &view->geometry.transformation_list,
+ &ivisurf->layer_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_scale(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->scaling.matrix;
+ float sx = 0.0f;
+ float sy = 0.0f;
+ float lw = 0.0f;
+ float sw = 0.0f;
+ float lh = 0.0f;
+ float sh = 0.0f;
+
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->prop.sourceWidth == 0 && ivisurf->prop.sourceHeight == 0) {
+ ivisurf->prop.sourceWidth = ivisurf->buffer_width;
+ ivisurf->prop.sourceHeight = ivisurf->buffer_height;
+
+ if (ivisurf->prop.destWidth == 0 && ivisurf->prop.destHeight == 0) {
+ ivisurf->prop.destWidth = ivisurf->buffer_width;
+ ivisurf->prop.destHeight = ivisurf->buffer_height;
+ }
+ }
+
+ lw = ((float)ivilayer->prop.destWidth / ivilayer->prop.sourceWidth );
+ sw = ((float)ivisurf->prop.destWidth / ivisurf->prop.sourceWidth );
+ lh = ((float)ivilayer->prop.destHeight / ivilayer->prop.sourceHeight);
+ sh = ((float)ivisurf->prop.destHeight / ivisurf->prop.sourceHeight );
+ sx = sw * lw;
+ sy = sh * lh;
+
+ wl_list_remove(&ivisurf->scaling.link);
+ weston_matrix_init(matrix);
+ weston_matrix_scale(matrix, sx, sy, 1.0f);
+
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->scaling.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_prop(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ if (ivilayer->event_mask | ivisurf->event_mask) {
+ update_opacity(ivilayer, ivisurf);
+ update_layer_orientation(ivilayer, ivisurf);
+ update_layer_position(ivilayer, ivisurf);
+ update_surface_position(ivisurf);
+ update_surface_orientation(ivilayer, ivisurf);
+ update_scale(ivilayer, ivisurf);
+
+ ivisurf->update_count++;
+
+ if (ivisurf->view != NULL) {
+ weston_view_geometry_dirty(ivisurf->view);
+ }
+
+ if (ivisurf->surface != NULL) {
+ weston_surface_damage(ivisurf->surface);
+ }
+ }
+}
+
+static void
+commit_changes(struct ivi_layout *layout)
+{
+ struct ivi_layout_screen *iviscrn = NULL;
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ update_prop(ivilayer, ivisurf);
+ }
+ }
+ }
+}
+
+static void
+commit_list_surface(struct ivi_layout *layout)
+{
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ ivisurf->prop = ivisurf->pending.prop;
+ }
+}
+
+static void
+commit_list_layer(struct ivi_layout *layout)
+{
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_surface *next = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ ivilayer->prop = ivilayer->pending.prop;
+
+ if (!(ivilayer->event_mask &
+ (IVI_NOTIFICATION_ADD | IVI_NOTIFICATION_REMOVE)) ) {
+ continue;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->order.list_surface, order.link) {
+ remove_ordersurface_from_layer(ivisurf);
+
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_for_each(ivisurf, &ivilayer->pending.list_surface,
+ pending.link) {
+ if(!wl_list_empty(&ivisurf->order.link)){
+ wl_list_remove(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_insert(&ivilayer->order.list_surface,
+ &ivisurf->order.link);
+ add_ordersurface_to_layer(ivisurf, ivilayer);
+ }
+ }
+}
+
+static void
+commit_list_screen(struct ivi_layout *layout)
+{
+ struct ivi_layout_screen *iviscrn = NULL;
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_layer *next = NULL;
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ if (iviscrn->event_mask & IVI_NOTIFICATION_ADD) {
+ wl_list_for_each_safe(ivilayer, next,
+ &iviscrn->order.list_layer, order.link) {
+ remove_orderlayer_from_screen(ivilayer);
+
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.link);
+ }
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_for_each(ivilayer, &iviscrn->pending.list_layer,
+ pending.link) {
+ wl_list_insert(&iviscrn->order.list_layer,
+ &ivilayer->order.link);
+ add_orderlayer_to_screen(ivilayer, iviscrn);
+ }
+ iviscrn->event_mask = 0;
+ }
+
+ /* Clear view list of layout layer */
+ wl_list_init(&layout->layout_layer.view_list);
+
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+
+ if (ivilayer->prop.visibility == 0)
+ continue;
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+
+ if (ivisurf->prop.visibility == 0)
+ continue;
+ if (ivisurf->surface == NULL || ivisurf->view == NULL)
+ continue;
+
+ wl_list_insert(&layout->layout_layer.view_list,
+ &ivisurf->view->layer_link);
+
+ ivisurf->surface->output = iviscrn->output;
+ }
+ }
+
+ break;
+ }
+}
+
+static void
+send_surface_prop(struct ivi_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivisurf->list_notification, link) {
+ notification->callback(ivisurf, &ivisurf->prop,
+ ivisurf->event_mask,
+ notification->userdata);
+ }
+
+ ivisurf->event_mask = 0;
+}
+
+static void
+send_layer_prop(struct ivi_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivilayer->list_notification, link) {
+ notification->callback(ivilayer, &ivilayer->prop,
+ ivilayer->event_mask,
+ notification->userdata);
+ }
+
+ ivilayer->event_mask = 0;
+}
+
+static void
+send_prop(struct ivi_layout *layout)
+{
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ send_layer_prop(ivilayer);
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ send_surface_prop(ivisurf);
+ }
+}
+
+/**
+ * Exported APIs of ivi-layout library are implemented from here.
+ * Brief of APIs is described in ivi-layout-export.h.
+ */
+WL_EXPORT int32_t
+ivi_layout_addNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_layerCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("ivi_layout_addNotificationCreateLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT void
+ivi_layout_removeNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_layerCreateNotification *link = NULL;
+ struct link_layerCreateNotification *next = NULL;
+
+ wl_list_for_each_safe(link, next, &layout->layer_notification.list_create, link) {
+ if ((link->callback == callback) &&
+ (link->userdata == userdata)) {
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+
+ free(link);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+ivi_layout_addNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("ivi_layout_addNotificationRemoveLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT void
+ivi_layout_removeNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_layerRemoveNotification *link = NULL;
+ struct link_layerRemoveNotification *next = NULL;
+
+ wl_list_for_each_safe(link, next, &layout->layer_notification.list_remove, link) {
+ if ((link->callback == callback) &&
+ (link->userdata == userdata)) {
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+
+ free(link);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+ivi_layout_addNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("ivi_layout_addNotificationCreateSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT void
+ivi_layout_removeNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *link = NULL;
+ struct link_surfaceCreateNotification *next = NULL;
+
+ wl_list_for_each_safe(link, next, &layout->surface_notification.list_create, link) {
+ if ((link->callback == callback) &&
+ (link->userdata == userdata)) {
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+
+ free(link);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+ivi_layout_addNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("ivi_layout_addNotificationRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT void
+ivi_layout_removeNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *link = NULL;
+ struct link_surfaceRemoveNotification *next = NULL;
+
+ wl_list_for_each_safe(link, next, &layout->surface_notification.list_remove, link) {
+ if ((link->callback == callback) &&
+ (link->userdata == userdata)) {
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+
+ free(link);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+ivi_layout_addNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceConfigureNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("ivi_layout_addNotificationConfigureSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_configure, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT void
+ivi_layout_removeNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceConfigureNotification *link = NULL;
+ struct link_surfaceConfigureNotification *next = NULL;
+
+ wl_list_for_each_safe(link, next, &layout->surface_notification.list_configure, link) {
+ if ((link->callback == callback) &&
+ (link->userdata == userdata)) {
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+
+ free(link);
+ }
+ }
+}
+
+WL_EXPORT uint32_t
+ivi_layout_getIdOfSurface(struct ivi_layout_surface *ivisurf)
+{
+ return ivisurf->id_surface;
+}
+
+WL_EXPORT uint32_t
+ivi_layout_getIdOfLayer(struct ivi_layout_layer *ivilayer)
+{
+ return ivilayer->id_layer;
+}
+
+WL_EXPORT struct ivi_layout_layer *
+ivi_layout_getLayerFromId(uint32_t id_layer)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_layer *ivilayer = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct ivi_layout_surface *
+ivi_layout_getSurfaceFromId(uint32_t id_surface)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct ivi_layout_screen *
+ivi_layout_getScreenFromId(uint32_t id_screen)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_screen *iviscrn = NULL;
+ (void)id_screen;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+//FIXME : select iviscrn from list_screen by id_screen
+ return iviscrn;
+ break;
+ }
+
+ return NULL;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getScreenResolution(struct ivi_layout_screen *iviscrn,
+ uint32_t *pWidth, uint32_t *pHeight)
+{
+ struct weston_output *output = NULL;
+
+ if (pWidth == NULL || pHeight == NULL) {
+ weston_log("ivi_layout_getScreenResolution: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ *pWidth = output->current_mode->width;
+ *pHeight = output->current_mode->height;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceAddNotification(struct ivi_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ if (ivisurf == NULL || callback == NULL) {
+ weston_log("ivi_layout_surfaceAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivisurf->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceRemoveNotification(struct ivi_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+ struct link_surfacePropertyNotification *next = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivisurf->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ }
+ wl_list_init(&ivisurf->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceRemove(struct ivi_layout_surface *ivisurf)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceRemove: invalid argument\n");
+ return -1;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+ if (!wl_list_empty(&ivisurf->link)) {
+ wl_list_remove(&ivisurf->link);
+ }
+ remove_ordersurface_from_layer(ivisurf);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ free(ivisurf);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_UpdateInputEventAcceptanceOn(struct ivi_layout_surface *ivisurf,
+ uint32_t devices, uint32_t acceptance)
+{
+ /* TODO */
+ (void)ivisurf;
+ (void)devices;
+ (void)acceptance;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceInitialize(struct ivi_layout_surface **pSurfaceId)
+{
+ /* TODO */
+ (void)pSurfaceId;
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getPropertiesOfLayer(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_LayerProperties *pLayerProperties)
+{
+ if (ivilayer == NULL || pLayerProperties == NULL) {
+ weston_log("ivi_layout_getPropertiesOfLayer: invalid argument\n");
+ return -1;
+ }
+
+ *pLayerProperties = ivilayer->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ uint32_t *pNumberOfHardwareLayers)
+{
+ /* TODO */
+ (void)id_screen;
+ (void)pNumberOfHardwareLayers;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getScreens(uint32_t *pLength, ivi_layout_screen_ptr **ppArray)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_screen *iviscrn = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getScreens: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(ivi_layout_screen_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ (*ppArray)[n++] = iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getScreensUnderLayer(struct ivi_layout_layer *ivilayer,
+ uint32_t *pLength,
+ ivi_layout_screen_ptr **ppArray)
+{
+ struct link_screen *link_scrn = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getScreensUnderLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(ivi_layout_screen_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_scrn, &ivilayer->list_screen, link) {
+ (*ppArray)[n++] = link_scrn->iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getLayers(uint32_t *pLength, ivi_layout_layer_ptr **ppArray)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_layer *ivilayer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(ivi_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getLayersOnScreen(struct ivi_layout_screen *iviscrn,
+ uint32_t *pLength,
+ ivi_layout_layer_ptr **ppArray)
+{
+ struct ivi_layout_layer *ivilayer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (iviscrn == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getLayersOnScreen: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&iviscrn->order.list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(ivi_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getLayersUnderSurface(struct ivi_layout_surface *ivisurf,
+ uint32_t *pLength,
+ ivi_layout_layer_ptr **ppArray)
+{
+ struct link_layer *link_layer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivisurf == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivisurf->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(ivi_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_layer, &ivisurf->list_layer, link) {
+ (*ppArray)[n++] = link_layer->ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getSurfaces(uint32_t *pLength, ivi_layout_surface_ptr **ppArray)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getSurfaces: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_surface);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(ivi_layout_surface_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getSurfacesOnLayer(struct ivi_layout_layer *ivilayer,
+ uint32_t *pLength,
+ ivi_layout_surface_ptr **ppArray)
+{
+ struct ivi_layout_surface *ivisurf = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getSurfaceIDsOnLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->order.list_surface);
+
+ if (length != 0) {
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(ivi_layout_surface_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT struct ivi_layout_layer *
+ivi_layout_layerCreateWithDimension(uint32_t id_layer,
+ uint32_t width, uint32_t height)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct link_layerCreateNotification *notification = NULL;
+
+ ivilayer = get_layer(&layout->list_layer, id_layer);
+ if (ivilayer != NULL) {
+ weston_log("id_layer is already created\n");
+ return ivilayer;
+ }
+
+ ivilayer = calloc(1, sizeof *ivilayer);
+ if (ivilayer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivilayer->link);
+ wl_list_init(&ivilayer->list_notification);
+ wl_list_init(&ivilayer->list_screen);
+ wl_list_init(&ivilayer->link_to_surface);
+ ivilayer->layout = layout;
+ ivilayer->id_layer = id_layer;
+
+ init_layerProperties(&ivilayer->prop, width, height);
+ ivilayer->event_mask = 0;
+
+ wl_list_init(&ivilayer->pending.list_surface);
+ wl_list_init(&ivilayer->pending.link);
+ ivilayer->pending.prop = ivilayer->prop;
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_init(&ivilayer->order.link);
+
+ wl_list_insert(&layout->list_layer, &ivilayer->link);
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ return ivilayer;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerRemove(struct ivi_layout_layer *ivilayer)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerRemove: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+ if (!wl_list_empty(&ivilayer->link)) {
+ wl_list_remove(&ivilayer->link);
+ }
+ remove_orderlayer_from_screen(ivilayer);
+ remove_link_to_surface(ivilayer);
+
+ free(ivilayer);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetType(struct ivi_layout_layer *ivilayer,
+ uint32_t *pLayerType)
+{
+ /* TODO */
+ (void)ivilayer;
+ (void)pLayerType;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetVisibility(struct ivi_layout_layer *ivilayer,
+ uint32_t newVisibility)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetVisibility(struct ivi_layout_layer *ivilayer, uint32_t *pVisibility)
+{
+ if (ivilayer == NULL || pVisibility == NULL) {
+ weston_log("ivi_layout_layerGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivilayer->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetOpacity(struct ivi_layout_layer *ivilayer,
+ float opacity)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->opacity = opacity;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetOpacity(struct ivi_layout_layer *ivilayer,
+ float *pOpacity)
+{
+ if (ivilayer == NULL || pOpacity == NULL) {
+ weston_log("ivi_layout_layerGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivilayer->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetSourceRectangle(struct ivi_layout_layer *ivilayer,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetDestinationRectangle(struct ivi_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetDimension(struct ivi_layout_layer *ivilayer,
+ uint32_t *pDimension)
+{
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("ivi_layout_layerGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivilayer->prop.destX;
+ pDimension[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetDimension(struct ivi_layout_layer *ivilayer,
+ uint32_t *pDimension)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("ivi_layout_layerSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetPosition(struct ivi_layout_layer *ivilayer, int32_t *pPosition)
+{
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("ivi_layout_layerGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivilayer->prop.destX;
+ pPosition[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetPosition(struct ivi_layout_layer *ivilayer, int32_t *pPosition)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("ivi_layout_layerSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetOrientation(struct ivi_layout_layer *ivilayer,
+ uint32_t orientation)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->orientation = orientation;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetOrientation(struct ivi_layout_layer *ivilayer,
+ uint32_t *pOrientation)
+{
+ if (ivilayer == NULL || pOrientation == NULL) {
+ weston_log("ivi_layout_layerGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivilayer->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetChromaKey(struct ivi_layout_layer *ivilayer, uint32_t* pColor)
+{
+ /* TODO */
+ (void)ivilayer;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetRenderOrder(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface **pSurface,
+ uint32_t number)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_surface *next = NULL;
+ uint32_t *id_surface = NULL;
+ uint32_t i = 0;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ if (pSurface == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_surface = &pSurface[i]->id_surface;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (*id_surface != ivisurf->id_surface) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetCapabilities(struct ivi_layout_layer *ivilayer,
+ uint32_t *pCapabilities)
+{
+ /* TODO */
+ (void)ivilayer;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerTypeGetCapabilities(uint32_t layerType,
+ uint32_t *pCapabilities)
+{
+ /* TODO */
+ (void)layerType;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetVisibility(struct ivi_layout_surface *ivisurf,
+ uint32_t newVisibility)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetVisibility(struct ivi_layout_surface *ivisurf,
+ uint32_t *pVisibility)
+{
+ if (ivisurf == NULL || pVisibility == NULL) {
+ weston_log("ivi_layout_surfaceGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivisurf->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetOpacity(struct ivi_layout_surface *ivisurf,
+ float opacity)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->opacity = opacity;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetOpacity(struct ivi_layout_surface *ivisurf,
+ float *pOpacity)
+{
+ if (ivisurf == NULL || pOpacity == NULL) {
+ weston_log("ivi_layout_surfaceGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivisurf->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_SetKeyboardFocusOn(struct ivi_layout_surface *ivisurf)
+{
+ /* TODO */
+ (void)ivisurf;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_GetKeyboardFocusSurfaceId(struct ivi_layout_surface **pSurfaceId)
+{
+ /* TODO */
+ (void)pSurfaceId;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetDestinationRectangle(struct ivi_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetDimension(struct ivi_layout_surface *ivisurf, uint32_t *pDimension)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("ivi_layout_surfaceSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetDimension(struct ivi_layout_surface *ivisurf,
+ uint32_t *pDimension)
+{
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("ivi_layout_surfaceGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivisurf->prop.destWidth;
+ pDimension[1] = ivisurf->prop.destHeight;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetPosition(struct ivi_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("ivi_layout_surfaceSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetPosition(struct ivi_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("ivi_layout_surfaceGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivisurf->prop.destX;
+ pPosition[1] = ivisurf->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetOrientation(struct ivi_layout_surface *ivisurf,
+ uint32_t orientation)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->orientation = orientation;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetOrientation(struct ivi_layout_surface *ivisurf,
+ uint32_t *pOrientation)
+{
+ if (ivisurf == NULL || pOrientation == NULL) {
+ weston_log("ivi_layout_surfaceGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivisurf->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetPixelformat(struct ivi_layout_layer *ivisurf, uint32_t *pPixelformat)
+{
+ /* TODO */
+ (void)ivisurf;
+ (void)pPixelformat;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetChromaKey(struct ivi_layout_surface *ivisurf, uint32_t* pColor)
+{
+ /* TODO */
+ (void)ivisurf;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_screenAddLayer(struct ivi_layout_screen *iviscrn,
+ struct ivi_layout_layer *addlayer)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_layer *next = NULL;
+ int is_layer_in_scrn = 0;
+
+ if (iviscrn == NULL || addlayer == NULL) {
+ weston_log("ivi_layout_screenAddLayer: invalid argument\n");
+ return -1;
+ }
+
+ is_layer_in_scrn = is_layer_in_screen(addlayer, iviscrn);
+ if (is_layer_in_scrn == 1) {
+ weston_log("ivi_layout_screenAddLayer: addlayer is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivilayer, next, &layout->list_layer, link) {
+ if (ivilayer->id_layer == addlayer->id_layer) {
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_screenSetRenderOrder(struct ivi_layout_screen *iviscrn,
+ struct ivi_layout_layer **pLayer,
+ const uint32_t number)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_layer *next = NULL;
+ uint32_t *id_layer = NULL;
+ uint32_t i = 0;
+
+ if (iviscrn == NULL) {
+ weston_log("ivi_layout_screenSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(ivilayer, next,
+ &iviscrn->pending.list_layer, pending.link) {
+ wl_list_init(&ivilayer->pending.link);
+ }
+
+ wl_list_init(&iviscrn->pending.list_layer);
+
+ if (pLayer == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_layer = &pLayer[i]->id_layer;
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (*id_layer != ivilayer->id_layer) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_takeScreenshot(struct ivi_layout_screen *iviscrn,
+ const char *filename)
+{
+ struct weston_output *output = NULL;
+ cairo_surface_t *cairo_surf = NULL;
+ int32_t i = 0;
+ int32_t width = 0;
+ int32_t height = 0;
+ int32_t stride = 0;
+ uint8_t *readpixs = NULL;
+ uint8_t *writepixs = NULL;
+ uint8_t *d = NULL;
+ uint8_t *s = NULL;
+
+ if (iviscrn == NULL || filename == NULL) {
+ weston_log("ivi_layout_takeScreenshot: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ output->disable_planes--;
+
+ width = output->current_mode->width;
+ height = output->current_mode->height;
+ stride = width * (PIXMAN_FORMAT_BPP(output->compositor->read_format) / 8);
+
+ readpixs = malloc(stride * height);
+ if (readpixs == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+ writepixs = malloc(stride * height);
+ if (writepixs == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ output->compositor->renderer->read_pixels(output,
+ output->compositor->read_format, readpixs,
+ 0, 0, width, height);
+
+ s = readpixs;
+ d = writepixs + stride * (height - 1);
+
+ for (i = 0; i < height; i++) {
+ memcpy(d, s, stride);
+ d -= stride;
+ s += stride;
+ }
+
+ cairo_surf = cairo_image_surface_create_for_data(writepixs,
+ CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+ cairo_surface_write_to_png(cairo_surf, filename);
+ cairo_surface_destroy(cairo_surf);
+ free(writepixs);
+ free(readpixs);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_takeLayerScreenshot(const char *filename, struct ivi_layout_layer *ivilayer)
+{
+ /* TODO */
+ (void)filename;
+ (void)ivilayer;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_takeSurfaceScreenshot(const char *filename,
+ struct ivi_layout_surface *ivisurf)
+{
+ weston_log("ivi_layout_takeSurfaceScreenshot: "
+ "This function is not supported now\n");
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_SetOptimizationMode(uint32_t id, uint32_t mode)
+{
+ /* TODO */
+ (void)id;
+ (void)mode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_GetOptimizationMode(uint32_t id, uint32_t *pMode)
+{
+ /* TODO */
+ (void)id;
+ (void)pMode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerAddNotification(struct ivi_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ if (ivilayer == NULL || callback == NULL) {
+ weston_log("ivi_layout_layerAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivilayer->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerRemoveNotification(struct ivi_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+ struct link_layerPropertyNotification *next = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivilayer->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ }
+ wl_list_init(&ivilayer->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getPropertiesOfSurface(struct ivi_layout_surface *ivisurf,
+ struct ivi_layout_SurfaceProperties *pSurfaceProperties)
+{
+ if (ivisurf == NULL || pSurfaceProperties == NULL) {
+ weston_log("ivi_layout_getPropertiesOfSurface: invalid argument\n");
+ return -1;
+ }
+
+ *pSurfaceProperties = ivisurf->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerAddSurface(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *addsurf)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_surface *next = NULL;
+ int is_surf_in_layer = 0;
+
+ if (ivilayer == NULL || addsurf == NULL) {
+ weston_log("ivi_layout_layerAddSurface: invalid argument\n");
+ return -1;
+ }
+
+ is_surf_in_layer = is_surface_in_layer(addsurf, ivilayer);
+ if (is_surf_in_layer == 1) {
+ weston_log("ivi_layout_layerAddSurface: addsurf is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivisurf, next, &layout->list_surface, link) {
+ if (ivisurf->id_surface == addsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerRemoveSurface(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *remsurf)
+{
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_surface *next = NULL;
+
+ if (ivilayer == NULL || remsurf == NULL) {
+ weston_log("ivi_layout_layerRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->pending.list_surface, pending.link) {
+ if (ivisurf->id_surface == remsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_REMOVE;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetSourceRectangle(struct ivi_layout_surface *ivisurf,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_commitChanges(void)
+{
+ struct ivi_layout *layout = get_instance();
+
+ commit_list_surface(layout);
+ commit_list_layer(layout);
+ commit_list_screen(layout);
+
+ commit_changes(layout);
+ send_prop(layout);
+ weston_compositor_schedule_repaint(layout->compositor);
+
+ return 0;
+}
+
+/***called from ivi-shell**/
+static struct weston_view *
+ivi_layout_get_weston_view(struct ivi_layout_surface *surface)
+{
+ return (surface != NULL) ? surface->view : NULL;
+}
+
+static void
+ivi_layout_surfaceConfigure(struct ivi_layout_surface *ivisurf,
+ uint32_t width, uint32_t height)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf->buffer_width = width;
+ ivisurf->buffer_height = height;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_configure, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+}
+
+static int32_t
+ivi_layout_surfaceSetNativeContent(struct weston_surface *surface,
+ uint32_t width,
+ uint32_t height,
+ uint32_t id_surface)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf == NULL) {
+ weston_log("layout surface is not found\n");
+ return -1;
+ }
+
+ if (ivisurf->surface != NULL) {
+ if (surface != NULL) {
+ weston_log("id_surface(%d) is already set the native content\n",
+ id_surface);
+ return -1;
+ }
+
+ wl_list_remove(&ivisurf->surface_destroy_listener.link);
+ weston_view_destroy(ivisurf->view);
+
+ ivisurf->surface = NULL;
+ ivisurf->view = NULL;
+ }
+
+ if (surface == NULL)
+ return 0;
+
+ ivisurf->surface = surface;
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(surface->resource,
+ &ivisurf->surface_destroy_listener);
+ ivisurf->view = weston_view_create(surface);
+ if (ivisurf->view == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ ivisurf->buffer_width = width;
+ ivisurf->buffer_height = height;
+ ivisurf->pixelformat = IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return 0;
+}
+
+static struct ivi_layout_surface*
+ivi_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (wl_surface == NULL) {
+ weston_log("ivi_layout_surfaceCreate: invalid argument\n");
+ return NULL;
+ }
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf != NULL) {
+ if (ivisurf->surface != NULL) {
+ weston_log("id_surface(%d) is already created\n", id_surface);
+ return NULL;
+ } else {
+ /* if ivisurf->surface exist, wl_surface is tied to id_surface again */
+ /* This means client destroys ivi_surface once, and then tries to tie
+ the id_surface to new wl_surface again. The property of id_surface can
+ be inherited.
+ */
+ ivi_layout_surfaceSetNativeContent(
+ wl_surface, wl_surface->width, wl_surface->height, id_surface);
+ return ivisurf;
+ }
+ }
+
+ ivisurf = calloc(1, sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivisurf->link);
+ wl_list_init(&ivisurf->list_notification);
+ wl_list_init(&ivisurf->list_layer);
+ ivisurf->id_surface = id_surface;
+ ivisurf->layout = layout;
+
+ ivisurf->surface = wl_surface;
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(wl_surface->resource,
+ &ivisurf->surface_destroy_listener);
+
+ ivisurf->view = weston_view_create(wl_surface);
+ if (ivisurf->view == NULL) {
+ weston_log("fails to allocate memory\n");
+ }
+
+ ivisurf->buffer_width = 0;
+ ivisurf->buffer_height = 0;
+
+ weston_matrix_init(&ivisurf->view->transform.matrix);
+
+ weston_matrix_init(&ivisurf->surface_rotation.matrix);
+ weston_matrix_init(&ivisurf->layer_rotation.matrix);
+ weston_matrix_init(&ivisurf->surface_pos.matrix);
+ weston_matrix_init(&ivisurf->layer_pos.matrix);
+ weston_matrix_init(&ivisurf->scaling.matrix);
+
+ wl_list_init(&ivisurf->surface_rotation.link);
+ wl_list_init(&ivisurf->layer_rotation.link);
+ wl_list_init(&ivisurf->surface_pos.link);
+ wl_list_init(&ivisurf->layer_pos.link);
+ wl_list_init(&ivisurf->scaling.link);
+
+ init_surfaceProperties(&ivisurf->prop);
+ ivisurf->pixelformat = IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+ ivisurf->event_mask = 0;
+
+ ivisurf->pending.prop = ivisurf->prop;
+ wl_list_init(&ivisurf->pending.link);
+
+ wl_list_init(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.list_layer);
+
+ wl_list_insert(&layout->list_surface, &ivisurf->link);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return ivisurf;
+}
+
+static void
+ivi_layout_initWithCompositor(struct weston_compositor *ec)
+{
+ struct ivi_layout *layout = get_instance();
+
+ layout->compositor = ec;
+
+ wl_list_init(&layout->list_surface);
+ wl_list_init(&layout->list_layer);
+ wl_list_init(&layout->list_screen);
+
+ wl_list_init(&layout->layer_notification.list_create);
+ wl_list_init(&layout->layer_notification.list_remove);
+
+ wl_list_init(&layout->surface_notification.list_create);
+ wl_list_init(&layout->surface_notification.list_remove);
+ wl_list_init(&layout->surface_notification.list_configure);
+
+ /* Add layout_layer at the last of weston_compositor.layer_list */
+ weston_layer_init(&layout->layout_layer, ec->layer_list.prev);
+
+ create_screen(ec);
+
+ struct weston_config *config = weston_config_parse("weston.ini");
+ struct weston_config_section *s =
+ weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ /*A cursor is configured if weston.ini has keys.*/
+ char* cursor_theme = NULL;
+ weston_config_section_get_string(s, "cursor-theme", &cursor_theme, NULL);
+ if (cursor_theme)
+ free(cursor_theme);
+ else
+ wl_list_remove(&ec->cursor_layer.link);
+ weston_config_destroy(config);
+}
+
+
+WL_EXPORT struct ivi_layout_interface ivi_layout_interface = {
+ .get_weston_view = ivi_layout_get_weston_view,
+ .surfaceConfigure = ivi_layout_surfaceConfigure,
+ .surfaceSetNativeContent = ivi_layout_surfaceSetNativeContent,
+ .surfaceCreate = ivi_layout_surfaceCreate,
+ .initWithCompositor = ivi_layout_initWithCompositor
+};
--
1.8.3.1
Nobuhiko Tanibata
2014-05-20 04:29:40 UTC
Permalink
This protocol realizes following features,
- UI ready
- changing modes; tiling, side by side, full_screen, and random
- Give control a surface; workspace to be controlled by using ivi layout APIs
- Display/undisplay a surface; home contains sevaral workspaces to launch
application

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- apply review comments from mailing list

protocol/Makefile.am | 3 +-
protocol/ivi-hmi-controller.xml | 96 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 98 insertions(+), 1 deletion(-)
create mode 100644 protocol/ivi-hmi-controller.xml

diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 9913f16..140aef5 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -9,7 +9,8 @@ protocol_sources = \
wayland-test.xml \
xdg-shell.xml \
scaler.xml \
- ivi-application.xml
+ ivi-application.xml \
+ ivi-hmi-controller.xml

if HAVE_XMLLINT
.PHONY: validate
diff --git a/protocol/ivi-hmi-controller.xml b/protocol/ivi-hmi-controller.xml
new file mode 100644
index 0000000..fd5ce2b
--- /dev/null
+++ b/protocol/ivi-hmi-controller.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ivi_hmi_controller">
+
+ <copyright>
+ Copyright (C) 2013 DENSO CORPORATION
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ </copyright>
+
+ <interface name="ivi_hmi_controller" version="1">
+ <description summary="set up and control IVI style UI"/>
+
+ <request name="UI_ready">
+ <description summary="inform the ready for drawing desktop." />
+ </request>
+
+ <request name="workspace_control">
+ <description summary="start controlling a surface by server">
+ Reference protocol to control a surface by server.
+ To control a surface by server, it gives seat to the server
+ to e.g. control Home screen. Home screen has several workspaces
+ to group launchers of wayland application. These workspaces
+ are drawn on a horizontally long surface to be controlled
+ by motion of input device. E.g. A motion from right to left
+ happens, the viewport of surface is controlled in the ivi-shell
+ by using ivi-layout. client can recognizes the end of controlling
+ by event "workspace_end_control".
+ </description>
+ <arg name="seat" type="object" interface="wl_seat"/>
+ <arg name="serial" type="uint"/>
+ </request>
+
+ <enum name="layout_mode">
+ <entry name="tiling" value="0"/>
+ <entry name="side_by_side" value="1"/>
+ <entry name="full_screen" value="2"/>
+ <entry name="random" value="3" />
+ </enum>
+
+ <request name="switch_mode">
+ <description summary="request mode switch of application layout">
+ hmi-controller loaded to ivi-shall implements 4 types of layout
+ as a reference; tiling, side by side, full_screen, and random.
+ </description>
+ <arg name="layout_mode" type="uint"/>
+ </request>
+
+ <enum name="home">
+ <entry name="off" value="0"/>
+ <entry name="on" value="1"/>
+ </enum>
+
+ <request name="home">
+ <description summary="request displaying/undisplaying home screen">
+ home screen is a reference implementation of launcher to launch
+ wayland applications. The home screen has several workspaces to
+ group wayland applications. By defining the following keys in
+ weston.ini, user can add launcher icon to launch a wayland application
+ to a workspace.
+ [ivi-launcher]
+ workspace-id=0
+ : id of workspace to add a launcher
+ icon-id=4001
+ : ivi id of ivi_surface to draw a icon
+ icon=/home/user/review/build-ivi-shell/data/icon_ivi_flower.png
+ : path to icon image
+ path=/home/user/review/build-ivi-shell/weston-dnd
+ : path to wayland application
+ </description>
+ <arg name="home" type="uint"/>
+ </request>
+
+ <event name="workspace_end_control">
+ <description summary="notify controlling workspace end"/>
+ <arg name="is_controlled" type="int"/>
+ </event>
+
+ </interface>
+
+</protocol>
--
1.8.3.1
Nobuhiko Tanibata
2014-05-20 04:30:05 UTC
Permalink
The library is used to manage layout of surfaces/layers. Layout change is
triggered by ivi-hmi-controller protocol, ivi-hmi-controller.xml. A reference
how to use the protocol, see hmi-controller-homescreen.

In-Vehicle Infotainment system usually manage properties of surfaces/layers
by only a central component which decide where surfaces/layers shall be. This
reference show examples to implement the central component as a module of
weston.

Default Scene graph of UI is defined in hmi_controller_create. It consists of
- In the bottom, a base layer to group surfaces of background, panel,
and buttons
- Next, a application layer to show application surfaces.
- Workspace background layer to show a surface of background image.
- Workspace layer to show launcher to launch application with icons. Paths to
binary and icon are defined in weston.ini. The width of this layer is longer
than the size of screen because a workspace has several pages and is
controlled by motion of input.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- apply review comments from mailing list

Makefile.am | 20 +-
ivi-shell/.gitignore | 7 +
ivi-shell/hmi-controller.c | 1924 +++++++++++++++++++++++++++++++++++++++++
ivi-shell/ivi-layout-export.h | 18 +-
ivi-shell/ivi-layout.c | 28 +-
5 files changed, 1971 insertions(+), 26 deletions(-)
create mode 100644 ivi-shell/.gitignore
create mode 100644 ivi-shell/hmi-controller.c

diff --git a/Makefile.am b/Makefile.am
index e8bcb1b..1f75cc3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -704,7 +704,8 @@ if ENABLE_IVI_SHELL

module_LTLIBRARIES += \
$(ivi_shell) \
- $(ivi_layout)
+ $(ivi_layout) \
+ $(hmi_controller)

ivi_shell = ivi-shell.la
ivi_shell_la_LDFLAGS = -module -avoid-version
@@ -720,6 +721,7 @@ nodist_ivi_shell_la_SOURCES = \

BUILT_SOURCES += $(nodist_ivi_shell_la_SOURCES)

+
ivi_layout = ivi-layout.la
ivi_layout_la_LDFLAGS = -module -avoid-version
ivi_layout_la_LIBADD = $(COMPOSITOR_LIBS) $(IVI_SHELL_LIBS) libshared.la
@@ -734,6 +736,22 @@ nodist_ivi_layout_la_SOURCES = \

BUILT_SOURCES += $(nodist_ivi_layout_la_SOURCES)

+hmi_controller = hmi-controller.la
+hmi_controller_la_LDFLAGS = -module -avoid-version
+hmi_controller_la_LIBADD = $(CLIENT_LIBS) $(IVI_SHELL_LIBS) libshared-cairo.la
+hmi_controller_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
+hmi_controller_la_SOURCES = \
+ ivi-shell/ivi-layout-export.h \
+ ivi-shell/hmi-controller.c
+nodist_hmi_controller_la_SOURCES = \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-client-protocol.h \
+ protocol/ivi-hmi-controller-protocol.c \
+ protocol/ivi-hmi-controller-client-protocol.h \
+ protocol/ivi-hmi-controller-server-protocol.h
+
+BUILT_SOURCES += $(nodist_hmi_controller_la_SOURCES)
+
endif


diff --git a/ivi-shell/.gitignore b/ivi-shell/.gitignore
new file mode 100644
index 0000000..9f31bfd
--- /dev/null
+++ b/ivi-shell/.gitignore
@@ -0,0 +1,7 @@
+ivi-application-client-protocol.h
+ivi-application-protocol.c
+ivi-application-server-protocol.h
+ivi-hmi-controller-client-protocol.h
+ivi-hmi-controller-protocol.c
+ivi-hmi-controller-server-protocol.h
+weston.ini
diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
new file mode 100644
index 0000000..6717990
--- /dev/null
+++ b/ivi-shell/hmi-controller.c
@@ -0,0 +1,1924 @@
+/*
+ * Copyright (C) 2014 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * A reference implementation how to use ivi-layout APIs in order to manage
+ * layout of surfaces/layers. Layout change is triggered by ivi-hmi-controller
+ * protocol, ivi-hmi-controller.xml. A reference how to use the protocol, see
+ * hmi-controller-homescreen.
+ *
+ * In-Vehicle Infotainment system usually manage properties of surfaces/layers
+ * by only a central component which decide where surfaces/layers shall be. This
+ * reference show examples to implement the central component as a module of weston.
+ *
+ * Default Scene graph of UI is defined in hmi_controller_create. It consists of
+ * - In the bottom, a base layer to group surfaces of background, panel,
+ * and buttons
+ * - Next, a application layer to show application surfaces.
+ * - Workspace background layer to show a surface of background image.
+ * - Workspace layer to show launcher to launch application with icons. Paths to
+ * binary and icon are defined in weston.ini. The width of this layer is longer
+ * than the size of screen because a workspace has several pages and is controlled
+ * by motion of input.
+ *
+ * TODO: animation method shall be refined
+ * TODO: support fade-in when UI is ready
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <assert.h>
+#include <time.h>
+
+#include "ivi-layout-export.h"
+#include "ivi-hmi-controller-server-protocol.h"
+
+/*****************************************************************************
+ * structure, globals
+ ****************************************************************************/
+struct hmi_controller_layer {
+ struct ivi_layout_layer *ivilayer;
+ uint32_t id_layer;
+ int32_t x;
+ int32_t y;
+ uint32_t width;
+ uint32_t height;
+};
+
+struct link_layer {
+ struct ivi_layout_layer *layout_layer;
+ struct wl_list link;
+};
+
+struct link_animation {
+ struct hmi_controller_animation *animation;
+ struct wl_list link;
+};
+
+struct hmi_controller_animation;
+typedef void (*hmi_controller_animation_frame_func)(void *animation, uint32_t timestamp);
+typedef void (*hmi_controller_animation_frame_user_func)(void *animation);
+typedef void (*hmi_controller_animation_destroy_func)(struct hmi_controller_animation *animation);
+
+struct move_animation_user_data {
+ struct ivi_layout_layer* layer;
+ struct animation_set *anima_set;
+ struct hmi_controller *hmi_ctrl;
+};
+
+struct hmi_controller_animation {
+ void *user_data;
+ uint32_t time_start;
+ uint32_t is_done;
+ hmi_controller_animation_frame_func frame_func;
+ hmi_controller_animation_frame_user_func frame_user_func;
+ hmi_controller_animation_destroy_func destroy_func;
+};
+
+struct hmi_controller_animation_fade {
+ struct hmi_controller_animation base;
+ double start;
+ double end;
+ struct weston_spring spring;
+};
+
+struct hmi_controller_animation_move {
+ struct hmi_controller_animation base;
+ double pos;
+ double pos_start;
+ double pos_end;
+ double v0;
+ double a;
+ double time_end;
+};
+
+struct hmi_controller_fade {
+ uint32_t isFadeIn;
+ struct hmi_controller_animation_fade *animation;
+ struct animation_set *anima_set;
+ struct wl_list layer_list;
+};
+
+struct animation_set {
+ struct wl_event_source *event_source;
+ struct wl_list animation_list;
+};
+
+struct
+hmi_server_setting {
+ uint32_t base_layer_id;
+ uint32_t application_layer_id;
+ uint32_t workspace_background_layer_id;
+ uint32_t workspace_layer_id;
+ uint32_t panel_height;
+};
+
+struct hmi_controller
+{
+ struct hmi_server_setting *hmi_setting;
+ struct hmi_controller_layer base_layer;
+ struct hmi_controller_layer application_layer;
+ struct hmi_controller_layer workspace_background_layer;
+ struct hmi_controller_layer workspace_layer;
+ enum ivi_hmi_controller_layout_mode layout_mode;
+
+ struct animation_set *anima_set;
+ struct hmi_controller_fade workspace_fade;
+ struct hmi_controller_animation_move *workspace_swipe_animation;
+ int32_t workspace_count;
+ struct wl_array ui_widgets;
+ int32_t is_initialized;
+};
+
+struct launcher_info
+{
+ uint32_t surface_id;
+ uint32_t workspace_id;
+ uint32_t index;
+};
+
+/*****************************************************************************
+ * local functions
+ ****************************************************************************/
+static void *
+fail_on_null(void *p, size_t size, char* file, int32_t line)
+{
+ if (size && !p) {
+ fprintf(stderr, "%s(%d) %zd: out of memory\n", file, line, size);
+ exit(EXIT_FAILURE);
+ }
+
+ return p;
+}
+
+static void *
+mem_alloc(size_t size, char* file, int32_t line)
+{
+ return fail_on_null(calloc(1, size), size, file, line);
+}
+
+#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
+
+static int32_t
+is_surf_in_uiWidget(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface *ivisurf)
+{
+ uint32_t id = ivi_layout_getIdOfSurface(ivisurf);
+
+ uint32_t *ui_widget_id = NULL;
+ wl_array_for_each (ui_widget_id, &hmi_ctrl->ui_widgets) {
+ if (*ui_widget_id == id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+compare_launcher_info(const void *lhs, const void *rhs)
+{
+ const struct launcher_info *left = (const struct launcher_info *)lhs;
+ const struct launcher_info *right = (const struct launcher_info *)rhs;
+
+ if (left->workspace_id < right->workspace_id) {
+ return -1;
+ }
+
+ if (left->workspace_id > right->workspace_id) {
+ return 1;
+ }
+
+ if (left->index < right->index) {
+ return -1;
+ }
+
+ if (left->index > right->index) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Internal methods called by mainly ivi_hmi_controller_switch_mode
+ * This reference shows 4 examples how to use ivi_layout APIs.
+ */
+static void
+mode_divided_into_tiling(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface **ppSurface,
+ uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const float surface_width = (float)layer->width * 0.25;
+ const float surface_height = (float)layer->height * 0.5;
+ int32_t surface_x = 0;
+ int32_t surface_y = 0;
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ uint32_t num = 1;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ if (num <= 8) {
+ if (num < 5) {
+ surface_x = (int32_t)((num - 1) * (surface_width));
+ surface_y = 0;
+ }
+ else {
+ surface_x = (int32_t)((num - 5) * (surface_width));
+ surface_y = (int32_t)surface_height;
+ }
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf, surface_x, surface_y,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 0);
+ assert(!ret);
+ }
+}
+
+static void
+mode_divided_into_sidebyside(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface **ppSurface,
+ uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ uint32_t surface_width = layer->width / 2;
+ uint32_t surface_height = layer->height;
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ uint32_t num = 1;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ if (num == 1) {
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf, 0, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+ else if (num == 2) {
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf, surface_width, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+
+ ivi_layout_surfaceSetVisibility(ivisurf, 0);
+ assert(!ret);
+ }
+}
+
+static void
+mode_fullscreen_someone(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface **ppSurface,
+ uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const uint32_t surface_width = layer->width;
+ const uint32_t surface_height = layer->height;
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf, 0, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+ }
+}
+
+static void
+mode_random_replace(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface **ppSurface,
+ uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const uint32_t surface_width = (uint32_t)(layer->width * 0.25f);
+ const uint32_t surface_height = (uint32_t)(layer->height * 0.25f);
+ uint32_t surface_x = 0;
+ uint32_t surface_y = 0;
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ surface_x = rand() % (layer->width - surface_width);
+ surface_y = rand() % (layer->height - surface_height);
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf, surface_x, surface_y,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+ }
+}
+
+static int32_t
+has_applicatipn_surface(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface **ppSurface,
+ uint32_t surface_length)
+{
+ struct ivi_layout_surface *ivisurf = NULL;
+ uint32_t i = 0;
+
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Supports 4 example to layout of application surfaces;
+ * tiling, side by side, fullscreen, and random.
+ */
+static void
+switch_mode(struct hmi_controller *hmi_ctrl,
+ enum ivi_hmi_controller_layout_mode layout_mode)
+{
+ if (!hmi_ctrl->is_initialized) {
+ return;
+ }
+
+ struct hmi_controller_layer *layer = &hmi_ctrl->application_layer;
+ struct ivi_layout_surface **ppSurface = NULL;
+ uint32_t surface_length = 0;
+ int32_t ret = 0;
+
+ hmi_ctrl->layout_mode = layout_mode;
+
+ ret = ivi_layout_getSurfaces(&surface_length, &ppSurface);
+ assert(!ret);
+
+ if (!has_applicatipn_surface(hmi_ctrl, ppSurface, surface_length)) {
+ free(ppSurface);
+ ppSurface = NULL;
+ return;
+ }
+
+ switch (layout_mode) {
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING:
+ mode_divided_into_tiling(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE:
+ mode_divided_into_sidebyside(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN:
+ mode_fullscreen_someone(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM:
+ mode_random_replace(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ }
+
+ ivi_layout_commitChanges();
+
+ free(ppSurface);
+ ppSurface = NULL;
+
+ return;
+}
+
+/**
+ * Internal method for animation
+ */
+static void
+hmi_controller_animation_frame(
+ struct hmi_controller_animation *animation, uint32_t timestamp)
+{
+ if (0 == animation->time_start) {
+ animation->time_start = timestamp;
+ }
+
+ animation->frame_func(animation, timestamp);
+ animation->frame_user_func(animation);
+}
+
+static int
+animation_set_do_anima(void* data)
+{
+ struct animation_set *anima_set = data;
+ uint32_t fps = 30;
+
+ if (wl_list_empty(&anima_set->animation_list)) {
+ wl_event_source_timer_update(anima_set->event_source, 0);
+ return 1;
+ }
+
+ wl_event_source_timer_update(anima_set->event_source, 1000 / fps);
+
+ struct timespec timestamp = {0};
+ clock_gettime(CLOCK_MONOTONIC, &timestamp);
+ uint32_t msec = (1e+3 * timestamp.tv_sec + 1e-6 * timestamp.tv_nsec);
+
+ struct link_animation *link_animation = NULL;
+ struct link_animation *next = NULL;
+
+ wl_list_for_each_safe(link_animation, next, &anima_set->animation_list, link) {
+ hmi_controller_animation_frame(link_animation->animation, msec);
+ }
+
+ ivi_layout_commitChanges();
+ return 1;
+}
+
+static struct animation_set *
+animation_set_create(struct weston_compositor* ec)
+{
+ struct animation_set *anima_set = MEM_ALLOC(sizeof(*anima_set));
+
+ wl_list_init(&anima_set->animation_list);
+
+ struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
+ anima_set->event_source = wl_event_loop_add_timer(loop, animation_set_do_anima, anima_set);
+ wl_event_source_timer_update(anima_set->event_source, 0);
+
+ return anima_set;
+}
+
+static void
+animation_set_add_animation(struct animation_set *anima_set,
+ struct hmi_controller_animation *anima)
+{
+ struct link_animation *link_anima = NULL;
+
+ link_anima = MEM_ALLOC(sizeof(*link_anima));
+ if (NULL == link_anima) {
+ return;
+ }
+
+ link_anima->animation = anima;
+ wl_list_insert(&anima_set->animation_list, &link_anima->link);
+ wl_event_source_timer_update(anima_set->event_source, 1);
+}
+
+static void
+animation_set_remove_animation(struct animation_set *anima_set,
+ struct hmi_controller_animation *anima)
+{
+ struct link_animation *link_animation = NULL;
+ struct link_animation *next = NULL;
+
+ wl_list_for_each_safe(link_animation, next, &anima_set->animation_list, link) {
+ if (link_animation->animation == anima) {
+ wl_list_remove(&link_animation->link);
+ free(link_animation);
+ break;
+ }
+ }
+}
+
+static void
+hmi_controller_animation_spring_frame(
+ struct hmi_controller_animation_fade *animation, uint32_t timestamp)
+{
+ if (0 == animation->spring.timestamp) {
+ animation->spring.timestamp = timestamp;
+ }
+
+ weston_spring_update(&animation->spring, timestamp);
+ animation->base.is_done = weston_spring_done(&animation->spring);
+}
+
+static void
+hmi_controller_animation_move_frame(
+ struct hmi_controller_animation_move *animation, uint32_t timestamp)
+{
+ double s = animation->pos_start;
+ double t = timestamp - animation->base.time_start;
+ double v0 = animation->v0;
+ double a = animation->a;
+ double time_end = animation->time_end;
+
+ if (time_end <= t) {
+ animation->pos = animation->pos_end;
+ animation->base.is_done = 1;
+ } else {
+ animation->pos = v0 * t + 0.5 * a * t * t + s;
+ }
+}
+
+static void
+hmi_controller_animation_destroy(struct hmi_controller_animation *animation)
+{
+ if (animation->destroy_func) {
+ animation->destroy_func(animation);
+ }
+
+ free(animation);
+}
+
+static void
+hmi_controller_fade_animation_destroy(struct hmi_controller_animation *animation)
+{
+ struct hmi_controller_fade *fade = animation->user_data;
+ animation_set_remove_animation(fade->anima_set, animation);
+ fade->animation = NULL;
+ animation->user_data = NULL;
+}
+
+static struct hmi_controller_animation_fade *
+hmi_controller_animation_fade_create(double start, double end, double k,
+ hmi_controller_animation_frame_user_func frame_user_func, void* user_data,
+ hmi_controller_animation_destroy_func destroy_func)
+{
+ struct hmi_controller_animation_fade* animation = MEM_ALLOC(sizeof(*animation));
+
+ animation->base.frame_user_func = frame_user_func;
+ animation->base.user_data = user_data;
+ animation->base.frame_func =
+ (hmi_controller_animation_frame_func)hmi_controller_animation_spring_frame;
+ animation->base.destroy_func = destroy_func;
+
+ animation->start = start;
+ animation->end = end;
+ weston_spring_init(&animation->spring, k, start, end);
+ animation->spring.friction = 1400;
+ animation->spring.previous = -(end - start) * 0.03;
+
+ return animation;
+}
+
+static struct hmi_controller_animation_move *
+hmi_controller_animation_move_create(
+ double pos_start, double pos_end, double v_start, double v_end,
+ hmi_controller_animation_frame_user_func frame_user_func, void* user_data,
+ hmi_controller_animation_destroy_func destroy_func)
+{
+ struct hmi_controller_animation_move* animation = MEM_ALLOC(sizeof(*animation));
+
+ animation->base.frame_user_func = frame_user_func;
+ animation->base.user_data = user_data;
+ animation->base.frame_func =
+ (hmi_controller_animation_frame_func)hmi_controller_animation_move_frame;
+ animation->base.destroy_func = destroy_func;
+
+ animation->pos_start = pos_start;
+ animation->pos_end = pos_end;
+ animation->v0 = v_start;
+ animation->pos = pos_start;
+
+ double dx = (pos_end - pos_start);
+
+ if (1e-3 < fabs(dx)) {
+ animation->a = 0.5 * (v_end * v_end - v_start * v_start) / dx;
+ if (1e-6 < fabs(animation->a)) {
+ animation->time_end = (v_end - v_start) / animation->a;
+
+ } else {
+ animation->a = 0;
+ animation->time_end = fabs(dx / animation->v0);
+ }
+
+ } else {
+ animation->time_end = 0;
+ }
+
+ return animation;
+}
+
+static double
+hmi_controller_animation_fade_alpha_get(struct hmi_controller_animation_fade* animation)
+{
+ if (animation->spring.current > 0.999) {
+ return 1.0;
+ } else if (animation->spring.current < 0.001 ) {
+ return 0.0;
+ } else {
+ return animation->spring.current;
+ }
+}
+
+static uint32_t
+hmi_controller_animation_is_done(struct hmi_controller_animation *animation)
+{
+ return animation->is_done;
+}
+
+static void
+hmi_controller_fade_update(struct hmi_controller_animation_fade *animation, double end)
+{
+ animation->spring.target = end;
+}
+
+static void
+hmi_controller_anima_fade_user_frame(struct hmi_controller_animation_fade *animation)
+{
+ double alpha = hmi_controller_animation_fade_alpha_get(animation);
+ alpha = wl_fixed_from_double(alpha);
+ struct hmi_controller_fade *fade = animation->base.user_data;
+ struct link_layer *linklayer = NULL;
+ int32_t is_done = hmi_controller_animation_is_done(&animation->base);
+ int32_t is_visible = !is_done || fade->isFadeIn;
+
+ wl_list_for_each(linklayer, &fade->layer_list, link) {
+ ivi_layout_layerSetOpacity(linklayer->layout_layer, alpha);
+ ivi_layout_layerSetVisibility(linklayer->layout_layer, is_visible);
+ }
+
+ if (is_done) {
+ hmi_controller_animation_destroy(&animation->base);
+ }
+}
+
+static void
+hmi_controller_anima_move_user_frame(struct hmi_controller_animation_move *animation)
+{
+ struct move_animation_user_data* user_data = animation->base.user_data;
+ struct ivi_layout_layer *layer = user_data->layer;
+ int32_t is_done = hmi_controller_animation_is_done(&animation->base);
+
+ int32_t pos[2] = {0};
+ ivi_layout_layerGetPosition(layer, pos);
+
+ pos[0] = (int32_t)animation->pos;
+ ivi_layout_layerSetPosition(layer, pos);
+
+ if (is_done) {
+ hmi_controller_animation_destroy(&animation->base);
+ }
+}
+
+static void
+hmi_controller_fade_run(uint32_t isFadeIn, struct hmi_controller_fade *fade)
+{
+ double tint = isFadeIn ? 1.0 : 0.0;
+ fade->isFadeIn = isFadeIn;
+
+ if (fade->animation) {
+ hmi_controller_fade_update(fade->animation, tint);
+ } else {
+ fade->animation = hmi_controller_animation_fade_create(
+ 1.0 - tint, tint, 300.0,
+ (hmi_controller_animation_frame_user_func)hmi_controller_anima_fade_user_frame,
+ fade, hmi_controller_fade_animation_destroy);
+
+ animation_set_add_animation(fade->anima_set, &fade->animation->base);
+ }
+}
+
+/**
+ * Internal method to create layer with hmi_controller_layer and add to a screen
+ */
+static void
+create_layer(struct ivi_layout_screen *iviscrn,
+ struct hmi_controller_layer *layer)
+{
+ int32_t ret = 0;
+
+ layer->ivilayer = ivi_layout_layerCreateWithDimension(layer->id_layer,
+ layer->width, layer->height);
+ assert(layer->ivilayer != NULL);
+
+ ret = ivi_layout_screenAddLayer(iviscrn, layer->ivilayer);
+ assert(!ret);
+
+ ret = ivi_layout_layerSetDestinationRectangle(layer->ivilayer, layer->x, layer->y,
+ layer->width, layer->height);
+ assert(!ret);
+
+ ret = ivi_layout_layerSetVisibility(layer->ivilayer, 1);
+ assert(!ret);
+}
+
+/**
+ * Internal set notification
+ */
+static void
+set_notification_create_surface(struct ivi_layout_surface *ivisurf,
+ void *userdata)
+{
+ struct hmi_controller* hmi_ctrl = userdata;
+ struct ivi_layout_layer *application_layer = hmi_ctrl->application_layer.ivilayer;
+ int32_t ret = 0;
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ return;
+ }
+
+ ret = ivi_layout_layerAddSurface(application_layer, ivisurf);
+ assert(!ret);
+}
+
+static void
+set_notification_remove_surface(struct ivi_layout_surface *ivisurf,
+ void *userdata)
+{
+ (void)ivisurf;
+ struct hmi_controller* hmi_ctrl = userdata;
+ switch_mode(hmi_ctrl, hmi_ctrl->layout_mode);
+}
+
+static void
+set_notification_configure_surface(struct ivi_layout_surface *ivisurf,
+ void *userdata)
+{
+ (void)ivisurf;
+ struct hmi_controller* hmi_ctrl = userdata;
+ switch_mode(hmi_ctrl, hmi_ctrl->layout_mode);
+}
+
+/**
+ * A hmi_controller used 4 layers to manage surfaces. The IDs of corresponding layer
+ * are defined in weston.ini. Default scene graph of layers are initialized in
+ * hmi_controller_create
+ */
+static struct hmi_server_setting *
+hmi_server_setting_create(void)
+{
+ struct hmi_server_setting* setting = MEM_ALLOC(sizeof(*setting));
+
+ struct weston_config *config = NULL;
+ config = weston_config_parse("weston.ini");
+
+ struct weston_config_section *shellSection = NULL;
+ shellSection = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ weston_config_section_get_uint(
+ shellSection, "base-layer-id", &setting->base_layer_id, 1000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-layer-id", &setting->workspace_background_layer_id, 2000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-layer-id", &setting->workspace_layer_id, 3000);
+
+ weston_config_section_get_uint(
+ shellSection, "application-layer-id", &setting->application_layer_id, 4000);
+
+ setting->panel_height = 70;
+
+ weston_config_destroy(config);
+
+ return setting;
+}
+
+/**
+ * This is a starting method called from module_init.
+ * This sets up scene graph of layers; base, application, workspace background,
+ * and workspace. These layers are created/added to screen in create_layer
+ *
+ * base: to group surfaces of panel and background
+ * application: to group surfaces of ivi_applications
+ * workspace background: to group a surface of background in workspace
+ * workspace: to group surfaces for launching ivi_applications
+ *
+ * Layers of workspace background and workspace is set to invisible at first.
+ * The properties of it is updated with animation when ivi_hmi_controller_home is
+ * requested.
+ */
+static struct hmi_controller *
+hmi_controller_create(struct weston_compositor *ec)
+{
+ struct ivi_layout_screen **ppScreen = NULL;
+ struct ivi_layout_screen *iviscrn = NULL;
+ uint32_t screen_length = 0;
+ uint32_t screen_width = 0;
+ uint32_t screen_height = 0;
+ int32_t ret = 0;
+ struct link_layer *tmp_link_layer = NULL;
+
+ struct hmi_controller *hmi_ctrl = MEM_ALLOC(sizeof(*hmi_ctrl));
+ wl_array_init(&hmi_ctrl->ui_widgets);
+ hmi_ctrl->layout_mode = IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING;
+ hmi_ctrl->hmi_setting = hmi_server_setting_create();
+
+ ivi_layout_getScreens(&screen_length, &ppScreen);
+
+ iviscrn = ppScreen[0];
+
+ ivi_layout_getScreenResolution(iviscrn, &screen_width, &screen_height);
+ assert(!ret);
+
+ /* init base layer*/
+ hmi_ctrl->base_layer.x = 0;
+ hmi_ctrl->base_layer.y = 0;
+ hmi_ctrl->base_layer.width = screen_width;
+ hmi_ctrl->base_layer.height = screen_height;
+ hmi_ctrl->base_layer.id_layer = hmi_ctrl->hmi_setting->base_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->base_layer);
+
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+
+
+ /* init application layer */
+ hmi_ctrl->application_layer.x = 0;
+ hmi_ctrl->application_layer.y = 0;
+ hmi_ctrl->application_layer.width = screen_width;
+ hmi_ctrl->application_layer.height = screen_height - panel_height;
+ hmi_ctrl->application_layer.id_layer = hmi_ctrl->hmi_setting->application_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->application_layer);
+
+ /* init workspace background layer */
+ hmi_ctrl->workspace_background_layer.x = 0;
+ hmi_ctrl->workspace_background_layer.y = 0;
+ hmi_ctrl->workspace_background_layer.width = screen_width;
+ hmi_ctrl->workspace_background_layer.height = screen_height - panel_height;
+
+ hmi_ctrl->workspace_background_layer.id_layer =
+ hmi_ctrl->hmi_setting->workspace_background_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->workspace_background_layer);
+ ivi_layout_layerSetOpacity(hmi_ctrl->workspace_background_layer.ivilayer, 0);
+ ivi_layout_layerSetVisibility(hmi_ctrl->workspace_background_layer.ivilayer, 0);
+
+ /* init workspace layer */
+ hmi_ctrl->workspace_layer.x = hmi_ctrl->workspace_background_layer.x;
+ hmi_ctrl->workspace_layer.y = hmi_ctrl->workspace_background_layer.y;
+ hmi_ctrl->workspace_layer.width = hmi_ctrl->workspace_background_layer.width;
+ hmi_ctrl->workspace_layer.height = hmi_ctrl->workspace_background_layer.height;
+ hmi_ctrl->workspace_layer.id_layer = hmi_ctrl->hmi_setting->workspace_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->workspace_layer);
+ ivi_layout_layerSetOpacity(hmi_ctrl->workspace_layer.ivilayer, 0);
+ ivi_layout_layerSetVisibility(hmi_ctrl->workspace_layer.ivilayer, 0);
+
+ /* set up animation to workspace background and workspace */
+ hmi_ctrl->anima_set = animation_set_create(ec);
+
+ wl_list_init(&hmi_ctrl->workspace_fade.layer_list);
+ tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer));
+ tmp_link_layer->layout_layer = hmi_ctrl->workspace_layer.ivilayer;
+ wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, &tmp_link_layer->link);
+ tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer));
+ tmp_link_layer->layout_layer = hmi_ctrl->workspace_background_layer.ivilayer;
+ wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, &tmp_link_layer->link);
+ hmi_ctrl->workspace_fade.anima_set = hmi_ctrl->anima_set;
+
+ ivi_layout_addNotificationCreateSurface(set_notification_create_surface, hmi_ctrl);
+ ivi_layout_addNotificationRemoveSurface(set_notification_remove_surface, hmi_ctrl);
+ ivi_layout_addNotificationConfigureSurface(set_notification_configure_surface, hmi_ctrl);
+
+ free(ppScreen);
+ ppScreen = NULL;
+
+ return hmi_ctrl;
+}
+
+/**
+ * Implementations of ivi-hmi-controller.xml
+ */
+
+/**
+ * A surface drawing background is identified by id_surface.
+ * Properties of the surface is set by using ivi_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_background(struct wl_resource *resource,
+ uint32_t id_surface)
+
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const uint32_t dstx = hmi_ctrl->application_layer.x;
+ const uint32_t dsty = hmi_ctrl->application_layer.y;
+ const uint32_t width = hmi_ctrl->application_layer.width;
+ const uint32_t height = hmi_ctrl->application_layer.height;
+ uint32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = ivi_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = ivi_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf,
+ dstx, dsty, width, height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ ivi_layout_commitChanges();
+}
+
+/**
+ * A surface drawing panel is identified by id_surface.
+ * Properties of the surface is set by using ivi_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_panel(struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const uint32_t width = hmi_ctrl->base_layer.width;
+ uint32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = ivi_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = ivi_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+ const uint32_t dstx = 0;
+ const uint32_t dsty = hmi_ctrl->base_layer.height - panel_height;
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(
+ ivisurf, dstx, dsty, width, panel_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ ivi_layout_commitChanges();
+}
+
+/**
+ * A surface drawing buttons in panel is identified by id_surface. It can set
+ * several buttons. Properties of the surface is set by using ivi_layout
+ * APIs according to the scene graph of UI defined in hmi_controller_create.
+ * Additionally, the position of it is shifted to right when new one is requested.
+ *
+ * UI layer is used to add these surfaces.
+ */
+static void
+ivi_hmi_controller_set_button(struct wl_resource *resource,
+ uint32_t id_surface, uint32_t number)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const uint32_t width = 48;
+ const uint32_t height = 48;
+ uint32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = ivi_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = ivi_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+
+ const uint32_t dstx = (60 * number) + 15;
+ const uint32_t dsty = (hmi_ctrl->base_layer.height - panel_height) + 5;
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(
+ ivisurf,dstx, dsty, width, height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ ivi_layout_commitChanges();
+}
+
+/**
+ * A surface drawing home button in panel is identified by id_surface.
+ * Properties of the surface is set by using ivi_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add these surfaces.
+ */
+static void
+ivi_hmi_controller_set_home_button(struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ uint32_t ret = 0;
+ uint32_t size = 48;
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+ const uint32_t dstx = (hmi_ctrl->base_layer.width - size) / 2;
+ const uint32_t dsty = (hmi_ctrl->base_layer.height - panel_height) + 5;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = ivi_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = ivi_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(
+ ivisurf, dstx, dsty, size, size);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ ivi_layout_commitChanges();
+ hmi_ctrl->is_initialized = 1;
+}
+
+/**
+ * A surface drawing background of workspace is identified by id_surface.
+ * Properties of the surface is set by using ivi_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * A layer of workspace_background is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_workspacebackground(struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_layer *ivilayer = NULL;
+ ivilayer = hmi_ctrl->workspace_background_layer.ivilayer;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ const uint32_t width = hmi_ctrl->workspace_background_layer.width;
+ const uint32_t height = hmi_ctrl->workspace_background_layer.height;
+ uint32_t ret = 0;
+
+ ivisurf = ivi_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = ivi_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf,
+ 0, 0, width, height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ ivi_layout_commitChanges();
+}
+
+/**
+ * A list of surfaces drawing launchers in workspace is identified by id_surfaces.
+ * Properties of the surface is set by using ivi_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * The workspace can have several pages to group surfaces of launcher. Each call
+ * of this interface increments a number of page to add a group of surfaces
+ */
+static void
+ivi_hmi_controller_add_launchers(struct wl_resource *resource,
+ uint32_t icon_size)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ uint32_t minspace_x = 10;
+ uint32_t minspace_y = minspace_x;
+
+ uint32_t width = hmi_ctrl->workspace_layer.width;
+ uint32_t height = hmi_ctrl->workspace_layer.height;
+
+ uint32_t x_count = (width - minspace_x) / (minspace_x + icon_size);
+ uint32_t space_x = (uint32_t)((width - x_count * icon_size) / (1.0 + x_count));
+ float fcell_size_x = icon_size + space_x;
+
+ uint32_t y_count = (height - minspace_y) / (minspace_y + icon_size);
+ uint32_t space_y = (uint32_t)((height - y_count * icon_size) / (1.0 + y_count));
+ float fcell_size_y = icon_size + space_y;
+
+ if (0 == x_count) {
+ x_count = 1;
+ }
+
+ if (0 == y_count) {
+ y_count = 1;
+ }
+
+ struct weston_config *config = weston_config_parse("weston.ini");
+ if (!config) {
+ return;
+ }
+
+ struct weston_config_section *section = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+ if (!section) {
+ return;
+ }
+
+ const char *name = NULL;
+ int launcher_count = 0;
+ struct wl_array launchers;
+ wl_array_init(&launchers);
+
+ while (weston_config_next_section(config, &section, &name)) {
+ uint32_t surfaceid = 0;
+ uint32_t workspaceid = 0;
+ if (0 != strcmp(name, "ivi-launcher")) {
+ continue;
+ }
+
+ if (0 != weston_config_section_get_uint(section, "icon-id", &surfaceid, 0)) {
+ continue;
+ }
+
+ if (0 != weston_config_section_get_uint(section, "workspace-id", &workspaceid, 0)) {
+ continue;
+ }
+
+ struct launcher_info *info = wl_array_add(&launchers, sizeof(*info));
+
+ if (info) {
+ info->surface_id = surfaceid;
+ info->workspace_id = workspaceid;
+ info->index = launcher_count;
+ ++launcher_count;
+ }
+ }
+
+ qsort(launchers.data, launcher_count, sizeof(struct launcher_info), compare_launcher_info);
+
+ uint32_t nx = 0;
+ uint32_t ny = 0;
+ int32_t prev = -1;
+ struct launcher_info *data = NULL;
+ wl_array_for_each(data, &launchers)
+ {
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = data->surface_id;
+
+ if (0 > prev || (uint32_t)prev != data->workspace_id) {
+ nx = 0;
+ ny = 0;
+ prev = data->workspace_id;
+
+ if (0 <= prev) {
+ hmi_ctrl->workspace_count++;
+ }
+ }
+
+ if (y_count == ny) {
+ ny = 0;
+ hmi_ctrl->workspace_count++;
+ }
+
+ uint32_t x = (uint32_t)(nx * fcell_size_x + (hmi_ctrl->workspace_count - 1) * width + space_x);
+ uint32_t y = (uint32_t)(ny * fcell_size_y + space_y) ;
+
+ struct ivi_layout_surface* layout_surface = NULL;
+ layout_surface = ivi_layout_getSurfaceFromId(data->surface_id);
+ assert(layout_surface);
+
+ uint32_t ret = 0;
+ ret = ivi_layout_layerAddSurface(layer, layout_surface);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(
+ layout_surface, x, y, icon_size, icon_size);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(layout_surface, 1);
+ assert(!ret);
+
+ nx++;
+
+ if (x_count == nx) {
+ ny++;
+ nx = 0;
+ }
+ }
+
+ wl_array_release(&launchers);
+ weston_config_destroy(config);
+ ivi_layout_commitChanges();
+}
+
+static void
+ivi_hmi_controller_UI_ready(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct setting {
+ uint32_t background_id;
+ uint32_t panel_id;
+ uint32_t tiling_id;
+ uint32_t sidebyside_id;
+ uint32_t fullscreen_id;
+ uint32_t random_id;
+ uint32_t home_id;
+ uint32_t workspace_background_id;
+ };
+
+ struct config_command {
+ char *key;
+ void *dest;
+ };
+
+ struct weston_config *config = NULL;
+ struct weston_config_section *section = NULL;
+ struct setting dest;
+ int result = 0;
+ int i = 0;
+
+ const struct config_command uint_commands[] = {
+ { "background-id", &dest.background_id },
+ { "panel-id", &dest.panel_id },
+ { "tiling-id", &dest.tiling_id },
+ { "sidebyside-id", &dest.sidebyside_id },
+ { "fullscreen-id", &dest.fullscreen_id },
+ { "random-id", &dest.random_id },
+ { "home-id", &dest.home_id },
+ { "workspace-background-id", &dest.workspace_background_id },
+ { NULL, NULL }
+ };
+
+ config = weston_config_parse("weston.ini");
+ section = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ for (i = 0; -1 != result; ++i)
+ {
+ const struct config_command *command = &uint_commands[i];
+
+ if (!command->key)
+ {
+ break;
+ }
+
+ if (weston_config_section_get_uint(
+ section, command->key, (uint32_t *)command->dest, 0) != 0)
+ {
+ result = -1;
+ }
+ }
+
+ if (-1 != result)
+ {
+ ivi_hmi_controller_set_background(resource, dest.background_id);
+ ivi_hmi_controller_set_panel(resource, dest.panel_id);
+ ivi_hmi_controller_set_button(resource, dest.tiling_id, 0);
+ ivi_hmi_controller_set_button(resource, dest.sidebyside_id, 1);
+ ivi_hmi_controller_set_button(resource, dest.fullscreen_id, 2);
+ ivi_hmi_controller_set_button(resource, dest.random_id, 3);
+ ivi_hmi_controller_set_home_button(resource, dest.home_id);
+ ivi_hmi_controller_set_workspacebackground(resource, dest.workspace_background_id);
+ }
+
+ weston_config_destroy(config);
+
+ ivi_hmi_controller_add_launchers(resource, 256);
+}
+
+/**
+ * Implementation of request and event of ivi_hmi_controller_workspace_control
+ * and controlling workspace.
+ *
+ * When motion of input is detected in a surface of workspace background,
+ * ivi_hmi_controller_workspace_control shall be invoked and to start controlling of
+ * workspace. The workspace has several pages to show several groups of applications.
+ * The workspace is slid by using ivi-layout to select a a page in layer_set_pos
+ * according to motion. When motion finished, e.g. touch up detected, control is
+ * terminated and event:ivi_hmi_controller_workspace_control is notified.
+ */
+struct pointer_grab {
+ struct weston_pointer_grab grab;
+ struct ivi_layout_layer *layer;
+ struct wl_resource *resource;
+};
+
+struct touch_grab {
+ struct weston_touch_grab grab;
+ struct ivi_layout_layer *layer;
+ struct wl_resource *resource;
+};
+
+struct move_grab {
+ wl_fixed_t dst[2];
+ wl_fixed_t rgn[2][2];
+ double v[2];
+ struct timespec start_time;
+ struct timespec pre_time;
+ wl_fixed_t start_pos[2];
+ wl_fixed_t pos[2];
+ int32_t is_moved;
+};
+
+struct pointer_move_grab {
+ struct pointer_grab base;
+ struct move_grab move;
+};
+
+struct touch_move_grab {
+ struct touch_grab base;
+ struct move_grab move;
+ int32_t is_active;
+};
+
+static void
+pointer_grab_start(struct pointer_grab *grab,
+ struct ivi_layout_layer *layer,
+ const struct weston_pointer_grab_interface *interface,
+ struct weston_pointer *pointer)
+{
+ grab->grab.interface = interface;
+ grab->layer = layer;
+ weston_pointer_start_grab(pointer, &grab->grab);
+}
+
+static void
+touch_grab_start(struct touch_grab *grab,
+ struct ivi_layout_layer *layer,
+ const struct weston_touch_grab_interface *interface,
+ struct weston_touch* touch)
+{
+ grab->grab.interface = interface;
+ grab->layer = layer;
+ weston_touch_start_grab(touch, &grab->grab);
+}
+
+static int32_t
+range_val(int32_t val, int32_t min, int32_t max)
+{
+ if (val < min) {
+ return min;
+ }
+
+ if (max < val) {
+ return max;
+ }
+
+ return val;
+}
+
+static void
+hmi_controller_move_animation_destroy(struct hmi_controller_animation *animation)
+{
+ struct move_animation_user_data *user_data = animation->user_data;
+ if (animation == &user_data->hmi_ctrl->workspace_swipe_animation->base) {
+ user_data->hmi_ctrl->workspace_swipe_animation = NULL;
+ }
+
+ animation_set_remove_animation(user_data->anima_set, animation);
+ free(animation->user_data);
+ animation->user_data = NULL;
+}
+
+static void
+move_workspace_grab_end(struct move_grab *move, struct wl_resource* resource,
+ wl_fixed_t grab_x, struct ivi_layout_layer *layer)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ int32_t width = (int32_t)hmi_ctrl->workspace_background_layer.width;
+
+ struct timespec time = {0};
+ clock_gettime(CLOCK_MONOTONIC, &time);
+
+ double grab_time = 1e+3 * (time.tv_sec - move->start_time.tv_sec) +
+ 1e-6 * (time.tv_nsec - move->start_time.tv_nsec);
+
+ double from_motion_time = 1e+3 * (time.tv_sec - move->pre_time.tv_sec) +
+ 1e-6 * (time.tv_nsec - move->pre_time.tv_nsec);
+
+ double pointer_v = move->v[0];
+
+ if (200 < from_motion_time) {
+ pointer_v = 0.0;
+ }
+
+ int32_t is_flick = grab_time < 400 &&
+ 0.4 < fabs(pointer_v);
+
+ int32_t pos[2] = {0};
+ ivi_layout_layerGetPosition(layer, pos);
+
+ int page_no = 0;
+
+ if (is_flick) {
+ int orgx = wl_fixed_to_int(move->dst[0] + grab_x);
+ page_no = (-orgx + width / 2) / width;
+
+ if (pointer_v < 0.0) {
+ page_no++;
+ }else {
+ page_no--;
+ }
+ }else {
+ page_no = (-pos[0] + width / 2) / width;
+ }
+
+ page_no = range_val(page_no, 0, hmi_ctrl->workspace_count - 1);
+ double end_pos = -page_no * width;
+
+ double dst = fabs(end_pos - pos[0]);
+ double max_time = 0.5 * 1e+3;
+ double v = dst / max_time;
+
+ double vmin = 1000 * 1e-3;
+ if (v < vmin ) {
+ v = vmin;
+ }
+
+ double v0 = 0.0;
+ if (pos[0] < end_pos) {
+ v0 = v;
+ } else {
+ v0 = -v;
+ }
+
+ struct move_animation_user_data *animation_user_data = NULL;
+ animation_user_data = MEM_ALLOC(sizeof(*animation_user_data));
+ animation_user_data->layer = layer;
+ animation_user_data->anima_set = hmi_ctrl->anima_set;
+ animation_user_data->hmi_ctrl = hmi_ctrl;
+
+ struct hmi_controller_animation_move* animation = NULL;
+ animation = hmi_controller_animation_move_create(
+ pos[0], end_pos, v0, v0,
+ (hmi_controller_animation_frame_user_func)hmi_controller_anima_move_user_frame,
+ animation_user_data, hmi_controller_move_animation_destroy);
+
+ hmi_ctrl->workspace_swipe_animation = animation;
+ animation_set_add_animation(hmi_ctrl->anima_set, &animation->base);
+
+ ivi_hmi_controller_send_workspace_end_control(resource, move->is_moved);
+}
+
+static void
+pointer_move_workspace_grab_end(struct pointer_grab *grab)
+{
+ struct pointer_move_grab *pnt_move_grab = (struct pointer_move_grab *) grab;
+ struct ivi_layout_layer *layer = pnt_move_grab->base.layer;
+
+ move_workspace_grab_end(&pnt_move_grab->move, grab->resource,
+ grab->grab.pointer->grab_x, layer);
+
+ weston_pointer_end_grab(grab->grab.pointer);
+}
+
+static void
+touch_move_workspace_grab_end(struct touch_grab *grab)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *) grab;
+ struct ivi_layout_layer *layer = tch_move_grab->base.layer;
+
+ move_workspace_grab_end(&tch_move_grab->move, grab->resource,
+ grab->grab.touch->grab_x, layer);
+
+ weston_touch_end_grab(grab->grab.touch);
+}
+
+static void
+pointer_noop_grab_focus(struct weston_pointer_grab *grab)
+{
+}
+
+static void
+move_grab_update(struct move_grab *move, wl_fixed_t pointer[2])
+{
+ struct timespec timestamp = {0};
+ clock_gettime(CLOCK_MONOTONIC, &timestamp);
+
+ double dt = (1e+3 * (timestamp.tv_sec - move->pre_time.tv_sec) +
+ 1e-6 * (timestamp.tv_nsec - move->pre_time.tv_nsec));
+
+ if (dt < 1e-6) {
+ dt = 1e-6;
+ }
+
+ move->pre_time = timestamp;
+
+ int32_t ii = 0;
+ for (ii = 0; ii < 2; ii++) {
+ wl_fixed_t prepos = move->pos[ii];
+ move->pos[ii] = pointer[ii] + move->dst[ii];
+
+ if (move->pos[ii] < move->rgn[0][ii]) {
+ move->pos[ii] = move->rgn[0][ii];
+ move->dst[ii] = move->pos[ii] - pointer[ii];
+ } else if (move->rgn[1][ii] < move->pos[ii]) {
+ move->pos[ii] = move->rgn[1][ii];
+ move->dst[ii] = move->pos[ii] - pointer[ii];
+ }
+
+ move->v[ii] = wl_fixed_to_double(move->pos[ii] - prepos) / dt;
+
+ if (!move->is_moved &&
+ 0 < wl_fixed_to_int(move->pos[ii] - move->start_pos[ii])) {
+ move->is_moved = 1;
+ }
+ }
+}
+
+static void
+layer_set_pos(struct ivi_layout_layer *layer, wl_fixed_t pos[2])
+{
+ int32_t layout_pos[2] = {0};
+ layout_pos[0] = wl_fixed_to_int(pos[0]);
+ layout_pos[1] = wl_fixed_to_int(pos[1]);
+ ivi_layout_layerSetPosition(layer, layout_pos);
+ ivi_layout_commitChanges();
+}
+
+static void
+pointer_move_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ struct pointer_move_grab *pnt_move_grab = (struct pointer_move_grab *) grab;
+ wl_fixed_t pointer_pos[2] = {x, y};
+ move_grab_update(&pnt_move_grab->move, pointer_pos);
+ layer_set_pos(pnt_move_grab->base.layer, pnt_move_grab->move.pos);
+ weston_pointer_move(pnt_move_grab->base.grab.pointer, x, y);
+}
+
+static void
+touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
+ int touch_id, wl_fixed_t x, wl_fixed_t y)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *) grab;
+
+ if (!tch_move_grab->is_active) {
+ return;
+ }
+
+ wl_fixed_t pointer_pos[2] = {grab->touch->grab_x, grab->touch->grab_y};
+ move_grab_update(&tch_move_grab->move, pointer_pos);
+ layer_set_pos(tch_move_grab->base.layer, tch_move_grab->move.pos);
+}
+
+static void
+pointer_move_workspace_grab_button(struct weston_pointer_grab *grab,
+ uint32_t time, uint32_t button,
+ uint32_t state_w)
+{
+ if (BTN_LEFT == button &&
+ WL_POINTER_BUTTON_STATE_RELEASED == state_w) {
+ struct pointer_grab *pg = (struct pointer_grab *)grab;
+ pointer_move_workspace_grab_end(pg);
+ free(grab);
+ }
+}
+
+static void
+touch_nope_grab_down(struct weston_touch_grab *grab, uint32_t time,
+ int touch_id, wl_fixed_t sx, wl_fixed_t sy)
+{
+}
+
+static void
+touch_move_workspace_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *)grab;
+
+ if (0 == touch_id) {
+ tch_move_grab->is_active = 0;
+ }
+
+ if (0 == grab->touch->num_tp) {
+ touch_move_workspace_grab_end(&tch_move_grab->base);
+ free(grab);
+ }
+}
+
+static void
+pointer_move_workspace_grab_cancel(struct weston_pointer_grab *grab)
+{
+ struct pointer_grab *pg = (struct pointer_grab *)grab;
+ pointer_move_workspace_grab_end(pg);
+ free(grab);
+}
+
+static void
+touch_move_workspace_grab_cancel(struct weston_touch_grab *grab)
+{
+ struct touch_grab *tg = (struct touch_grab *)grab;
+ touch_move_workspace_grab_end(tg);
+ free(grab);
+}
+
+static const struct weston_pointer_grab_interface pointer_move_grab_workspace_interface = {
+ pointer_noop_grab_focus,
+ pointer_move_grab_motion,
+ pointer_move_workspace_grab_button,
+ pointer_move_workspace_grab_cancel
+};
+
+static const struct weston_touch_grab_interface touch_move_grab_workspace_interface = {
+ touch_nope_grab_down,
+ touch_move_workspace_grab_up,
+ touch_move_grab_motion,
+ touch_move_workspace_grab_cancel
+};
+
+enum HMI_GRAB_DEVICE
+{
+ HMI_GRAB_DEVICE_NONE,
+ HMI_GRAB_DEVICE_POINTER,
+ HMI_GRAB_DEVICE_TOUCH
+};
+
+static enum HMI_GRAB_DEVICE
+get_hmi_grab_device(struct weston_seat *seat, uint32_t serial)
+{
+ if (seat->pointer &&
+ seat->pointer->focus &&
+ seat->pointer->button_count &&
+ seat->pointer->grab_serial == serial) {
+ return HMI_GRAB_DEVICE_POINTER;
+ }
+
+ if (seat->touch &&
+ seat->touch->focus &&
+ seat->touch->grab_serial) {
+ return HMI_GRAB_DEVICE_TOUCH;
+ }
+
+ return HMI_GRAB_DEVICE_NONE;
+}
+
+static void
+move_grab_init(struct move_grab* move, wl_fixed_t start_pos[2],
+ wl_fixed_t grab_pos[2], wl_fixed_t rgn[2][2],
+ struct wl_resource* resource)
+{
+ clock_gettime(CLOCK_MONOTONIC, &move->start_time);
+ move->pre_time = move->start_time;
+ move->pos[0] = start_pos[0];
+ move->pos[1] = start_pos[1];
+ move->start_pos[0] = start_pos[0];
+ move->start_pos[1] = start_pos[1];
+ move->dst[0] = start_pos[0] - grab_pos[0];
+ move->dst[1] = start_pos[1] - grab_pos[1];
+ memcpy(move->rgn, rgn, sizeof(move->rgn));
+}
+
+static void
+move_grab_init_workspace(struct move_grab* move,
+ wl_fixed_t grab_x, wl_fixed_t grab_y,
+ struct wl_resource *resource)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ int32_t workspace_count = hmi_ctrl->workspace_count;
+ int32_t workspace_width = hmi_ctrl->workspace_background_layer.width;
+ int32_t layer_pos[2] = {0};
+ ivi_layout_layerGetPosition(layer, layer_pos);
+
+ wl_fixed_t start_pos[2] = {0};
+ start_pos[0] = wl_fixed_from_int(layer_pos[0]);
+ start_pos[1] = wl_fixed_from_int(layer_pos[1]);
+
+ wl_fixed_t rgn[2][2] = {{0}};
+ rgn[0][0] = wl_fixed_from_int(-workspace_width * (workspace_count - 1));
+
+ rgn[0][1] = wl_fixed_from_int(0);
+ rgn[1][0] = wl_fixed_from_int(0);
+ rgn[1][1] = wl_fixed_from_int(0);
+
+ wl_fixed_t grab_pos[2] = {grab_x, grab_y};
+
+ move_grab_init(move, start_pos, grab_pos, rgn, resource);
+}
+
+static struct pointer_move_grab *
+create_workspace_pointer_move(struct weston_pointer *pointer, struct wl_resource* resource)
+{
+ struct pointer_move_grab *pnt_move_grab = MEM_ALLOC(sizeof(*pnt_move_grab));
+ pnt_move_grab->base.resource = resource;
+ move_grab_init_workspace(&pnt_move_grab->move, pointer->grab_x, pointer->grab_y, resource);
+ return pnt_move_grab;
+}
+
+static struct touch_move_grab *
+create_workspace_touch_move(struct weston_touch *touch, struct wl_resource* resource)
+{
+ struct touch_move_grab *tch_move_grab = MEM_ALLOC(sizeof(*tch_move_grab));
+ tch_move_grab->base.resource = resource;
+ tch_move_grab->is_active = 1;
+ move_grab_init_workspace(&tch_move_grab->move, touch->grab_x,touch->grab_y, resource);
+ return tch_move_grab;
+}
+
+static void
+ivi_hmi_controller_workspace_control(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *seat_resource,
+ uint32_t serial)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+
+ if (hmi_ctrl->workspace_count < 2) {
+ return;
+ }
+
+ struct weston_seat* seat = wl_resource_get_user_data(seat_resource);
+ enum HMI_GRAB_DEVICE device = get_hmi_grab_device(seat, serial);
+
+ if (HMI_GRAB_DEVICE_POINTER != device &&
+ HMI_GRAB_DEVICE_TOUCH != device) {
+ return;
+ }
+
+ if (hmi_ctrl->workspace_swipe_animation) {
+ hmi_controller_animation_destroy(&hmi_ctrl->workspace_swipe_animation->base);
+ }
+
+ struct ivi_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ struct pointer_move_grab *pnt_move_grab = NULL;
+ struct touch_move_grab *tch_move_grab = NULL;
+
+ switch (device) {
+ case HMI_GRAB_DEVICE_POINTER:
+ pnt_move_grab = create_workspace_pointer_move(seat->pointer, resource);
+
+ pointer_grab_start(
+ &pnt_move_grab->base, layer, &pointer_move_grab_workspace_interface,
+ seat->pointer);
+ break;
+
+ case HMI_GRAB_DEVICE_TOUCH:
+ tch_move_grab = create_workspace_touch_move(seat->touch, resource);
+
+ touch_grab_start(
+ &tch_move_grab->base, layer, &touch_move_grab_workspace_interface,
+ seat->touch);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * Implementation of switch_mode
+ */
+static void
+ivi_hmi_controller_switch_mode(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t layout_mode)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ switch_mode(hmi_ctrl, layout_mode);
+}
+
+/**
+ * Implementation of on/off displaying workspace and workspace background layers.
+ */
+static void
+ivi_hmi_controller_home(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t home)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+
+ if ((IVI_HMI_CONTROLLER_HOME_ON == home && !hmi_ctrl->workspace_fade.isFadeIn) ||
+ (IVI_HMI_CONTROLLER_HOME_OFF == home && hmi_ctrl->workspace_fade.isFadeIn)) {
+
+ uint32_t isFadeIn = !hmi_ctrl->workspace_fade.isFadeIn;
+ hmi_controller_fade_run(isFadeIn, &hmi_ctrl->workspace_fade);
+ }
+}
+
+/**
+ * binding ivi-hmi-controller implementation
+ */
+static const struct ivi_hmi_controller_interface ivi_hmi_controller_implementation = {
+ ivi_hmi_controller_UI_ready,
+ ivi_hmi_controller_workspace_control,
+ ivi_hmi_controller_switch_mode,
+ ivi_hmi_controller_home
+};
+
+static void
+unbind_hmi_controller(struct wl_resource *resource)
+{
+}
+
+static void
+bind_hmi_controller(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource = NULL;
+
+ resource = wl_resource_create(
+ client, &ivi_hmi_controller_interface, 1, id);
+
+ wl_resource_set_implementation(
+ resource, &ivi_hmi_controller_implementation,
+ data, unbind_hmi_controller);
+}
+
+static void
+launch_hmi_client(void *data)
+{
+ /*Nothing to do here*/
+}
+
+/*****************************************************************************
+ * exported functions
+ ****************************************************************************/
+
+WL_EXPORT int
+module_init(struct weston_compositor *ec,
+ int *argc, char *argv[])
+{
+ struct hmi_controller *hmi_ctrl = hmi_controller_create(ec);
+
+ if (wl_global_create(ec->wl_display,
+ &ivi_hmi_controller_interface, 1,
+ hmi_ctrl, bind_hmi_controller) == NULL) {
+ return -1;
+ }
+
+ struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
+ wl_event_loop_add_idle(loop, launch_hmi_client, ec);
+
+ return 0;
+}
diff --git a/ivi-shell/ivi-layout-export.h b/ivi-shell/ivi-layout-export.h
index 0f95f53..9784cf3 100644
--- a/ivi-shell/ivi-layout-export.h
+++ b/ivi-shell/ivi-layout-export.h
@@ -106,10 +106,6 @@ struct ivi_layout_LayerProperties
struct ivi_layout_layer;
struct ivi_layout_screen;

-typedef struct ivi_layout_surface* ivi_layout_surface_ptr;
-typedef struct ivi_layout_layer* ivi_layout_layer_ptr;
-typedef struct ivi_layout_screen* ivi_layout_screen_ptr;
-
enum ivi_layout_notification_mask {
IVI_NOTIFICATION_NONE = 0,
IVI_NOTIFICATION_OPACITY = (1 << 1),
@@ -393,7 +389,7 @@ ivi_layout_getNumberOfHardwareLayers(uint32_t id_screen,
* \return -1 if the method call was failed
*/
int32_t
-ivi_layout_getScreens(uint32_t *pLength, ivi_layout_screen_ptr **ppArray);
+ivi_layout_getScreens(uint32_t *pLength, struct ivi_layout_screen ***ppArray);

/**
* \brief Get the screens under the given layer
@@ -404,7 +400,7 @@ ivi_layout_getScreens(uint32_t *pLength, ivi_layout_screen_ptr **ppArray);
int32_t
ivi_layout_getScreensUnderLayer(struct ivi_layout_layer *ivilayer,
uint32_t *pLength,
- ivi_layout_screen_ptr **ppArray);
+ struct ivi_layout_screen ***ppArray);

/**
* \brief Get all Layers which are currently registered and managed by the services
@@ -413,7 +409,7 @@ ivi_layout_getScreensUnderLayer(struct ivi_layout_layer *ivilayer,
* \return -1 if the method call was failed
*/
int32_t
-ivi_layout_getLayers(uint32_t *pLength, ivi_layout_layer_ptr **ppArray);
+ivi_layout_getLayers(uint32_t *pLength, struct ivi_layout_layer ***ppArray);

/**
* \brief Get all Layers of the given screen
@@ -424,7 +420,7 @@ ivi_layout_getLayers(uint32_t *pLength, ivi_layout_layer_ptr **ppArray);
int32_t
ivi_layout_getLayersOnScreen(struct ivi_layout_screen *iviscrn,
uint32_t *pLength,
- ivi_layout_layer_ptr **ppArray);
+ struct ivi_layout_layer ***ppArray);

/**
* \brief Get all Layers under the given surface
@@ -435,7 +431,7 @@ ivi_layout_getLayersOnScreen(struct ivi_layout_screen *iviscrn,
int32_t
ivi_layout_getLayersUnderSurface(struct ivi_layout_surface *ivisurf,
uint32_t *pLength,
- ivi_layout_layer_ptr **ppArray);
+ struct ivi_layout_layer ***ppArray);

/**
* \brief Get all Surfaces which are currently registered and managed by the services
@@ -444,7 +440,7 @@ ivi_layout_getLayersUnderSurface(struct ivi_layout_surface *ivisurf,
* \return -1 if the method call was failed
*/
int32_t
-ivi_layout_getSurfaces(uint32_t *pLength, ivi_layout_surface_ptr **ppArray);
+ivi_layout_getSurfaces(uint32_t *pLength, struct ivi_layout_surface ***ppArray);

/**
* \brief Get all Surfaces which are currently registered to a given layer and are managed by the services
@@ -455,7 +451,7 @@ ivi_layout_getSurfaces(uint32_t *pLength, ivi_layout_surface_ptr **ppArray);
int32_t
ivi_layout_getSurfacesOnLayer(struct ivi_layout_layer *ivilayer,
uint32_t *pLength,
- ivi_layout_surface_ptr **ppArray);
+ struct ivi_layout_surface ***ppArray);

/**
* \brief Create a layer which should be managed by the service
diff --git a/ivi-shell/ivi-layout.c b/ivi-shell/ivi-layout.c
index 68f9b52..41b2b3b 100644
--- a/ivi-shell/ivi-layout.c
+++ b/ivi-shell/ivi-layout.c
@@ -1376,7 +1376,7 @@ ivi_layout_getNumberOfHardwareLayers(uint32_t id_screen,
}

WL_EXPORT int32_t
-ivi_layout_getScreens(uint32_t *pLength, ivi_layout_screen_ptr **ppArray)
+ivi_layout_getScreens(uint32_t *pLength, struct ivi_layout_screen ***ppArray)
{
struct ivi_layout *layout = get_instance();
struct ivi_layout_screen *iviscrn = NULL;
@@ -1392,7 +1392,7 @@ ivi_layout_getScreens(uint32_t *pLength, ivi_layout_screen_ptr **ppArray)

if (length != 0){
/* the Array must be free by module which called this function */
- *ppArray = calloc(length, sizeof(ivi_layout_screen_ptr));
+ *ppArray = calloc(length, sizeof(struct ivi_layout_screen *));
if (*ppArray == NULL) {
weston_log("fails to allocate memory\n");
return -1;
@@ -1411,7 +1411,7 @@ ivi_layout_getScreens(uint32_t *pLength, ivi_layout_screen_ptr **ppArray)
WL_EXPORT int32_t
ivi_layout_getScreensUnderLayer(struct ivi_layout_layer *ivilayer,
uint32_t *pLength,
- ivi_layout_screen_ptr **ppArray)
+ struct ivi_layout_screen ***ppArray)
{
struct link_screen *link_scrn = NULL;
uint32_t length = 0;
@@ -1426,7 +1426,7 @@ ivi_layout_getScreensUnderLayer(struct ivi_layout_layer *ivilayer,

if (length != 0){
/* the Array must be free by module which called this function */
- *ppArray = calloc(length, sizeof(ivi_layout_screen_ptr));
+ *ppArray = calloc(length, sizeof(struct ivi_layout_screen *));
if (*ppArray == NULL) {
weston_log("fails to allocate memory\n");
return -1;
@@ -1443,7 +1443,7 @@ ivi_layout_getScreensUnderLayer(struct ivi_layout_layer *ivilayer,
}

WL_EXPORT int32_t
-ivi_layout_getLayers(uint32_t *pLength, ivi_layout_layer_ptr **ppArray)
+ivi_layout_getLayers(uint32_t *pLength, struct ivi_layout_layer ***ppArray)
{
struct ivi_layout *layout = get_instance();
struct ivi_layout_layer *ivilayer = NULL;
@@ -1459,7 +1459,7 @@ ivi_layout_getLayers(uint32_t *pLength, ivi_layout_layer_ptr **ppArray)

if (length != 0){
/* the Array must be free by module which called this function */
- *ppArray = calloc(length, sizeof(ivi_layout_layer_ptr));
+ *ppArray = calloc(length, sizeof(struct ivi_layout_layer *));
if (*ppArray == NULL) {
weston_log("fails to allocate memory\n");
return -1;
@@ -1478,7 +1478,7 @@ ivi_layout_getLayers(uint32_t *pLength, ivi_layout_layer_ptr **ppArray)
WL_EXPORT int32_t
ivi_layout_getLayersOnScreen(struct ivi_layout_screen *iviscrn,
uint32_t *pLength,
- ivi_layout_layer_ptr **ppArray)
+ struct ivi_layout_layer ***ppArray)
{
struct ivi_layout_layer *ivilayer = NULL;
uint32_t length = 0;
@@ -1493,7 +1493,7 @@ ivi_layout_getLayersOnScreen(struct ivi_layout_screen *iviscrn,

if (length != 0){
/* the Array must be free by module which called this function */
- *ppArray = calloc(length, sizeof(ivi_layout_layer_ptr));
+ *ppArray = calloc(length, sizeof(struct ivi_layout_layer *));
if (*ppArray == NULL) {
weston_log("fails to allocate memory\n");
return -1;
@@ -1512,7 +1512,7 @@ ivi_layout_getLayersOnScreen(struct ivi_layout_screen *iviscrn,
WL_EXPORT int32_t
ivi_layout_getLayersUnderSurface(struct ivi_layout_surface *ivisurf,
uint32_t *pLength,
- ivi_layout_layer_ptr **ppArray)
+ struct ivi_layout_layer ***ppArray)
{
struct link_layer *link_layer = NULL;
uint32_t length = 0;
@@ -1527,7 +1527,7 @@ ivi_layout_getLayersUnderSurface(struct ivi_layout_surface *ivisurf,

if (length != 0){
/* the Array must be free by module which called this function */
- *ppArray = calloc(length, sizeof(ivi_layout_layer_ptr));
+ *ppArray = calloc(length, sizeof(struct ivi_layout_layer *));
if (*ppArray == NULL) {
weston_log("fails to allocate memory\n");
return -1;
@@ -1544,7 +1544,7 @@ ivi_layout_getLayersUnderSurface(struct ivi_layout_surface *ivisurf,
}

WL_EXPORT int32_t
-ivi_layout_getSurfaces(uint32_t *pLength, ivi_layout_surface_ptr **ppArray)
+ivi_layout_getSurfaces(uint32_t *pLength, struct ivi_layout_surface ***ppArray)
{
struct ivi_layout *layout = get_instance();
struct ivi_layout_surface *ivisurf = NULL;
@@ -1560,7 +1560,7 @@ ivi_layout_getSurfaces(uint32_t *pLength, ivi_layout_surface_ptr **ppArray)

if (length != 0){
/* the Array must be free by module which called this function */
- *ppArray = calloc(length, sizeof(ivi_layout_surface_ptr));
+ *ppArray = calloc(length, sizeof(struct ivi_layout_surface *));
if (*ppArray == NULL) {
weston_log("fails to allocate memory\n");
return -1;
@@ -1579,7 +1579,7 @@ ivi_layout_getSurfaces(uint32_t *pLength, ivi_layout_surface_ptr **ppArray)
WL_EXPORT int32_t
ivi_layout_getSurfacesOnLayer(struct ivi_layout_layer *ivilayer,
uint32_t *pLength,
- ivi_layout_surface_ptr **ppArray)
+ struct ivi_layout_surface ***ppArray)
{
struct ivi_layout_surface *ivisurf = NULL;
uint32_t length = 0;
@@ -1594,7 +1594,7 @@ ivi_layout_getSurfacesOnLayer(struct ivi_layout_layer *ivilayer,

if (length != 0) {
/* the Array must be free by module which called this function */
- *ppArray = calloc(length, sizeof(ivi_layout_surface_ptr));
+ *ppArray = calloc(length, sizeof(struct ivi_layout_surface *));
if (*ppArray == NULL) {
weston_log("fails to allocate memory\n");
return -1;
--
1.8.3.1
Nobuhiko Tanibata
2014-05-20 04:30:27 UTC
Permalink
This is launched from hmi-controller by launch_hmi_client_process and invoke a
client process.

The basic flow is as followed,
1/ process invoked
2/ read configuration from weston.ini.
3/ draw png file to surface according to configuration of weston.ini
4/ all parts of UI are ready. request "UI_ready" to draw UI.
5/ Enter event loop
6/ If a surface receives touch/pointer event, followings are invoked according
to type of event and surface
6-1/ If a surface to launch ivi_application receive touch up, it execs
ivi-application configured in weston.ini.
6-2/ If a surface to switch layout mode receive touch up, it sends a request,
ivi_hmi_controller_switch_mode, to hmi-controller.
6-3/ If a surface to show workspace having launchers, it sends a request,
ivi_hmi_controller_home, to hmi-controller.
6-4/ If touch down events happens in workspace,
ivi_hmi_controller_workspace_control is sent to slide workspace.
When control finished, event: ivi_hmi_controller_workspace_end_control
is received.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- apply review comments from mailing list

Makefile.am | 10 +-
clients/ivi-shell-user-interface.c | 1332 ++++++++++++++++++++++++++++++++++++
ivi-shell/hmi-controller.c | 42 +-
3 files changed, 1380 insertions(+), 4 deletions(-)
create mode 100644 clients/ivi-shell-user-interface.c

diff --git a/Makefile.am b/Makefile.am
index 1f75cc3..46c5e3d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -359,7 +359,8 @@ libexec_PROGRAMS += \
weston-desktop-shell \
weston-screenshooter \
weston-keyboard \
- weston-simple-im
+ weston-simple-im \
+ weston-ivi-shell-user-interface

demo_clients = \
weston-flower \
@@ -570,6 +571,13 @@ nodist_weston_desktop_shell_SOURCES = \
weston_desktop_shell_LDADD = libtoytoolkit.la
weston_desktop_shell_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)

+weston_ivi_shell_user_interface_SOURCES = clients/ivi-shell-user-interface.c
+nodist_weston_ivi_shell_user_interface_SOURCES = \
+ protocol/ivi-hmi-controller-client-protocol.h \
+ protocol/ivi-hmi-controller-protocol.c
+weston_ivi_shell_user_interface_LDADD = libtoytoolkit.la
+weston_ivi_shell_user_interface_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
if BUILD_FULL_GL_CLIENTS
demo_clients += weston-gears
weston_gears_SOURCES = clients/gears.c
diff --git a/clients/ivi-shell-user-interface.c b/clients/ivi-shell-user-interface.c
new file mode 100644
index 0000000..70b854b
--- /dev/null
+++ b/clients/ivi-shell-user-interface.c
@@ -0,0 +1,1332 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <wayland-cursor.h>
+#include "../shared/cairo-util.h"
+#include "../shared/config-parser.h"
+#include "ivi-application-client-protocol.h"
+#include "ivi-hmi-controller-client-protocol.h"
+
+/**
+ * A reference implementation how to use ivi-hmi-controller interface to interact
+ * with hmi-controller. This is launched from hmi-controller by using
+ * hmi_client_start and create a pthread.
+ *
+ * The basic flow is as followed,
+ * 1/ create pthread
+ * 2/ read configuration from weston.ini.
+ * 3/ draw png file to surface according to configuration of weston.ini
+ * 4/ set up UI by using ivi-hmi-controller protocol
+ * 5/ Enter event loop
+ * 6/ If a surface receives touch/pointer event, followings are invoked according
+ * to type of event and surface
+ * 6-1/ If a surface to launch ivi_application receive touch up, it execs
+ * ivi-application configured in weston.ini.
+ * 6-2/ If a surface to switch layout mode receive touch up, it sends a request,
+ * ivi_hmi_controller_switch_mode, to hmi-controller.
+ * 6-3/ If a surface to show workspace having launchers, it sends a request,
+ * ivi_hmi_controller_home, to hmi-controller.
+ * 6-4/ If touch down events happens in workspace,
+ * ivi_hmi_controller_workspace_control is sent to slide workspace.
+ * When control finished, event: ivi_hmi_controller_workspace_end_control
+ * is received.
+ */
+
+/*****************************************************************************
+ * structure, globals
+ ****************************************************************************/
+enum cursor_type {
+ CURSOR_BOTTOM_LEFT,
+ CURSOR_BOTTOM_RIGHT,
+ CURSOR_BOTTOM,
+ CURSOR_DRAGGING,
+ CURSOR_LEFT_PTR,
+ CURSOR_LEFT,
+ CURSOR_RIGHT,
+ CURSOR_TOP_LEFT,
+ CURSOR_TOP_RIGHT,
+ CURSOR_TOP,
+ CURSOR_IBEAM,
+ CURSOR_HAND1,
+ CURSOR_WATCH,
+
+ CURSOR_BLANK
+};
+struct wlContextCommon {
+ struct wl_display *wlDisplay;
+ struct wl_registry *wlRegistry;
+ struct wl_compositor *wlCompositor;
+ struct wl_shm *wlShm;
+ struct wl_seat *wlSeat;
+ struct wl_pointer *wlPointer;
+ struct wl_touch *wlTouch;
+ struct ivi_application *iviApplication;
+ struct ivi_hmi_controller *hmiCtrl;
+ struct hmi_homescreen_setting *hmi_setting;
+ struct wl_list *list_wlContextStruct;
+ struct wl_surface *enterSurface;
+ int32_t is_home_on;
+ struct wl_cursor_theme *cursor_theme;
+ struct wl_cursor **cursors;
+ struct wl_surface *pointer_surface;
+ enum cursor_type current_cursor;
+ uint32_t enter_serial;
+};
+
+struct wlContextStruct {
+ struct wlContextCommon cmm;
+ struct wl_surface *wlSurface;
+ struct wl_buffer *wlBuffer;
+ uint32_t formats;
+ cairo_surface_t *ctx_image;
+ void *data;
+ uint32_t id_surface;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_srf {
+ uint32_t id;
+ char *filePath;
+ uint32_t color;
+};
+
+struct
+hmi_homescreen_workspace {
+ struct wl_array launcher_id_array;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_launcher {
+ uint32_t icon_surface_id;
+ uint32_t workspace_id;
+ char* icon;
+ char* path;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_setting {
+ struct hmi_homescreen_srf background;
+ struct hmi_homescreen_srf panel;
+ struct hmi_homescreen_srf tiling;
+ struct hmi_homescreen_srf sidebyside;
+ struct hmi_homescreen_srf fullscreen;
+ struct hmi_homescreen_srf random;
+ struct hmi_homescreen_srf home;
+ struct hmi_homescreen_srf workspace_background;
+
+ struct wl_list workspace_list;
+ struct wl_list launcher_list;
+
+ char *cursor_theme;
+ int32_t cursor_size;
+};
+
+volatile int gRun = 0;
+
+static void *
+fail_on_null(void *p, size_t size, char* file, int32_t line)
+{
+ if (size && !p) {
+ fprintf(stderr, "%s(%d) %zd: out of memory\n", file, line, size);
+ exit(EXIT_FAILURE);
+ }
+
+ return p;
+}
+
+static void *
+mem_alloc(size_t size, char* file, int32_t line)
+{
+ return fail_on_null(calloc(1, size), size, file, line);
+}
+
+#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+/*****************************************************************************
+ * Event Handler
+ ****************************************************************************/
+
+static void
+shm_format(void* data, struct wl_shm* pWlShm, uint32_t format)
+{
+ struct wlContextStruct* pDsp = data;
+ pDsp->formats |= (1 << format);
+}
+
+static struct wl_shm_listener shm_listenter = {
+ shm_format
+};
+
+static int32_t
+getIdOfWlSurface(struct wlContextCommon *pCtx, struct wl_surface *wlSurface)
+{
+ if (NULL == pCtx ||
+ NULL == wlSurface ) {
+ return 0;
+ }
+
+ struct wlContextStruct* pWlCtxSt = NULL;
+ wl_list_for_each(pWlCtxSt, pCtx->list_wlContextStruct, link) {
+ if (pWlCtxSt->wlSurface == wlSurface) {
+ return pWlCtxSt->id_surface;
+ }
+ continue;
+ }
+ return -1;
+}
+
+static void
+set_pointer_image(struct wlContextCommon *pCtx, uint32_t index)
+{
+ if (!pCtx->wlPointer ||
+ !pCtx->cursors) {
+ return;
+ }
+
+ if (CURSOR_BLANK == pCtx->current_cursor) {
+ wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
+ NULL, 0, 0);
+ return;
+ }
+
+ struct wl_cursor *cursor = pCtx->cursors[pCtx->current_cursor];
+ if (!cursor) {
+ return;
+ }
+
+ if (cursor->image_count <= index) {
+ fprintf(stderr, "cursor index out of range\n");
+ return;
+ }
+
+ struct wl_cursor_image *image = cursor->images[index];
+ struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
+
+ if (!buffer) {
+ return;
+ }
+
+ wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
+ pCtx->pointer_surface,
+ image->hotspot_x, image->hotspot_y);
+
+ wl_surface_attach(pCtx->pointer_surface, buffer, 0, 0);
+
+ wl_surface_damage(pCtx->pointer_surface, 0, 0,
+ image->width, image->height);
+
+ wl_surface_commit(pCtx->pointer_surface);
+}
+
+static void
+PointerHandleEnter(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ struct wl_surface* wlSurface, wl_fixed_t sx, wl_fixed_t sy)
+{
+ (void)wlPointer;
+ (void)serial;
+
+ struct wlContextCommon *pCtx = data;
+ pCtx->enter_serial = serial;
+ pCtx->enterSurface = wlSurface;
+ set_pointer_image(pCtx, 0);
+#ifdef _DEBUG
+ printf("ENTER PointerHandleEnter: x(%d), y(%d)\n", sx, sy);
+#endif
+}
+
+static void
+PointerHandleLeave(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ struct wl_surface* wlSurface)
+{
+ (void)wlPointer;
+ (void)wlSurface;
+
+ struct wlContextCommon *pCtx = data;
+ pCtx->enterSurface = NULL;
+
+#ifdef _DEBUG
+ printf("ENTER PointerHandleLeave: serial(%d)\n", serial);
+#endif
+}
+
+static void
+PointerHandleMotion(void* data, struct wl_pointer* wlPointer, uint32_t time,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ (void)data;
+ (void)wlPointer;
+ (void)time;
+
+#ifdef _DEBUG
+ printf("ENTER PointerHandleMotion: x(%d), y(%d)\n", gPointerX, gPointerY);
+#endif
+}
+
+/**
+ * if a surface assigned as launcher receives touch-off event, invoking
+ * ivi-application which configured in weston.ini with path to binary.
+ */
+extern char **environ; /*defied by libc */
+
+static pid_t execute_process(char* path, char *argv[])
+{
+ pid_t pid = fork();
+ if (pid < 0) {
+ fprintf(stderr, "Failed to fork\n");
+ }
+
+ if (pid) {
+ return pid;
+ }
+
+ if (-1 == execve(path, argv, environ)) {
+ fprintf(stderr, "Failed to execve %s\n", path);
+ exit(1);
+ }
+
+ return pid;
+}
+
+static int32_t
+launcher_button(uint32_t surfaceId, struct wl_list *launcher_list)
+{
+ struct hmi_homescreen_launcher *launcher = NULL;
+
+ wl_list_for_each(launcher, launcher_list, link) {
+ if (surfaceId != launcher->icon_surface_id) {
+ continue;
+ }
+
+ char *argv[] = {NULL};
+ execute_process(launcher->path, argv);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * is-method to identify a surface set as launcher in workspace or workspace
+ * itself. This is-method is used to decide whether request;
+ * ivi_hmi_controller_workspace_control is sent or not.
+ */
+static int32_t
+isWorkspaceSurface(uint32_t id, struct hmi_homescreen_setting *hmi_setting)
+{
+ if (id == hmi_setting->workspace_background.id) {
+ return 1;
+ }
+
+ struct hmi_homescreen_launcher *launcher = NULL;
+ wl_list_for_each(launcher, &hmi_setting->launcher_list, link) {
+ if (id == launcher->icon_surface_id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Decide which request is sent to hmi-controller
+ */
+static void
+touch_up(struct ivi_hmi_controller *hmi_ctrl, uint32_t id_surface,
+ int32_t *is_home_on, struct hmi_homescreen_setting* hmi_setting)
+{
+ if (launcher_button(id_surface, &hmi_setting->launcher_list)) {
+ *is_home_on = 0;
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ } else if (id_surface == hmi_setting->tiling.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING);
+ } else if (id_surface == hmi_setting->sidebyside.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE);
+ } else if (id_surface == hmi_setting->fullscreen.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN);
+ } else if (id_surface == hmi_setting->random.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM);
+ } else if (id_surface == hmi_setting->home.id) {
+ *is_home_on = !(*is_home_on);
+ if (*is_home_on) {
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_ON);
+ } else {
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ }
+ }
+}
+
+/**
+ * Even handler of Pointer event. IVI system is usually manipulated by touch
+ * screen. However, some systems also have pointer device.
+ * Release is the same behavior as touch off
+ * Pressed is the same behavior as touch on
+ */
+static void
+PointerHandleButton(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ uint32_t time, uint32_t button, uint32_t state)
+{
+ (void)wlPointer;
+ (void)serial;
+ (void)time;
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ if (BTN_RIGHT == button) {
+ return;
+ }
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ switch (state) {
+ case WL_POINTER_BUTTON_STATE_RELEASED:
+ touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, pCtx->hmi_setting);
+ break;
+
+ case WL_POINTER_BUTTON_STATE_PRESSED:
+
+ if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
+ ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, serial);
+ }
+
+ break;
+ }
+#ifdef _DEBUG
+ printf("ENTER PointerHandleButton: button(%d), state(%d)\n", button, state);
+#endif
+}
+
+static void
+PointerHandleAxis(void* data, struct wl_pointer* wlPointer, uint32_t time,
+ uint32_t axis, wl_fixed_t value)
+{
+ (void)data;
+ (void)wlPointer;
+ (void)time;
+#ifdef _DEBUG
+ printf("ENTER PointerHandleAxis: axis(%d), value(%d)\n", axis, value);
+#endif
+}
+
+static struct wl_pointer_listener pointer_listener = {
+ PointerHandleEnter,
+ PointerHandleLeave,
+ PointerHandleMotion,
+ PointerHandleButton,
+ PointerHandleAxis
+};
+
+/**
+ * Even handler of touch event
+ */
+static void
+TouchHandleDown(void *data, struct wl_touch *wlTouch, uint32_t serial, uint32_t time,
+ struct wl_surface *surface, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ if (0 == id){
+ pCtx->enterSurface = surface;
+ }
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * When touch down happens on surfaces of workspace, ask hmi-controller to start
+ * control workspace to select page of workspace.
+ * After sending seat to hmi-controller by ivi_hmi_controller_workspace_control,
+ * hmi-controller-homescreen doesn't receive any event till hmi-controller sends
+ * back it.
+ */
+ if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
+ ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, serial);
+ }
+}
+
+static void
+TouchHandleUp(void *data, struct wl_touch *wlTouch, uint32_t serial, uint32_t time,
+ int32_t id)
+{
+ (void)serial;
+ (void)time;
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * triggering event according to touch-up happening on which surface.
+ */
+ if (id == 0){
+ touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, pCtx->hmi_setting);
+ }
+}
+
+static void
+TouchHandleMotion(void *data, struct wl_touch *wlTouch, uint32_t time,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+}
+
+static void
+TouchHandleFrame(void *data, struct wl_touch *wlTouch)
+{
+}
+
+static void
+TouchHandleCancel(void *data, struct wl_touch *wlTouch)
+{
+}
+
+static struct wl_touch_listener touch_listener = {
+ TouchHandleDown,
+ TouchHandleUp,
+ TouchHandleMotion,
+ TouchHandleFrame,
+ TouchHandleCancel,
+};
+
+/**
+ * Handler of capabilities
+ */
+static void
+seat_handle_capabilities(void* data, struct wl_seat* seat, uint32_t caps)
+{
+ (void)seat;
+ struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
+ struct wl_seat* wlSeat = p_wlCtx->wlSeat;
+ struct wl_pointer* wlPointer = p_wlCtx->wlPointer;
+ struct wl_touch* wlTouch = p_wlCtx->wlTouch;
+
+ if (p_wlCtx->hmi_setting->cursor_theme) {
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wlPointer){
+ wlPointer = wl_seat_get_pointer(wlSeat);
+ wl_pointer_set_user_data(wlPointer, data);
+ wl_pointer_add_listener(wlPointer, &pointer_listener, data);
+ } else
+ if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wlPointer){
+ wl_pointer_destroy(wlPointer);
+ wlPointer = NULL;
+ }
+ p_wlCtx->wlPointer = wlPointer;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wlTouch){
+ wlTouch = wl_seat_get_touch(wlSeat);
+ wl_touch_set_user_data(wlTouch, data);
+ wl_touch_add_listener(wlTouch, &touch_listener, data);
+ } else
+ if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wlTouch){
+ wl_touch_destroy(wlTouch);
+ wlTouch = NULL;
+ }
+ p_wlCtx->wlTouch = wlTouch;
+}
+
+static struct wl_seat_listener seat_Listener = {
+ seat_handle_capabilities,
+};
+
+/**
+ * Registration of event
+ * This event is received when hmi-controller server finished controlling
+ * workspace.
+ */
+static void
+ivi_hmi_controller_workspace_end_control(void *data,
+ struct ivi_hmi_controller *hmi_ctrl,
+ int32_t is_controlled)
+{
+ if (is_controlled) {
+ return;
+ }
+
+ struct wlContextCommon *pCtx = data;
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * During being controlled by hmi-controller, any input event is not
+ * notified. So when control ends with touch up, it invokes launcher
+ * if up event happens on a launcher surface.
+ *
+ */
+ if (launcher_button(id_surface, &pCtx->hmi_setting->launcher_list)) {
+ pCtx->is_home_on = 0;
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ }
+}
+
+static const struct ivi_hmi_controller_listener hmi_controller_listener = {
+ ivi_hmi_controller_workspace_end_control
+};
+
+/**
+ * Registration of interfaces
+ */
+static void
+registry_handle_global(void* data, struct wl_registry* registry, uint32_t name,
+ const char *interface, uint32_t version)
+{
+ (void)version;
+ struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
+
+ do {
+ if (!strcmp(interface, "wl_compositor")) {
+ p_wlCtx->wlCompositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+ break;
+ }
+ if (!strcmp(interface, "wl_shm")) {
+ p_wlCtx->wlShm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
+ wl_shm_add_listener(p_wlCtx->wlShm, &shm_listenter, p_wlCtx);
+ break;
+ }
+ if (!strcmp(interface, "wl_seat")) {
+ p_wlCtx->wlSeat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
+ wl_seat_add_listener(p_wlCtx->wlSeat, &seat_Listener, data);
+ break;
+ }
+ if (!strcmp(interface, "ivi_application")) {
+ p_wlCtx->iviApplication = wl_registry_bind(registry, name, &ivi_application_interface, 1);
+ break;
+ }
+ if (!strcmp(interface, "ivi_hmi_controller")) {
+ p_wlCtx->hmiCtrl = wl_registry_bind(registry, name, &ivi_hmi_controller_interface, 1);
+
+ if (p_wlCtx->hmiCtrl) {
+ ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl, &hmi_controller_listener, p_wlCtx);
+ }
+ break;
+ }
+
+ } while(0);
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ NULL
+};
+
+static void
+frame_listener_func(void *data, struct wl_callback *callback, uint32_t time)
+{
+ if (callback) {
+ wl_callback_destroy(callback);
+ }
+}
+
+static const struct wl_callback_listener frame_listener = {
+ frame_listener_func
+};
+
+/*
+ * The following correspondences between file names and cursors was copied
+ * from: https://bugs.kde.org/attachment.cgi?id=67313
+ */
+static const char *bottom_left_corners[] = {
+ "bottom_left_corner",
+ "sw-resize",
+ "size_bdiag"
+};
+
+static const char *bottom_right_corners[] = {
+ "bottom_right_corner",
+ "se-resize",
+ "size_fdiag"
+};
+
+static const char *bottom_sides[] = {
+ "bottom_side",
+ "s-resize",
+ "size_ver"
+};
+
+static const char *grabbings[] = {
+ "grabbing",
+ "closedhand",
+ "208530c400c041818281048008011002"
+};
+
+static const char *left_ptrs[] = {
+ "left_ptr",
+ "default",
+ "top_left_arrow",
+ "left-arrow"
+};
+
+static const char *left_sides[] = {
+ "left_side",
+ "w-resize",
+ "size_hor"
+};
+
+static const char *right_sides[] = {
+ "right_side",
+ "e-resize",
+ "size_hor"
+};
+
+static const char *top_left_corners[] = {
+ "top_left_corner",
+ "nw-resize",
+ "size_fdiag"
+};
+
+static const char *top_right_corners[] = {
+ "top_right_corner",
+ "ne-resize",
+ "size_bdiag"
+};
+
+static const char *top_sides[] = {
+ "top_side",
+ "n-resize",
+ "size_ver"
+};
+
+static const char *xterms[] = {
+ "xterm",
+ "ibeam",
+ "text"
+};
+
+static const char *hand1s[] = {
+ "hand1",
+ "pointer",
+ "pointing_hand",
+ "e29285e634086352946a0e7090d73106"
+};
+
+static const char *watches[] = {
+ "watch",
+ "wait",
+ "0426c94ea35c87780ff01dc239897213"
+};
+
+struct cursor_alternatives {
+ const char **names;
+ size_t count;
+};
+
+static const struct cursor_alternatives cursors[] = {
+ {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
+ {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
+ {bottom_sides, ARRAY_LENGTH(bottom_sides)},
+ {grabbings, ARRAY_LENGTH(grabbings)},
+ {left_ptrs, ARRAY_LENGTH(left_ptrs)},
+ {left_sides, ARRAY_LENGTH(left_sides)},
+ {right_sides, ARRAY_LENGTH(right_sides)},
+ {top_left_corners, ARRAY_LENGTH(top_left_corners)},
+ {top_right_corners, ARRAY_LENGTH(top_right_corners)},
+ {top_sides, ARRAY_LENGTH(top_sides)},
+ {xterms, ARRAY_LENGTH(xterms)},
+ {hand1s, ARRAY_LENGTH(hand1s)},
+ {watches, ARRAY_LENGTH(watches)},
+};
+
+static void
+create_cursors(struct wlContextCommon *cmm)
+{
+ uint32_t i = 0;
+ uint32_t j = 0;
+ struct wl_cursor *cursor = NULL;
+ char* cursor_theme = cmm->hmi_setting->cursor_theme;
+ int32_t cursor_size = cmm->hmi_setting->cursor_size;
+
+ cmm->cursor_theme = wl_cursor_theme_load(cursor_theme, cursor_size, cmm->wlShm);
+
+ cmm->cursors = MEM_ALLOC(ARRAY_LENGTH(cursors) * sizeof(cmm->cursors[0]));
+
+ for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
+ cursor = NULL;
+
+ for (j = 0; !cursor && j < cursors[i].count; ++j) {
+ cursor = wl_cursor_theme_get_cursor(
+ cmm->cursor_theme, cursors[i].names[j]);
+ }
+
+ if (!cursor) {
+ fprintf(stderr, "could not load cursor '%s'\n",
+ cursors[i].names[0]);
+ }
+
+ cmm->cursors[i] = cursor;
+ }
+}
+
+static void
+destroy_cursors(struct wlContextCommon *cmm)
+{
+ if (cmm->cursor_theme) {
+ wl_cursor_theme_destroy(cmm->cursor_theme);
+ }
+
+ free(cmm->cursors);
+}
+
+/**
+ * Internal method to prepare parts of UI
+ */
+static void
+createShmBuffer(struct wlContextStruct *p_wlCtx)
+{
+ struct wl_shm_pool *pool;
+
+ char filename[] = "/tmp/wayland-shm-XXXXXX";
+ int fd = -1;
+ int size = 0;
+ int width = 0;
+ int height = 0;
+ int stride = 0;
+
+ fd = mkstemp(filename);
+ if (fd < 0) {
+ fprintf(stderr, "open %s failed: %m\n", filename);
+ return;
+ }
+
+ width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
+ height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
+ stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
+
+ size = stride * height;
+ if (ftruncate(fd, size) < 0) {
+ fprintf(stderr, "ftruncate failed: %m\n");
+ close(fd);
+ return;
+ }
+
+ p_wlCtx->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ if (MAP_FAILED == p_wlCtx->data) {
+ fprintf(stderr, "mmap failed: %m\n");
+ close(fd);
+ return;
+ }
+
+ pool = wl_shm_create_pool(p_wlCtx->cmm.wlShm, fd, size);
+ p_wlCtx->wlBuffer = wl_shm_pool_create_buffer(pool, 0,
+ width,
+ height,
+ stride,
+ WL_SHM_FORMAT_ARGB8888);
+
+ if (NULL == p_wlCtx->wlBuffer) {
+ fprintf(stderr, "wl_shm_create_buffer failed: %m\n");
+ close(fd);
+ return;
+ }
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ return;
+}
+
+static void
+destroyWLContextCommon(struct wlContextCommon *p_wlCtx)
+{
+ destroy_cursors(p_wlCtx);
+
+ if (p_wlCtx->pointer_surface) {
+ wl_surface_destroy(p_wlCtx->pointer_surface);
+ }
+
+ if (p_wlCtx->wlCompositor) {
+ wl_compositor_destroy(p_wlCtx->wlCompositor);
+ }
+}
+
+static void
+destroyWLContextStruct(struct wlContextStruct *p_wlCtx)
+{
+ if (p_wlCtx->wlSurface) {
+ wl_surface_destroy(p_wlCtx->wlSurface);
+ }
+
+ if (p_wlCtx->ctx_image) {
+ cairo_surface_destroy(p_wlCtx->ctx_image);
+ p_wlCtx->ctx_image = NULL;
+ }
+}
+
+static int
+createWLContext(struct wlContextStruct *p_wlCtx)
+{
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+
+ p_wlCtx->wlSurface = wl_compositor_create_surface(p_wlCtx->cmm.wlCompositor);
+ if (NULL == p_wlCtx->wlSurface) {
+ printf("Error: wl_compositor_create_surface failed.\n");
+ destroyWLContextCommon(&p_wlCtx->cmm);
+ abort();
+ }
+
+
+ createShmBuffer(p_wlCtx);
+
+ wl_display_flush(p_wlCtx->cmm.wlDisplay);
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+
+ return 0;
+}
+
+static void
+drawImage(struct wlContextStruct *p_wlCtx)
+{
+ struct wl_callback *callback;
+
+ int width = 0;
+ int height = 0;
+ int stride = 0;
+ void *data = NULL;
+
+ width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
+ height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
+ stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
+ data = cairo_image_surface_get_data(p_wlCtx->ctx_image);
+
+ memcpy(p_wlCtx->data, data, stride * height);
+
+ wl_surface_attach(p_wlCtx->wlSurface, p_wlCtx->wlBuffer, 0, 0);
+ wl_surface_damage(p_wlCtx->wlSurface, 0, 0, width, height);
+
+ callback = wl_surface_frame(p_wlCtx->wlSurface);
+ wl_callback_add_listener(callback, &frame_listener, NULL);
+
+ wl_surface_commit(p_wlCtx->wlSurface);
+
+ wl_display_flush(p_wlCtx->cmm.wlDisplay);
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+}
+
+static void
+create_ivisurface(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ cairo_surface_t* surface)
+{
+ struct ivi_surface *ivisurf = NULL;
+
+ p_wlCtx->ctx_image = surface;
+
+ p_wlCtx->id_surface = id_surface;
+ wl_list_init(&p_wlCtx->link);
+ wl_list_insert(p_wlCtx->cmm.list_wlContextStruct, &p_wlCtx->link);
+
+ createWLContext(p_wlCtx);
+
+ ivisurf = ivi_application_surface_create(p_wlCtx->cmm.iviApplication,
+ id_surface, p_wlCtx->wlSurface);
+ if (ivisurf == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ return;
+ }
+
+ drawImage(p_wlCtx);
+
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+}
+
+static void
+create_ivisurfaceFromFile(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ const char* imageFile)
+{
+ cairo_surface_t* surface = load_cairo_surface(imageFile);
+
+ if (NULL == surface) {
+ fprintf(stderr, "Failed to load_cairo_surface %s\n", imageFile);
+ return;
+ }
+
+ create_ivisurface(p_wlCtx, id_surface, surface);
+}
+
+static void
+set_hex_color(cairo_t *cr, uint32_t color)
+{
+ cairo_set_source_rgba(cr,
+ ((color >> 16) & 0xff) / 255.0,
+ ((color >> 8) & 0xff) / 255.0,
+ ((color >> 0) & 0xff) / 255.0,
+ ((color >> 24) & 0xff) / 255.0);
+}
+
+static void
+create_ivisurfaceFromColor(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ uint32_t width, uint32_t height,
+ uint32_t color)
+{
+ cairo_surface_t *surface = NULL;
+ cairo_t *cr = NULL;
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+
+ cr = cairo_create(surface);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle(cr, 0, 0, width, height);
+ set_hex_color(cr, color);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+
+ create_ivisurface(p_wlCtx, id_surface, surface);
+}
+
+static void
+UI_ready(struct ivi_hmi_controller *controller)
+{
+ ivi_hmi_controller_UI_ready(controller);
+}
+
+/**
+ * Internal method to set up UI by using ivi-hmi-controller
+ */
+static void
+create_background(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+}
+
+static void
+create_panel(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+}
+
+static void
+create_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile, uint32_t number)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+}
+
+static void
+create_home_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+}
+
+static void
+create_workspace_background(
+ struct wlContextStruct *p_wlCtx, struct hmi_homescreen_srf *srf)
+{
+ create_ivisurfaceFromColor(p_wlCtx, srf->id, 1, 1, srf->color);
+}
+
+static void
+create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list)
+{
+ int launcher_count = wl_list_length(launcher_list);
+
+ if (0 == launcher_count) {
+ return;
+ }
+
+ struct hmi_homescreen_launcher** launchers;
+ launchers = MEM_ALLOC(launcher_count * sizeof(*launchers));
+
+ int ii = 0;
+ struct hmi_homescreen_launcher *launcher = NULL;
+
+ wl_list_for_each(launcher, launcher_list, link) {
+ launchers[ii] = launcher;
+ ii++;
+ }
+
+ int start = 0;
+
+ for (ii = 0; ii < launcher_count; ii++) {
+
+ if (ii != launcher_count -1 &&
+ launchers[ii]->workspace_id == launchers[ii + 1]->workspace_id) {
+ continue;
+ }
+
+ int jj = 0;
+ for (jj = start; jj <= ii; jj++) {
+ struct wlContextStruct *p_wlCtx = MEM_ALLOC(sizeof(*p_wlCtx));
+ p_wlCtx->cmm = *cmm;
+ create_ivisurfaceFromFile(p_wlCtx,launchers[jj]->icon_surface_id, launchers[jj]->icon);
+ }
+
+ start = ii + 1;
+ }
+
+ free(launchers);
+}
+
+static void sigFunc(int signum)
+{
+ gRun = 0;
+}
+
+/**
+ * Internal method to read out weston.ini to get configuration
+ */
+static struct hmi_homescreen_setting*
+hmi_homescreen_setting_create(void)
+{
+ struct hmi_homescreen_setting* setting = MEM_ALLOC(sizeof(*setting));
+
+ wl_list_init(&setting->workspace_list);
+ wl_list_init(&setting->launcher_list);
+
+ struct weston_config *config = NULL;
+ config = weston_config_parse("weston.ini");
+
+ struct weston_config_section *shellSection = NULL;
+ shellSection = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ weston_config_section_get_string(
+ shellSection, "cursor-theme", &setting->cursor_theme, NULL);
+
+ weston_config_section_get_int(shellSection, "cursor-size", &setting->cursor_size, 32);
+
+ uint32_t workspace_layer_id;
+ weston_config_section_get_uint(
+ shellSection, "workspace-layer-id", &workspace_layer_id, 3000);
+
+ weston_config_section_get_string(
+ shellSection, "background-image", &setting->background.filePath,
+ DATADIR "/weston/background.png");
+
+ weston_config_section_get_uint(
+ shellSection, "background-id", &setting->background.id, 1001);
+
+ weston_config_section_get_string(
+ shellSection, "panel-image", &setting->panel.filePath,
+ DATADIR "/weston/panel.png");
+
+ weston_config_section_get_uint(
+ shellSection, "panel-id", &setting->panel.id, 1002);
+
+ weston_config_section_get_string(
+ shellSection, "tiling-image", &setting->tiling.filePath,
+ DATADIR "/weston/tiling.png");
+
+ weston_config_section_get_uint(
+ shellSection, "tiling-id", &setting->tiling.id, 1003);
+
+ weston_config_section_get_string(
+ shellSection, "sidebyside-image", &setting->sidebyside.filePath,
+ DATADIR "/weston/sidebyside.png");
+
+ weston_config_section_get_uint(
+ shellSection, "sidebyside-id", &setting->sidebyside.id, 1004);
+
+ weston_config_section_get_string(
+ shellSection, "fullscreen-image", &setting->fullscreen.filePath,
+ DATADIR "/weston/fullscreen.png");
+
+ weston_config_section_get_uint(
+ shellSection, "fullscreen-id", &setting->fullscreen.id, 1005);
+
+ weston_config_section_get_string(
+ shellSection, "random-image", &setting->random.filePath,
+ DATADIR "/weston/random.png");
+
+ weston_config_section_get_uint(
+ shellSection, "random-id", &setting->random.id, 1006);
+
+ weston_config_section_get_string(
+ shellSection, "home-image", &setting->home.filePath,
+ DATADIR "/weston/home.png");
+
+ weston_config_section_get_uint(
+ shellSection, "home-id", &setting->home.id, 1007);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-color",
+ &setting->workspace_background.color, 0x99000000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-id",
+ &setting->workspace_background.id, 2001);
+
+ struct weston_config_section *section = NULL;
+ const char *name = NULL;
+
+ uint32_t icon_surface_id = workspace_layer_id + 1;
+
+ while (weston_config_next_section(config, &section, &name)) {
+
+ if (0 == strcmp(name, "ivi-launcher")) {
+
+ struct hmi_homescreen_launcher *launcher = NULL;
+ launcher = MEM_ALLOC(sizeof(*launcher));
+ wl_list_init(&launcher->link);
+
+ weston_config_section_get_string(section, "icon", &launcher->icon, NULL);
+ weston_config_section_get_string(section, "path", &launcher->path, NULL);
+ weston_config_section_get_uint(section, "workspace-id", &launcher->workspace_id, 0);
+ weston_config_section_get_uint(section, "icon-id", &launcher->icon_surface_id, icon_surface_id);
+ icon_surface_id++;
+
+ wl_list_insert(setting->launcher_list.prev, &launcher->link);
+ }
+ }
+
+ weston_config_destroy(config);
+ return setting;
+}
+
+/**
+ * Main thread
+ *
+ * The basic flow are as followed,
+ * 1/ read configuration from weston.ini by hmi_homescreen_setting_create
+ * 2/ draw png file to surface according to configuration of weston.ini and
+ * set up UI by using ivi-hmi-controller protocol by each create_* method
+ */
+int main(int argc, char **argv)
+{
+ struct wlContextCommon wlCtxCommon;
+ struct wlContextStruct wlCtx_BackGround;
+ struct wlContextStruct wlCtx_Panel;
+ struct wlContextStruct wlCtx_Button_1;
+ struct wlContextStruct wlCtx_Button_2;
+ struct wlContextStruct wlCtx_Button_3;
+ struct wlContextStruct wlCtx_Button_4;
+ struct wlContextStruct wlCtx_HomeButton;
+ struct wlContextStruct wlCtx_WorkSpaceBackGround;
+ struct wl_list launcher_wlCtxList;
+
+ memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon));
+ memset(&wlCtx_BackGround, 0x00, sizeof(wlCtx_BackGround));
+ memset(&wlCtx_Panel, 0x00, sizeof(wlCtx_Panel));
+ memset(&wlCtx_Button_1, 0x00, sizeof(wlCtx_Button_1));
+ memset(&wlCtx_Button_2, 0x00, sizeof(wlCtx_Button_2));
+ memset(&wlCtx_Button_3, 0x00, sizeof(wlCtx_Button_3));
+ memset(&wlCtx_Button_4, 0x00, sizeof(wlCtx_Button_4));
+ memset(&wlCtx_HomeButton, 0x00, sizeof(wlCtx_HomeButton));
+ memset(&wlCtx_WorkSpaceBackGround, 0x00, sizeof(wlCtx_WorkSpaceBackGround));
+ wl_list_init(&launcher_wlCtxList);
+ wlCtxCommon.list_wlContextStruct = MEM_ALLOC(sizeof(struct wl_list));
+ assert(wlCtxCommon.list_wlContextStruct);
+ wl_list_init(wlCtxCommon.list_wlContextStruct);
+
+ struct hmi_homescreen_setting *hmi_setting = hmi_homescreen_setting_create();
+ wlCtxCommon.hmi_setting = hmi_setting;
+
+ gRun = 1;
+
+ wlCtxCommon.wlDisplay = wl_display_connect(NULL);
+ if (NULL == wlCtxCommon.wlDisplay) {
+ printf("Error: wl_display_connect failed.\n");
+ return -1;
+ }
+
+ /* get wl_registry */
+ wlCtxCommon.wlRegistry = wl_display_get_registry(wlCtxCommon.wlDisplay);
+ wl_registry_add_listener(wlCtxCommon.wlRegistry,
+ &registry_listener, &wlCtxCommon);
+ wl_display_dispatch(wlCtxCommon.wlDisplay);
+ wl_display_roundtrip(wlCtxCommon.wlDisplay);
+
+ if (wlCtxCommon.hmi_setting->cursor_theme) {
+ create_cursors(&wlCtxCommon);
+
+ wlCtxCommon.pointer_surface =
+ wl_compositor_create_surface(wlCtxCommon.wlCompositor);
+
+ wlCtxCommon.current_cursor = CURSOR_LEFT_PTR;
+ }
+
+ wlCtx_BackGround.cmm = wlCtxCommon;
+ wlCtx_Panel.cmm = wlCtxCommon;
+ wlCtx_Button_1.cmm = wlCtxCommon;
+ wlCtx_Button_2.cmm = wlCtxCommon;
+ wlCtx_Button_3.cmm = wlCtxCommon;
+ wlCtx_Button_4.cmm = wlCtxCommon;
+ wlCtx_HomeButton.cmm = wlCtxCommon;
+ wlCtx_WorkSpaceBackGround.cmm = wlCtxCommon;
+
+ /* create desktop widgets */
+ create_background(&wlCtx_BackGround, hmi_setting->background.id,
+ hmi_setting->background.filePath);
+
+ create_panel(&wlCtx_Panel, hmi_setting->panel.id,
+ hmi_setting->panel.filePath);
+
+ create_button(&wlCtx_Button_1, hmi_setting->tiling.id,
+ hmi_setting->tiling.filePath, 0);
+
+ create_button(&wlCtx_Button_2, hmi_setting->sidebyside.id,
+ hmi_setting->sidebyside.filePath, 1);
+
+ create_button(&wlCtx_Button_3, hmi_setting->fullscreen.id,
+ hmi_setting->fullscreen.filePath, 2);
+
+ create_button(&wlCtx_Button_4, hmi_setting->random.id,
+ hmi_setting->random.filePath, 3);
+
+ create_workspace_background(&wlCtx_WorkSpaceBackGround,
+ &hmi_setting->workspace_background);
+
+ create_launchers(&wlCtxCommon, &hmi_setting->launcher_list);
+
+ create_home_button(&wlCtx_HomeButton, hmi_setting->home.id,
+ hmi_setting->home.filePath);
+
+ UI_ready(wlCtxCommon.hmiCtrl);
+
+ /* signal handling */
+ signal(SIGINT, sigFunc);
+ signal(SIGKILL, sigFunc);
+
+ while(gRun) {
+ wl_display_dispatch(wlCtxCommon.wlDisplay);
+ }
+
+ struct wlContextStruct* pWlCtxSt = NULL;
+ wl_list_for_each(pWlCtxSt, wlCtxCommon.list_wlContextStruct, link) {
+ destroyWLContextStruct(pWlCtxSt);
+ }
+
+ destroyWLContextCommon(&wlCtxCommon);
+ free(wlCtxCommon.list_wlContextStruct);
+
+ return 0;
+}
diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
index 4e4e7c0..86db700 100644
--- a/ivi-shell/hmi-controller.c
+++ b/ivi-shell/hmi-controller.c
@@ -134,6 +134,7 @@ hmi_server_setting {
uint32_t workspace_background_layer_id;
uint32_t workspace_layer_id;
uint32_t panel_height;
+ char *ivi_homescreen;
};

struct hmi_controller
@@ -151,6 +152,10 @@ struct hmi_controller
int32_t workspace_count;
struct wl_array ui_widgets;
int32_t is_initialized;
+
+ struct weston_compositor *compositor;
+ struct weston_process process;
+ struct wl_listener destroy_listener;
};

struct launcher_info
@@ -830,6 +835,9 @@ hmi_server_setting_create(void)

setting->panel_height = 70;

+ weston_config_section_get_string(
+ shellSection, "ivi-shell-user-interface", &setting->ivi_homescreen, NULL);
+
weston_config_destroy(config);

return setting;
@@ -1896,9 +1904,36 @@ bind_hmi_controller(struct wl_client *client,
}

static void
-launch_hmi_client(void *data)
+handle_hmi_client_process_sigchld(struct weston_process *proc, int status)
+{
+ proc->pid = 0;
+}
+
+static void
+hmi_client_destroy(struct wl_listener *listener, void *data)
+{
+ struct hmi_controller *hmi_ctrl =
+ container_of(listener, struct hmi_controller, destroy_listener);
+
+ kill(hmi_ctrl->process.pid, SIGTERM);
+ hmi_ctrl->process.pid = 0;
+}
+
+static void
+launch_hmi_client_process(void *data)
{
- /*Nothing to do here*/
+ struct hmi_controller *hmi_ctrl =
+ (struct hmi_controller *)data;
+
+ weston_client_launch(hmi_ctrl->compositor,
+ &hmi_ctrl->process,
+ hmi_ctrl->hmi_setting->ivi_homescreen,
+ handle_hmi_client_process_sigchld);
+
+ hmi_ctrl->destroy_listener.notify = hmi_client_destroy;
+ wl_signal_add(&hmi_ctrl->compositor->destroy_signal, &hmi_ctrl->destroy_listener);
+
+ free(hmi_ctrl->hmi_setting->ivi_homescreen);
}

/*****************************************************************************
@@ -1910,6 +1945,7 @@ module_init(struct weston_compositor *ec,
int *argc, char *argv[])
{
struct hmi_controller *hmi_ctrl = hmi_controller_create(ec);
+ hmi_ctrl->compositor = ec;

if (wl_global_create(ec->wl_display,
&ivi_hmi_controller_interface, 1,
@@ -1918,7 +1954,7 @@ module_init(struct weston_compositor *ec,
}

struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
- wl_event_loop_add_idle(loop, launch_hmi_client, ec);
+ wl_event_loop_add_idle(loop, launch_hmi_client_process, hmi_ctrl);

return 0;
}
--
1.8.3.1
Manuel Bachmann
2014-06-25 09:41:47 UTC
Permalink
Hello Tanibata-San,

I am currently testing your patches against the latest Weston 1.5 release.

For this particular patch, I had to modify this section in order to compile
:

nodist_weston_ivi_shell_user_interface_SOURCES = \
protocol/ivi-hmi-controller-client-protocol.h \
protocol/ivi-hmi-controller-protocol.c \
protocol/ivi-application-protocol.c

Notice the "protocol/ivi-application-protocol.c" line at the end. WIthout
it, the build process failed when linking the binary.



2014-05-20 6:30 GMT+02:00 Nobuhiko Tanibata <
NOBUHIKO_TANIBATA at xddp.denso.co.jp>:

> This is launched from hmi-controller by launch_hmi_client_process and
> invoke a
> client process.
>
> The basic flow is as followed,
> 1/ process invoked
> 2/ read configuration from weston.ini.
> 3/ draw png file to surface according to configuration of weston.ini
> 4/ all parts of UI are ready. request "UI_ready" to draw UI.
> 5/ Enter event loop
> 6/ If a surface receives touch/pointer event, followings are invoked
> according
> to type of event and surface
> 6-1/ If a surface to launch ivi_application receive touch up, it execs
> ivi-application configured in weston.ini.
> 6-2/ If a surface to switch layout mode receive touch up, it sends a
> request,
> ivi_hmi_controller_switch_mode, to hmi-controller.
> 6-3/ If a surface to show workspace having launchers, it sends a request,
> ivi_hmi_controller_home, to hmi-controller.
> 6-4/ If touch down events happens in workspace,
> ivi_hmi_controller_workspace_control is sent to slide workspace.
> When control finished, event: ivi_hmi_controller_workspace_end_control
> is received.
>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - squash Makefile to this patch
>
> Changes for v3 and v4
> - nothing. Version number aligned to the first patch
>
> Changes for v5:
> - rebase weston v1.5 branch
> - apply review comments from mailing list
>
> Makefile.am | 10 +-
> clients/ivi-shell-user-interface.c | 1332
> ++++++++++++++++++++++++++++++++++++
> ivi-shell/hmi-controller.c | 42 +-
> 3 files changed, 1380 insertions(+), 4 deletions(-)
> create mode 100644 clients/ivi-shell-user-interface.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 1f75cc3..46c5e3d 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -359,7 +359,8 @@ libexec_PROGRAMS += \
> weston-desktop-shell \
> weston-screenshooter \
> weston-keyboard \
> - weston-simple-im
> + weston-simple-im \
> + weston-ivi-shell-user-interface
>
> demo_clients = \
> weston-flower \
> @@ -570,6 +571,13 @@ nodist_weston_desktop_shell_SOURCES =
> \
> weston_desktop_shell_LDADD = libtoytoolkit.la
> weston_desktop_shell_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
>
> +weston_ivi_shell_user_interface_SOURCES =
> clients/ivi-shell-user-interface.c
> +nodist_weston_ivi_shell_user_interface_SOURCES = \
> + protocol/ivi-hmi-controller-client-protocol.h \
> + protocol/ivi-hmi-controller-protocol.c
> +weston_ivi_shell_user_interface_LDADD = libtoytoolkit.la
> +weston_ivi_shell_user_interface_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
> +
> if BUILD_FULL_GL_CLIENTS
> demo_clients += weston-gears
> weston_gears_SOURCES = clients/gears.c
> diff --git a/clients/ivi-shell-user-interface.c
> b/clients/ivi-shell-user-interface.c
> new file mode 100644
> index 0000000..70b854b
> --- /dev/null
> +++ b/clients/ivi-shell-user-interface.c
> @@ -0,0 +1,1332 @@
> +/*
> + * Copyright (C) 2013 DENSO CORPORATION
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee,
> provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used
> in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission. The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose. It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/wait.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <linux/input.h>
> +#include <assert.h>
> +#include <fcntl.h>
> +#include <signal.h>
> +#include <sys/mman.h>
> +#include <getopt.h>
> +#include <pthread.h>
> +#include <wayland-cursor.h>
> +#include "../shared/cairo-util.h"
> +#include "../shared/config-parser.h"
> +#include "ivi-application-client-protocol.h"
> +#include "ivi-hmi-controller-client-protocol.h"
> +
> +/**
> + * A reference implementation how to use ivi-hmi-controller interface to
> interact
> + * with hmi-controller. This is launched from hmi-controller by using
> + * hmi_client_start and create a pthread.
> + *
> + * The basic flow is as followed,
> + * 1/ create pthread
> + * 2/ read configuration from weston.ini.
> + * 3/ draw png file to surface according to configuration of weston.ini
> + * 4/ set up UI by using ivi-hmi-controller protocol
> + * 5/ Enter event loop
> + * 6/ If a surface receives touch/pointer event, followings are invoked
> according
> + * to type of event and surface
> + * 6-1/ If a surface to launch ivi_application receive touch up, it execs
> + * ivi-application configured in weston.ini.
> + * 6-2/ If a surface to switch layout mode receive touch up, it sends a
> request,
> + * ivi_hmi_controller_switch_mode, to hmi-controller.
> + * 6-3/ If a surface to show workspace having launchers, it sends a
> request,
> + * ivi_hmi_controller_home, to hmi-controller.
> + * 6-4/ If touch down events happens in workspace,
> + * ivi_hmi_controller_workspace_control is sent to slide workspace.
> + * When control finished, event:
> ivi_hmi_controller_workspace_end_control
> + * is received.
> + */
> +
>
> +/*****************************************************************************
> + * structure, globals
> +
> ****************************************************************************/
> +enum cursor_type {
> + CURSOR_BOTTOM_LEFT,
> + CURSOR_BOTTOM_RIGHT,
> + CURSOR_BOTTOM,
> + CURSOR_DRAGGING,
> + CURSOR_LEFT_PTR,
> + CURSOR_LEFT,
> + CURSOR_RIGHT,
> + CURSOR_TOP_LEFT,
> + CURSOR_TOP_RIGHT,
> + CURSOR_TOP,
> + CURSOR_IBEAM,
> + CURSOR_HAND1,
> + CURSOR_WATCH,
> +
> + CURSOR_BLANK
> +};
> +struct wlContextCommon {
> + struct wl_display *wlDisplay;
> + struct wl_registry *wlRegistry;
> + struct wl_compositor *wlCompositor;
> + struct wl_shm *wlShm;
> + struct wl_seat *wlSeat;
> + struct wl_pointer *wlPointer;
> + struct wl_touch *wlTouch;
> + struct ivi_application *iviApplication;
> + struct ivi_hmi_controller *hmiCtrl;
> + struct hmi_homescreen_setting *hmi_setting;
> + struct wl_list *list_wlContextStruct;
> + struct wl_surface *enterSurface;
> + int32_t is_home_on;
> + struct wl_cursor_theme *cursor_theme;
> + struct wl_cursor **cursors;
> + struct wl_surface *pointer_surface;
> + enum cursor_type current_cursor;
> + uint32_t enter_serial;
> +};
> +
> +struct wlContextStruct {
> + struct wlContextCommon cmm;
> + struct wl_surface *wlSurface;
> + struct wl_buffer *wlBuffer;
> + uint32_t formats;
> + cairo_surface_t *ctx_image;
> + void *data;
> + uint32_t id_surface;
> + struct wl_list link;
> +};
> +
> +struct
> +hmi_homescreen_srf {
> + uint32_t id;
> + char *filePath;
> + uint32_t color;
> +};
> +
> +struct
> +hmi_homescreen_workspace {
> + struct wl_array launcher_id_array;
> + struct wl_list link;
> +};
> +
> +struct
> +hmi_homescreen_launcher {
> + uint32_t icon_surface_id;
> + uint32_t workspace_id;
> + char* icon;
> + char* path;
> + struct wl_list link;
> +};
> +
> +struct
> +hmi_homescreen_setting {
> + struct hmi_homescreen_srf background;
> + struct hmi_homescreen_srf panel;
> + struct hmi_homescreen_srf tiling;
> + struct hmi_homescreen_srf sidebyside;
> + struct hmi_homescreen_srf fullscreen;
> + struct hmi_homescreen_srf random;
> + struct hmi_homescreen_srf home;
> + struct hmi_homescreen_srf workspace_background;
> +
> + struct wl_list workspace_list;
> + struct wl_list launcher_list;
> +
> + char *cursor_theme;
> + int32_t cursor_size;
> +};
> +
> +volatile int gRun = 0;
> +
> +static void *
> +fail_on_null(void *p, size_t size, char* file, int32_t line)
> +{
> + if (size && !p) {
> + fprintf(stderr, "%s(%d) %zd: out of memory\n", file, line, size);
> + exit(EXIT_FAILURE);
> + }
> +
> + return p;
> +}
> +
> +static void *
> +mem_alloc(size_t size, char* file, int32_t line)
> +{
> + return fail_on_null(calloc(1, size), size, file, line);
> +}
> +
> +#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
> +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
> +
>
> +/*****************************************************************************
> + * Event Handler
> +
> ****************************************************************************/
> +
> +static void
> +shm_format(void* data, struct wl_shm* pWlShm, uint32_t format)
> +{
> + struct wlContextStruct* pDsp = data;
> + pDsp->formats |= (1 << format);
> +}
> +
> +static struct wl_shm_listener shm_listenter = {
> + shm_format
> +};
> +
> +static int32_t
> +getIdOfWlSurface(struct wlContextCommon *pCtx, struct wl_surface
> *wlSurface)
> +{
> + if (NULL == pCtx ||
> + NULL == wlSurface ) {
> + return 0;
> + }
> +
> + struct wlContextStruct* pWlCtxSt = NULL;
> + wl_list_for_each(pWlCtxSt, pCtx->list_wlContextStruct, link) {
> + if (pWlCtxSt->wlSurface == wlSurface) {
> + return pWlCtxSt->id_surface;
> + }
> + continue;
> + }
> + return -1;
> +}
> +
> +static void
> +set_pointer_image(struct wlContextCommon *pCtx, uint32_t index)
> +{
> + if (!pCtx->wlPointer ||
> + !pCtx->cursors) {
> + return;
> + }
> +
> + if (CURSOR_BLANK == pCtx->current_cursor) {
> + wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
> + NULL, 0, 0);
> + return;
> + }
> +
> + struct wl_cursor *cursor = pCtx->cursors[pCtx->current_cursor];
> + if (!cursor) {
> + return;
> + }
> +
> + if (cursor->image_count <= index) {
> + fprintf(stderr, "cursor index out of range\n");
> + return;
> + }
> +
> + struct wl_cursor_image *image = cursor->images[index];
> + struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
> +
> + if (!buffer) {
> + return;
> + }
> +
> + wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
> + pCtx->pointer_surface,
> + image->hotspot_x, image->hotspot_y);
> +
> + wl_surface_attach(pCtx->pointer_surface, buffer, 0, 0);
> +
> + wl_surface_damage(pCtx->pointer_surface, 0, 0,
> + image->width, image->height);
> +
> + wl_surface_commit(pCtx->pointer_surface);
> +}
> +
> +static void
> +PointerHandleEnter(void* data, struct wl_pointer* wlPointer, uint32_t
> serial,
> + struct wl_surface* wlSurface, wl_fixed_t sx,
> wl_fixed_t sy)
> +{
> + (void)wlPointer;
> + (void)serial;
> +
> + struct wlContextCommon *pCtx = data;
> + pCtx->enter_serial = serial;
> + pCtx->enterSurface = wlSurface;
> + set_pointer_image(pCtx, 0);
> +#ifdef _DEBUG
> + printf("ENTER PointerHandleEnter: x(%d), y(%d)\n", sx, sy);
> +#endif
> +}
> +
> +static void
> +PointerHandleLeave(void* data, struct wl_pointer* wlPointer, uint32_t
> serial,
> + struct wl_surface* wlSurface)
> +{
> + (void)wlPointer;
> + (void)wlSurface;
> +
> + struct wlContextCommon *pCtx = data;
> + pCtx->enterSurface = NULL;
> +
> +#ifdef _DEBUG
> + printf("ENTER PointerHandleLeave: serial(%d)\n", serial);
> +#endif
> +}
> +
> +static void
> +PointerHandleMotion(void* data, struct wl_pointer* wlPointer, uint32_t
> time,
> + wl_fixed_t sx, wl_fixed_t sy)
> +{
> + (void)data;
> + (void)wlPointer;
> + (void)time;
> +
> +#ifdef _DEBUG
> + printf("ENTER PointerHandleMotion: x(%d), y(%d)\n", gPointerX,
> gPointerY);
> +#endif
> +}
> +
> +/**
> + * if a surface assigned as launcher receives touch-off event, invoking
> + * ivi-application which configured in weston.ini with path to binary.
> + */
> +extern char **environ; /*defied by libc */
> +
> +static pid_t execute_process(char* path, char *argv[])
> +{
> + pid_t pid = fork();
> + if (pid < 0) {
> + fprintf(stderr, "Failed to fork\n");
> + }
> +
> + if (pid) {
> + return pid;
> + }
> +
> + if (-1 == execve(path, argv, environ)) {
> + fprintf(stderr, "Failed to execve %s\n", path);
> + exit(1);
> + }
> +
> + return pid;
> +}
> +
> +static int32_t
> +launcher_button(uint32_t surfaceId, struct wl_list *launcher_list)
> +{
> + struct hmi_homescreen_launcher *launcher = NULL;
> +
> + wl_list_for_each(launcher, launcher_list, link) {
> + if (surfaceId != launcher->icon_surface_id) {
> + continue;
> + }
> +
> + char *argv[] = {NULL};
> + execute_process(launcher->path, argv);
> +
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * is-method to identify a surface set as launcher in workspace or
> workspace
> + * itself. This is-method is used to decide whether request;
> + * ivi_hmi_controller_workspace_control is sent or not.
> + */
> +static int32_t
> +isWorkspaceSurface(uint32_t id, struct hmi_homescreen_setting
> *hmi_setting)
> +{
> + if (id == hmi_setting->workspace_background.id) {
> + return 1;
> + }
> +
> + struct hmi_homescreen_launcher *launcher = NULL;
> + wl_list_for_each(launcher, &hmi_setting->launcher_list, link) {
> + if (id == launcher->icon_surface_id) {
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * Decide which request is sent to hmi-controller
> + */
> +static void
> +touch_up(struct ivi_hmi_controller *hmi_ctrl, uint32_t id_surface,
> + int32_t *is_home_on, struct hmi_homescreen_setting* hmi_setting)
> +{
> + if (launcher_button(id_surface, &hmi_setting->launcher_list)) {
> + *is_home_on = 0;
> + ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
> + } else if (id_surface == hmi_setting->tiling.id) {
> + ivi_hmi_controller_switch_mode(
> + hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING);
> + } else if (id_surface == hmi_setting->sidebyside.id) {
> + ivi_hmi_controller_switch_mode(
> + hmi_ctrl,
> IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE);
> + } else if (id_surface == hmi_setting->fullscreen.id) {
> + ivi_hmi_controller_switch_mode(
> + hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN);
> + } else if (id_surface == hmi_setting->random.id) {
> + ivi_hmi_controller_switch_mode(
> + hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM);
> + } else if (id_surface == hmi_setting->home.id) {
> + *is_home_on = !(*is_home_on);
> + if (*is_home_on) {
> + ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_ON);
> + } else {
> + ivi_hmi_controller_home(hmi_ctrl,
> IVI_HMI_CONTROLLER_HOME_OFF);
> + }
> + }
> +}
> +
> +/**
> + * Even handler of Pointer event. IVI system is usually manipulated by
> touch
> + * screen. However, some systems also have pointer device.
> + * Release is the same behavior as touch off
> + * Pressed is the same behavior as touch on
> + */
> +static void
> +PointerHandleButton(void* data, struct wl_pointer* wlPointer, uint32_t
> serial,
> + uint32_t time, uint32_t button, uint32_t state)
> +{
> + (void)wlPointer;
> + (void)serial;
> + (void)time;
> + struct wlContextCommon *pCtx = data;
> + struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
> +
> + if (BTN_RIGHT == button) {
> + return;
> + }
> +
> + const uint32_t id_surface = getIdOfWlSurface(pCtx,
> pCtx->enterSurface);
> +
> + switch (state) {
> + case WL_POINTER_BUTTON_STATE_RELEASED:
> + touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on,
> pCtx->hmi_setting);
> + break;
> +
> + case WL_POINTER_BUTTON_STATE_PRESSED:
> +
> + if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
> + ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat,
> serial);
> + }
> +
> + break;
> + }
> +#ifdef _DEBUG
> + printf("ENTER PointerHandleButton: button(%d), state(%d)\n", button,
> state);
> +#endif
> +}
> +
> +static void
> +PointerHandleAxis(void* data, struct wl_pointer* wlPointer, uint32_t time,
> + uint32_t axis, wl_fixed_t value)
> +{
> + (void)data;
> + (void)wlPointer;
> + (void)time;
> +#ifdef _DEBUG
> + printf("ENTER PointerHandleAxis: axis(%d), value(%d)\n", axis, value);
> +#endif
> +}
> +
> +static struct wl_pointer_listener pointer_listener = {
> + PointerHandleEnter,
> + PointerHandleLeave,
> + PointerHandleMotion,
> + PointerHandleButton,
> + PointerHandleAxis
> +};
> +
> +/**
> + * Even handler of touch event
> + */
> +static void
> +TouchHandleDown(void *data, struct wl_touch *wlTouch, uint32_t serial,
> uint32_t time,
> + struct wl_surface *surface, int32_t id, wl_fixed_t x_w,
> wl_fixed_t y_w)
> +{
> + struct wlContextCommon *pCtx = data;
> + struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
> +
> + if (0 == id){
> + pCtx->enterSurface = surface;
> + }
> +
> + const uint32_t id_surface = getIdOfWlSurface(pCtx,
> pCtx->enterSurface);
> +
> + /**
> + * When touch down happens on surfaces of workspace, ask
> hmi-controller to start
> + * control workspace to select page of workspace.
> + * After sending seat to hmi-controller by
> ivi_hmi_controller_workspace_control,
> + * hmi-controller-homescreen doesn't receive any event till
> hmi-controller sends
> + * back it.
> + */
> + if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
> + ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat,
> serial);
> + }
> +}
> +
> +static void
> +TouchHandleUp(void *data, struct wl_touch *wlTouch, uint32_t serial,
> uint32_t time,
> + int32_t id)
> +{
> + (void)serial;
> + (void)time;
> + struct wlContextCommon *pCtx = data;
> + struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
> +
> + const uint32_t id_surface = getIdOfWlSurface(pCtx,
> pCtx->enterSurface);
> +
> + /**
> + * triggering event according to touch-up happening on which surface.
> + */
> + if (id == 0){
> + touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on,
> pCtx->hmi_setting);
> + }
> +}
> +
> +static void
> +TouchHandleMotion(void *data, struct wl_touch *wlTouch, uint32_t time,
> + int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
> +{
> +}
> +
> +static void
> +TouchHandleFrame(void *data, struct wl_touch *wlTouch)
> +{
> +}
> +
> +static void
> +TouchHandleCancel(void *data, struct wl_touch *wlTouch)
> +{
> +}
> +
> +static struct wl_touch_listener touch_listener = {
> + TouchHandleDown,
> + TouchHandleUp,
> + TouchHandleMotion,
> + TouchHandleFrame,
> + TouchHandleCancel,
> +};
> +
> +/**
> + * Handler of capabilities
> + */
> +static void
> +seat_handle_capabilities(void* data, struct wl_seat* seat, uint32_t caps)
> +{
> + (void)seat;
> + struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
> + struct wl_seat* wlSeat = p_wlCtx->wlSeat;
> + struct wl_pointer* wlPointer = p_wlCtx->wlPointer;
> + struct wl_touch* wlTouch = p_wlCtx->wlTouch;
> +
> + if (p_wlCtx->hmi_setting->cursor_theme) {
> + if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wlPointer){
> + wlPointer = wl_seat_get_pointer(wlSeat);
> + wl_pointer_set_user_data(wlPointer, data);
> + wl_pointer_add_listener(wlPointer, &pointer_listener, data);
> + } else
> + if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wlPointer){
> + wl_pointer_destroy(wlPointer);
> + wlPointer = NULL;
> + }
> + p_wlCtx->wlPointer = wlPointer;
> + }
> +
> + if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wlTouch){
> + wlTouch = wl_seat_get_touch(wlSeat);
> + wl_touch_set_user_data(wlTouch, data);
> + wl_touch_add_listener(wlTouch, &touch_listener, data);
> + } else
> + if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wlTouch){
> + wl_touch_destroy(wlTouch);
> + wlTouch = NULL;
> + }
> + p_wlCtx->wlTouch = wlTouch;
> +}
> +
> +static struct wl_seat_listener seat_Listener = {
> + seat_handle_capabilities,
> +};
> +
> +/**
> + * Registration of event
> + * This event is received when hmi-controller server finished controlling
> + * workspace.
> + */
> +static void
> +ivi_hmi_controller_workspace_end_control(void *data,
> + struct ivi_hmi_controller *hmi_ctrl,
> + int32_t is_controlled)
> +{
> + if (is_controlled) {
> + return;
> + }
> +
> + struct wlContextCommon *pCtx = data;
> + const uint32_t id_surface = getIdOfWlSurface(pCtx,
> pCtx->enterSurface);
> +
> + /**
> + * During being controlled by hmi-controller, any input event is not
> + * notified. So when control ends with touch up, it invokes launcher
> + * if up event happens on a launcher surface.
> + *
> + */
> + if (launcher_button(id_surface, &pCtx->hmi_setting->launcher_list)) {
> + pCtx->is_home_on = 0;
> + ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
> + }
> +}
> +
> +static const struct ivi_hmi_controller_listener hmi_controller_listener =
> {
> + ivi_hmi_controller_workspace_end_control
> +};
> +
> +/**
> + * Registration of interfaces
> + */
> +static void
> +registry_handle_global(void* data, struct wl_registry* registry, uint32_t
> name,
> + const char *interface, uint32_t version)
> +{
> + (void)version;
> + struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
> +
> + do {
> + if (!strcmp(interface, "wl_compositor")) {
> + p_wlCtx->wlCompositor = wl_registry_bind(registry, name,
> &wl_compositor_interface, 1);
> + break;
> + }
> + if (!strcmp(interface, "wl_shm")) {
> + p_wlCtx->wlShm = wl_registry_bind(registry, name,
> &wl_shm_interface, 1);
> + wl_shm_add_listener(p_wlCtx->wlShm, &shm_listenter, p_wlCtx);
> + break;
> + }
> + if (!strcmp(interface, "wl_seat")) {
> + p_wlCtx->wlSeat = wl_registry_bind(registry, name,
> &wl_seat_interface, 1);
> + wl_seat_add_listener(p_wlCtx->wlSeat, &seat_Listener, data);
> + break;
> + }
> + if (!strcmp(interface, "ivi_application")) {
> + p_wlCtx->iviApplication = wl_registry_bind(registry, name,
> &ivi_application_interface, 1);
> + break;
> + }
> + if (!strcmp(interface, "ivi_hmi_controller")) {
> + p_wlCtx->hmiCtrl = wl_registry_bind(registry, name,
> &ivi_hmi_controller_interface, 1);
> +
> + if (p_wlCtx->hmiCtrl) {
> + ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl,
> &hmi_controller_listener, p_wlCtx);
> + }
> + break;
> + }
> +
> + } while(0);
> +}
> +
> +static const struct wl_registry_listener registry_listener = {
> + registry_handle_global,
> + NULL
> +};
> +
> +static void
> +frame_listener_func(void *data, struct wl_callback *callback, uint32_t
> time)
> +{
> + if (callback) {
> + wl_callback_destroy(callback);
> + }
> +}
> +
> +static const struct wl_callback_listener frame_listener = {
> + frame_listener_func
> +};
> +
> +/*
> + * The following correspondences between file names and cursors was copied
> + * from: https://bugs.kde.org/attachment.cgi?id=67313
> + */
> +static const char *bottom_left_corners[] = {
> + "bottom_left_corner",
> + "sw-resize",
> + "size_bdiag"
> +};
> +
> +static const char *bottom_right_corners[] = {
> + "bottom_right_corner",
> + "se-resize",
> + "size_fdiag"
> +};
> +
> +static const char *bottom_sides[] = {
> + "bottom_side",
> + "s-resize",
> + "size_ver"
> +};
> +
> +static const char *grabbings[] = {
> + "grabbing",
> + "closedhand",
> + "208530c400c041818281048008011002"
> +};
> +
> +static const char *left_ptrs[] = {
> + "left_ptr",
> + "default",
> + "top_left_arrow",
> + "left-arrow"
> +};
> +
> +static const char *left_sides[] = {
> + "left_side",
> + "w-resize",
> + "size_hor"
> +};
> +
> +static const char *right_sides[] = {
> + "right_side",
> + "e-resize",
> + "size_hor"
> +};
> +
> +static const char *top_left_corners[] = {
> + "top_left_corner",
> + "nw-resize",
> + "size_fdiag"
> +};
> +
> +static const char *top_right_corners[] = {
> + "top_right_corner",
> + "ne-resize",
> + "size_bdiag"
> +};
> +
> +static const char *top_sides[] = {
> + "top_side",
> + "n-resize",
> + "size_ver"
> +};
> +
> +static const char *xterms[] = {
> + "xterm",
> + "ibeam",
> + "text"
> +};
> +
> +static const char *hand1s[] = {
> + "hand1",
> + "pointer",
> + "pointing_hand",
> + "e29285e634086352946a0e7090d73106"
> +};
> +
> +static const char *watches[] = {
> + "watch",
> + "wait",
> + "0426c94ea35c87780ff01dc239897213"
> +};
> +
> +struct cursor_alternatives {
> + const char **names;
> + size_t count;
> +};
> +
> +static const struct cursor_alternatives cursors[] = {
> + {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
> + {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
> + {bottom_sides, ARRAY_LENGTH(bottom_sides)},
> + {grabbings, ARRAY_LENGTH(grabbings)},
> + {left_ptrs, ARRAY_LENGTH(left_ptrs)},
> + {left_sides, ARRAY_LENGTH(left_sides)},
> + {right_sides, ARRAY_LENGTH(right_sides)},
> + {top_left_corners, ARRAY_LENGTH(top_left_corners)},
> + {top_right_corners, ARRAY_LENGTH(top_right_corners)},
> + {top_sides, ARRAY_LENGTH(top_sides)},
> + {xterms, ARRAY_LENGTH(xterms)},
> + {hand1s, ARRAY_LENGTH(hand1s)},
> + {watches, ARRAY_LENGTH(watches)},
> +};
> +
> +static void
> +create_cursors(struct wlContextCommon *cmm)
> +{
> + uint32_t i = 0;
> + uint32_t j = 0;
> + struct wl_cursor *cursor = NULL;
> + char* cursor_theme = cmm->hmi_setting->cursor_theme;
> + int32_t cursor_size = cmm->hmi_setting->cursor_size;
> +
> + cmm->cursor_theme = wl_cursor_theme_load(cursor_theme, cursor_size,
> cmm->wlShm);
> +
> + cmm->cursors = MEM_ALLOC(ARRAY_LENGTH(cursors) *
> sizeof(cmm->cursors[0]));
> +
> + for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
> + cursor = NULL;
> +
> + for (j = 0; !cursor && j < cursors[i].count; ++j) {
> + cursor = wl_cursor_theme_get_cursor(
> + cmm->cursor_theme, cursors[i].names[j]);
> + }
> +
> + if (!cursor) {
> + fprintf(stderr, "could not load cursor '%s'\n",
> + cursors[i].names[0]);
> + }
> +
> + cmm->cursors[i] = cursor;
> + }
> +}
> +
> +static void
> +destroy_cursors(struct wlContextCommon *cmm)
> +{
> + if (cmm->cursor_theme) {
> + wl_cursor_theme_destroy(cmm->cursor_theme);
> + }
> +
> + free(cmm->cursors);
> +}
> +
> +/**
> + * Internal method to prepare parts of UI
> + */
> +static void
> +createShmBuffer(struct wlContextStruct *p_wlCtx)
> +{
> + struct wl_shm_pool *pool;
> +
> + char filename[] = "/tmp/wayland-shm-XXXXXX";
> + int fd = -1;
> + int size = 0;
> + int width = 0;
> + int height = 0;
> + int stride = 0;
> +
> + fd = mkstemp(filename);
> + if (fd < 0) {
> + fprintf(stderr, "open %s failed: %m\n", filename);
> + return;
> + }
> +
> + width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
> + height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
> + stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
> +
> + size = stride * height;
> + if (ftruncate(fd, size) < 0) {
> + fprintf(stderr, "ftruncate failed: %m\n");
> + close(fd);
> + return;
> + }
> +
> + p_wlCtx->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
> fd, 0);
> +
> + if (MAP_FAILED == p_wlCtx->data) {
> + fprintf(stderr, "mmap failed: %m\n");
> + close(fd);
> + return;
> + }
> +
> + pool = wl_shm_create_pool(p_wlCtx->cmm.wlShm, fd, size);
> + p_wlCtx->wlBuffer = wl_shm_pool_create_buffer(pool, 0,
> + width,
> + height,
> + stride,
> + WL_SHM_FORMAT_ARGB8888);
> +
> + if (NULL == p_wlCtx->wlBuffer) {
> + fprintf(stderr, "wl_shm_create_buffer failed: %m\n");
> + close(fd);
> + return;
> + }
> + wl_shm_pool_destroy(pool);
> + close(fd);
> +
> + return;
> +}
> +
> +static void
> +destroyWLContextCommon(struct wlContextCommon *p_wlCtx)
> +{
> + destroy_cursors(p_wlCtx);
> +
> + if (p_wlCtx->pointer_surface) {
> + wl_surface_destroy(p_wlCtx->pointer_surface);
> + }
> +
> + if (p_wlCtx->wlCompositor) {
> + wl_compositor_destroy(p_wlCtx->wlCompositor);
> + }
> +}
> +
> +static void
> +destroyWLContextStruct(struct wlContextStruct *p_wlCtx)
> +{
> + if (p_wlCtx->wlSurface) {
> + wl_surface_destroy(p_wlCtx->wlSurface);
> + }
> +
> + if (p_wlCtx->ctx_image) {
> + cairo_surface_destroy(p_wlCtx->ctx_image);
> + p_wlCtx->ctx_image = NULL;
> + }
> +}
> +
> +static int
> +createWLContext(struct wlContextStruct *p_wlCtx)
> +{
> + wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
> +
> + p_wlCtx->wlSurface =
> wl_compositor_create_surface(p_wlCtx->cmm.wlCompositor);
> + if (NULL == p_wlCtx->wlSurface) {
> + printf("Error: wl_compositor_create_surface failed.\n");
> + destroyWLContextCommon(&p_wlCtx->cmm);
> + abort();
> + }
> +
> +
> + createShmBuffer(p_wlCtx);
> +
> + wl_display_flush(p_wlCtx->cmm.wlDisplay);
> + wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
> +
> + return 0;
> +}
> +
> +static void
> +drawImage(struct wlContextStruct *p_wlCtx)
> +{
> + struct wl_callback *callback;
> +
> + int width = 0;
> + int height = 0;
> + int stride = 0;
> + void *data = NULL;
> +
> + width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
> + height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
> + stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
> + data = cairo_image_surface_get_data(p_wlCtx->ctx_image);
> +
> + memcpy(p_wlCtx->data, data, stride * height);
> +
> + wl_surface_attach(p_wlCtx->wlSurface, p_wlCtx->wlBuffer, 0, 0);
> + wl_surface_damage(p_wlCtx->wlSurface, 0, 0, width, height);
> +
> + callback = wl_surface_frame(p_wlCtx->wlSurface);
> + wl_callback_add_listener(callback, &frame_listener, NULL);
> +
> + wl_surface_commit(p_wlCtx->wlSurface);
> +
> + wl_display_flush(p_wlCtx->cmm.wlDisplay);
> + wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
> +}
> +
> +static void
> +create_ivisurface(struct wlContextStruct *p_wlCtx,
> + uint32_t id_surface,
> + cairo_surface_t* surface)
> +{
> + struct ivi_surface *ivisurf = NULL;
> +
> + p_wlCtx->ctx_image = surface;
> +
> + p_wlCtx->id_surface = id_surface;
> + wl_list_init(&p_wlCtx->link);
> + wl_list_insert(p_wlCtx->cmm.list_wlContextStruct, &p_wlCtx->link);
> +
> + createWLContext(p_wlCtx);
> +
> + ivisurf = ivi_application_surface_create(p_wlCtx->cmm.iviApplication,
> + id_surface,
> p_wlCtx->wlSurface);
> + if (ivisurf == NULL) {
> + fprintf(stderr, "Failed to create ivi_client_surface\n");
> + return;
> + }
> +
> + drawImage(p_wlCtx);
> +
> + wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
> +}
> +
> +static void
> +create_ivisurfaceFromFile(struct wlContextStruct *p_wlCtx,
> + uint32_t id_surface,
> + const char* imageFile)
> +{
> + cairo_surface_t* surface = load_cairo_surface(imageFile);
> +
> + if (NULL == surface) {
> + fprintf(stderr, "Failed to load_cairo_surface %s\n", imageFile);
> + return;
> + }
> +
> + create_ivisurface(p_wlCtx, id_surface, surface);
> +}
> +
> +static void
> +set_hex_color(cairo_t *cr, uint32_t color)
> +{
> + cairo_set_source_rgba(cr,
> + ((color >> 16) & 0xff) / 255.0,
> + ((color >> 8) & 0xff) / 255.0,
> + ((color >> 0) & 0xff) / 255.0,
> + ((color >> 24) & 0xff) / 255.0);
> +}
> +
> +static void
> +create_ivisurfaceFromColor(struct wlContextStruct *p_wlCtx,
> + uint32_t id_surface,
> + uint32_t width, uint32_t height,
> + uint32_t color)
> +{
> + cairo_surface_t *surface = NULL;
> + cairo_t *cr = NULL;
> +
> + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width,
> height);
> +
> + cr = cairo_create(surface);
> + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
> + cairo_rectangle(cr, 0, 0, width, height);
> + set_hex_color(cr, color);
> + cairo_fill(cr);
> + cairo_destroy(cr);
> +
> + create_ivisurface(p_wlCtx, id_surface, surface);
> +}
> +
> +static void
> +UI_ready(struct ivi_hmi_controller *controller)
> +{
> + ivi_hmi_controller_UI_ready(controller);
> +}
> +
> +/**
> + * Internal method to set up UI by using ivi-hmi-controller
> + */
> +static void
> +create_background(struct wlContextStruct *p_wlCtx, const uint32_t
> id_surface,
> + const char* imageFile)
> +{
> + create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
> +}
> +
> +static void
> +create_panel(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
> + const char* imageFile)
> +{
> + create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
> +}
> +
> +static void
> +create_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
> + const char* imageFile, uint32_t number)
> +{
> + create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
> +}
> +
> +static void
> +create_home_button(struct wlContextStruct *p_wlCtx, const uint32_t
> id_surface,
> + const char* imageFile)
> +{
> + create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
> +}
> +
> +static void
> +create_workspace_background(
> + struct wlContextStruct *p_wlCtx, struct hmi_homescreen_srf *srf)
> +{
> + create_ivisurfaceFromColor(p_wlCtx, srf->id, 1, 1, srf->color);
> +}
> +
> +static void
> +create_launchers(struct wlContextCommon *cmm, struct wl_list
> *launcher_list)
> +{
> + int launcher_count = wl_list_length(launcher_list);
> +
> + if (0 == launcher_count) {
> + return;
> + }
> +
> + struct hmi_homescreen_launcher** launchers;
> + launchers = MEM_ALLOC(launcher_count * sizeof(*launchers));
> +
> + int ii = 0;
> + struct hmi_homescreen_launcher *launcher = NULL;
> +
> + wl_list_for_each(launcher, launcher_list, link) {
> + launchers[ii] = launcher;
> + ii++;
> + }
> +
> + int start = 0;
> +
> + for (ii = 0; ii < launcher_count; ii++) {
> +
> + if (ii != launcher_count -1 &&
> + launchers[ii]->workspace_id == launchers[ii +
> 1]->workspace_id) {
> + continue;
> + }
> +
> + int jj = 0;
> + for (jj = start; jj <= ii; jj++) {
> + struct wlContextStruct *p_wlCtx = MEM_ALLOC(sizeof(*p_wlCtx));
> + p_wlCtx->cmm = *cmm;
> +
> create_ivisurfaceFromFile(p_wlCtx,launchers[jj]->icon_surface_id,
> launchers[jj]->icon);
> + }
> +
> + start = ii + 1;
> + }
> +
> + free(launchers);
> +}
> +
> +static void sigFunc(int signum)
> +{
> + gRun = 0;
> +}
> +
> +/**
> + * Internal method to read out weston.ini to get configuration
> + */
> +static struct hmi_homescreen_setting*
> +hmi_homescreen_setting_create(void)
> +{
> + struct hmi_homescreen_setting* setting = MEM_ALLOC(sizeof(*setting));
> +
> + wl_list_init(&setting->workspace_list);
> + wl_list_init(&setting->launcher_list);
> +
> + struct weston_config *config = NULL;
> + config = weston_config_parse("weston.ini");
> +
> + struct weston_config_section *shellSection = NULL;
> + shellSection = weston_config_get_section(config, "ivi-shell", NULL,
> NULL);
> +
> + weston_config_section_get_string(
> + shellSection, "cursor-theme", &setting->cursor_theme, NULL);
> +
> + weston_config_section_get_int(shellSection, "cursor-size",
> &setting->cursor_size, 32);
> +
> + uint32_t workspace_layer_id;
> + weston_config_section_get_uint(
> + shellSection, "workspace-layer-id", &workspace_layer_id, 3000);
> +
> + weston_config_section_get_string(
> + shellSection, "background-image", &setting->background.filePath,
> + DATADIR "/weston/background.png");
> +
> + weston_config_section_get_uint(
> + shellSection, "background-id", &setting->background.id, 1001);
> +
> + weston_config_section_get_string(
> + shellSection, "panel-image", &setting->panel.filePath,
> + DATADIR "/weston/panel.png");
> +
> + weston_config_section_get_uint(
> + shellSection, "panel-id", &setting->panel.id, 1002);
> +
> + weston_config_section_get_string(
> + shellSection, "tiling-image", &setting->tiling.filePath,
> + DATADIR "/weston/tiling.png");
> +
> + weston_config_section_get_uint(
> + shellSection, "tiling-id", &setting->tiling.id, 1003);
> +
> + weston_config_section_get_string(
> + shellSection, "sidebyside-image", &setting->sidebyside.filePath,
> + DATADIR "/weston/sidebyside.png");
> +
> + weston_config_section_get_uint(
> + shellSection, "sidebyside-id", &setting->sidebyside.id, 1004);
> +
> + weston_config_section_get_string(
> + shellSection, "fullscreen-image", &setting->fullscreen.filePath,
> + DATADIR "/weston/fullscreen.png");
> +
> + weston_config_section_get_uint(
> + shellSection, "fullscreen-id", &setting->fullscreen.id, 1005);
> +
> + weston_config_section_get_string(
> + shellSection, "random-image", &setting->random.filePath,
> + DATADIR "/weston/random.png");
> +
> + weston_config_section_get_uint(
> + shellSection, "random-id", &setting->random.id, 1006);
> +
> + weston_config_section_get_string(
> + shellSection, "home-image", &setting->home.filePath,
> + DATADIR "/weston/home.png");
> +
> + weston_config_section_get_uint(
> + shellSection, "home-id", &setting->home.id, 1007);
> +
> + weston_config_section_get_uint(
> + shellSection, "workspace-background-color",
> + &setting->workspace_background.color, 0x99000000);
> +
> + weston_config_section_get_uint(
> + shellSection, "workspace-background-id",
> + &setting->workspace_background.id, 2001);
> +
> + struct weston_config_section *section = NULL;
> + const char *name = NULL;
> +
> + uint32_t icon_surface_id = workspace_layer_id + 1;
> +
> + while (weston_config_next_section(config, &section, &name)) {
> +
> + if (0 == strcmp(name, "ivi-launcher")) {
> +
> + struct hmi_homescreen_launcher *launcher = NULL;
> + launcher = MEM_ALLOC(sizeof(*launcher));
> + wl_list_init(&launcher->link);
> +
> + weston_config_section_get_string(section, "icon",
> &launcher->icon, NULL);
> + weston_config_section_get_string(section, "path",
> &launcher->path, NULL);
> + weston_config_section_get_uint(section, "workspace-id",
> &launcher->workspace_id, 0);
> + weston_config_section_get_uint(section, "icon-id",
> &launcher->icon_surface_id, icon_surface_id);
> + icon_surface_id++;
> +
> + wl_list_insert(setting->launcher_list.prev, &launcher->link);
> + }
> + }
> +
> + weston_config_destroy(config);
> + return setting;
> +}
> +
> +/**
> + * Main thread
> + *
> + * The basic flow are as followed,
> + * 1/ read configuration from weston.ini by hmi_homescreen_setting_create
> + * 2/ draw png file to surface according to configuration of weston.ini
> and
> + * set up UI by using ivi-hmi-controller protocol by each create_*
> method
> + */
> +int main(int argc, char **argv)
> +{
> + struct wlContextCommon wlCtxCommon;
> + struct wlContextStruct wlCtx_BackGround;
> + struct wlContextStruct wlCtx_Panel;
> + struct wlContextStruct wlCtx_Button_1;
> + struct wlContextStruct wlCtx_Button_2;
> + struct wlContextStruct wlCtx_Button_3;
> + struct wlContextStruct wlCtx_Button_4;
> + struct wlContextStruct wlCtx_HomeButton;
> + struct wlContextStruct wlCtx_WorkSpaceBackGround;
> + struct wl_list launcher_wlCtxList;
> +
> + memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon));
> + memset(&wlCtx_BackGround, 0x00, sizeof(wlCtx_BackGround));
> + memset(&wlCtx_Panel, 0x00, sizeof(wlCtx_Panel));
> + memset(&wlCtx_Button_1, 0x00, sizeof(wlCtx_Button_1));
> + memset(&wlCtx_Button_2, 0x00, sizeof(wlCtx_Button_2));
> + memset(&wlCtx_Button_3, 0x00, sizeof(wlCtx_Button_3));
> + memset(&wlCtx_Button_4, 0x00, sizeof(wlCtx_Button_4));
> + memset(&wlCtx_HomeButton, 0x00, sizeof(wlCtx_HomeButton));
> + memset(&wlCtx_WorkSpaceBackGround, 0x00,
> sizeof(wlCtx_WorkSpaceBackGround));
> + wl_list_init(&launcher_wlCtxList);
> + wlCtxCommon.list_wlContextStruct = MEM_ALLOC(sizeof(struct wl_list));
> + assert(wlCtxCommon.list_wlContextStruct);
> + wl_list_init(wlCtxCommon.list_wlContextStruct);
> +
> + struct hmi_homescreen_setting *hmi_setting =
> hmi_homescreen_setting_create();
> + wlCtxCommon.hmi_setting = hmi_setting;
> +
> + gRun = 1;
> +
> + wlCtxCommon.wlDisplay = wl_display_connect(NULL);
> + if (NULL == wlCtxCommon.wlDisplay) {
> + printf("Error: wl_display_connect failed.\n");
> + return -1;
> + }
> +
> + /* get wl_registry */
> + wlCtxCommon.wlRegistry =
> wl_display_get_registry(wlCtxCommon.wlDisplay);
> + wl_registry_add_listener(wlCtxCommon.wlRegistry,
> + &registry_listener, &wlCtxCommon);
> + wl_display_dispatch(wlCtxCommon.wlDisplay);
> + wl_display_roundtrip(wlCtxCommon.wlDisplay);
> +
> + if (wlCtxCommon.hmi_setting->cursor_theme) {
> + create_cursors(&wlCtxCommon);
> +
> + wlCtxCommon.pointer_surface =
> + wl_compositor_create_surface(wlCtxCommon.wlCompositor);
> +
> + wlCtxCommon.current_cursor = CURSOR_LEFT_PTR;
> + }
> +
> + wlCtx_BackGround.cmm = wlCtxCommon;
> + wlCtx_Panel.cmm = wlCtxCommon;
> + wlCtx_Button_1.cmm = wlCtxCommon;
> + wlCtx_Button_2.cmm = wlCtxCommon;
> + wlCtx_Button_3.cmm = wlCtxCommon;
> + wlCtx_Button_4.cmm = wlCtxCommon;
> + wlCtx_HomeButton.cmm = wlCtxCommon;
> + wlCtx_WorkSpaceBackGround.cmm = wlCtxCommon;
> +
> + /* create desktop widgets */
> + create_background(&wlCtx_BackGround, hmi_setting->background.id,
> + hmi_setting->background.filePath);
> +
> + create_panel(&wlCtx_Panel, hmi_setting->panel.id,
> + hmi_setting->panel.filePath);
> +
> + create_button(&wlCtx_Button_1, hmi_setting->tiling.id,
> + hmi_setting->tiling.filePath, 0);
> +
> + create_button(&wlCtx_Button_2, hmi_setting->sidebyside.id,
> + hmi_setting->sidebyside.filePath, 1);
> +
> + create_button(&wlCtx_Button_3, hmi_setting->fullscreen.id,
> + hmi_setting->fullscreen.filePath, 2);
> +
> + create_button(&wlCtx_Button_4, hmi_setting->random.id,
> + hmi_setting->random.filePath, 3);
> +
> + create_workspace_background(&wlCtx_WorkSpaceBackGround,
> + &hmi_setting->workspace_background);
> +
> + create_launchers(&wlCtxCommon, &hmi_setting->launcher_list);
> +
> + create_home_button(&wlCtx_HomeButton, hmi_setting->home.id,
> + hmi_setting->home.filePath);
> +
> + UI_ready(wlCtxCommon.hmiCtrl);
> +
> + /* signal handling */
> + signal(SIGINT, sigFunc);
> + signal(SIGKILL, sigFunc);
> +
> + while(gRun) {
> + wl_display_dispatch(wlCtxCommon.wlDisplay);
> + }
> +
> + struct wlContextStruct* pWlCtxSt = NULL;
> + wl_list_for_each(pWlCtxSt, wlCtxCommon.list_wlContextStruct, link) {
> + destroyWLContextStruct(pWlCtxSt);
> + }
> +
> + destroyWLContextCommon(&wlCtxCommon);
> + free(wlCtxCommon.list_wlContextStruct);
> +
> + return 0;
> +}
> diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
> index 4e4e7c0..86db700 100644
> --- a/ivi-shell/hmi-controller.c
> +++ b/ivi-shell/hmi-controller.c
> @@ -134,6 +134,7 @@ hmi_server_setting {
> uint32_t workspace_background_layer_id;
> uint32_t workspace_layer_id;
> uint32_t panel_height;
> + char *ivi_homescreen;
> };
>
> struct hmi_controller
> @@ -151,6 +152,10 @@ struct hmi_controller
> int32_t workspace_count;
> struct wl_array ui_widgets;
> int32_t is_initialized;
> +
> + struct weston_compositor *compositor;
> + struct weston_process process;
> + struct wl_listener destroy_listener;
> };
>
> struct launcher_info
> @@ -830,6 +835,9 @@ hmi_server_setting_create(void)
>
> setting->panel_height = 70;
>
> + weston_config_section_get_string(
> + shellSection, "ivi-shell-user-interface",
> &setting->ivi_homescreen, NULL);
> +
> weston_config_destroy(config);
>
> return setting;
> @@ -1896,9 +1904,36 @@ bind_hmi_controller(struct wl_client *client,
> }
>
> static void
> -launch_hmi_client(void *data)
> +handle_hmi_client_process_sigchld(struct weston_process *proc, int status)
> +{
> + proc->pid = 0;
> +}
> +
> +static void
> +hmi_client_destroy(struct wl_listener *listener, void *data)
> +{
> + struct hmi_controller *hmi_ctrl =
> + container_of(listener, struct hmi_controller, destroy_listener);
> +
> + kill(hmi_ctrl->process.pid, SIGTERM);
> + hmi_ctrl->process.pid = 0;
> +}
> +
> +static void
> +launch_hmi_client_process(void *data)
> {
> - /*Nothing to do here*/
> + struct hmi_controller *hmi_ctrl =
> + (struct hmi_controller *)data;
> +
> + weston_client_launch(hmi_ctrl->compositor,
> + &hmi_ctrl->process,
> + hmi_ctrl->hmi_setting->ivi_homescreen,
> + handle_hmi_client_process_sigchld);
> +
> + hmi_ctrl->destroy_listener.notify = hmi_client_destroy;
> + wl_signal_add(&hmi_ctrl->compositor->destroy_signal,
> &hmi_ctrl->destroy_listener);
> +
> + free(hmi_ctrl->hmi_setting->ivi_homescreen);
> }
>
>
> /*****************************************************************************
> @@ -1910,6 +1945,7 @@ module_init(struct weston_compositor *ec,
> int *argc, char *argv[])
> {
> struct hmi_controller *hmi_ctrl = hmi_controller_create(ec);
> + hmi_ctrl->compositor = ec;
>
> if (wl_global_create(ec->wl_display,
> &ivi_hmi_controller_interface, 1,
> @@ -1918,7 +1954,7 @@ module_init(struct weston_compositor *ec,
> }
>
> struct wl_event_loop *loop =
> wl_display_get_event_loop(ec->wl_display);
> - wl_event_loop_add_idle(loop, launch_hmi_client, ec);
> + wl_event_loop_add_idle(loop, launch_hmi_client_process, hmi_ctrl);
>
> return 0;
> }
> --
> 1.8.3.1
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>



--
Regards,



*Manuel BACHMANN Tizen Project VANNES-FR*
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20140625/9cd2f37f/attachment-0001.html>
Nobuhiko Tanibata
2014-06-25 11:36:41 UTC
Permalink
Hi Manuel,

Thank you!
I will resend my patches.

BR,
Nobuhiko

2014-06-25 18:41 ? Manuel Bachmann ????????:
> Hello Tanibata-San,
>
> I am currently testing your patches against the latest Weston 1.5
> release.
>
> For this particular patch, I had to modify this section in order to
> compile :
>
> nodist_weston_ivi_shell_user_interface_SOURCES
> =???????????????
> ???????
> protocol/ivi-hmi-controller-client-protocol.h??????????
> ???????
> protocol/ivi-hmi-controller-protocol.c?????????????????
>
> ??????? protocol/ivi-application-protocol.c
>
> Notice the "protocol/ivi-application-protocol.c" line at the end.
> WIthout it, the build process failed when linking the binary.
>
> 2014-05-20 6:30 GMT+02:00 Nobuhiko Tanibata
> <NOBUHIKO_TANIBATA at xddp.denso.co.jp>:
>
>> This is launched from hmi-controller by launch_hmi_client_process
>> and invoke a
>> client process.
>>
>> The basic flow is as followed,
>> 1/ process invoked
>> 2/ read configuration from weston.ini.
>> 3/ draw png file to surface according to configuration of
>> weston.ini
>> 4/ all parts of UI are ready. request "UI_ready" to draw UI.
>> 5/ Enter event loop
>> 6/ If a surface receives touch/pointer event, followings are
>> invoked according
>> ? ?to type of event and surface
>> 6-1/ If a surface to launch ivi_application receive touch up, it
>> execs
>> ? ? ?ivi-application configured in weston.ini.
>> 6-2/ If a surface to switch layout mode receive touch up, it sends
>> a request,
>> ? ? ?ivi_hmi_controller_switch_mode, to hmi-controller.
>> 6-3/ If a surface to show workspace having launchers, it sends a
>> request,
>> ? ? ?ivi_hmi_controller_home, to hmi-controller.
>> 6-4/ If touch down events happens in workspace,
>> ? ? ?ivi_hmi_controller_workspace_control is sent to slide
>> workspace.
>> ? ? ?When control finished, event:
>> ivi_hmi_controller_workspace_end_control
>> ? ? ?is received.
>>
>> Signed-off-by: Nobuhiko Tanibata
>> <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2:
>> ?- squash Makefile to this patch
>>
>> Changes for v3 and v4
>> ?- nothing. Version number aligned to the first patch
>>
>> Changes for v5:
>> ?- rebase weston v1.5 branch
>> ?- apply review comments from mailing list
>>
>> ?Makefile.am ? ? ? ? ? ? ? ? ? ? ? ?| ? 10 +-
>> ?clients/ivi-shell-user-interface.c | 1332
>> ++++++++++++++++++++++++++++++++++++
>> ?ivi-shell/hmi-controller.c ? ? ? ? | ? 42 +-
>> ?3 files changed, 1380 insertions(+), 4 deletions(-)
>> ?create mode 100644 clients/ivi-shell-user-interface.c
>>
>> diff --git a/Makefile.am b/Makefile.am
>> index 1f75cc3..46c5e3d 100644
>> --- a/Makefile.am
>> +++ b/Makefile.am
>> @@ -359,7 +359,8 @@ libexec_PROGRAMS += ? ? ? ? ? ? ? ? ?
>> ? ? ?
>> ? ? ? ? weston-desktop-shell ? ? ? ? ? ? ? ? ? ?
>> ? ? ? ? weston-screenshooter ? ? ? ? ? ? ? ? ? ?
>> ? ? ? ? weston-keyboard ? ? ? ? ? ? ? ? ? ? ? ?
>> - ? ? ? weston-simple-im
>> + ? ? ? weston-simple-im ? ? ? ? ? ? ? ? ? ? ? ?
>> + ? ? ? weston-ivi-shell-user-interface
>>
>> ?demo_clients = ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
>> ? ? ? ? weston-flower ? ? ? ? ? ? ? ? ? ? ? ? ?
>> @@ -570,6 +571,13 @@ nodist_weston_desktop_shell_SOURCES = ? ? ?
>> ? ? ? ? ? ? ? ?
>> ?weston_desktop_shell_LDADD = libtoytoolkit.la [1]
>> ?weston_desktop_shell_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
>>
>> +weston_ivi_shell_user_interface_SOURCES =
>> clients/ivi-shell-user-interface.c
>> +nodist_weston_ivi_shell_user_interface_SOURCES = ? ? ? ? ? ?
>> ? ? ? ? ?
>> + ? ? ? protocol/ivi-hmi-controller-client-protocol.h ? ? ?
>> ? ? ? ? ? ?
>> + ? ? ? protocol/ivi-hmi-controller-protocol.c
>> +weston_ivi_shell_user_interface_LDADD = libtoytoolkit.la [1]
>> +weston_ivi_shell_user_interface_CFLAGS = $(AM_CFLAGS)
>> $(CLIENT_CFLAGS)
>> +
>> ?if BUILD_FULL_GL_CLIENTS
>> ?demo_clients += weston-gears
>> ?weston_gears_SOURCES = clients/gears.c
>> diff --git a/clients/ivi-shell-user-interface.c
>> b/clients/ivi-shell-user-interface.c
>> new file mode 100644
>> index 0000000..70b854b
>> --- /dev/null
>> +++ b/clients/ivi-shell-user-interface.c
>> @@ -0,0 +1,1332 @@
>> +/*
>> + * Copyright (C) 2013 DENSO CORPORATION
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this
>> software and
>> + * its documentation for any purpose is hereby granted without
>> fee, provided
>> + * that the above copyright notice appear in all copies and that
>> both that
>> + * copyright notice and this permission notice appear in
>> supporting
>> + * documentation, and that the name of the copyright holders not
>> be used in
>> + * advertising or publicity pertaining to distribution of the
>> software
>> + * without specific, written prior permission. ?The copyright
>> holders make
>> + * no representations about the suitability of this software for
>> any
>> + * purpose. ?It is provided "as is" without express or implied
>> warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO
>> THIS
>> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
>> AND
>> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR
>> ANY
>> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
>> WHATSOEVER
>> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
>> ACTION OF
>> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
>> OR IN
>> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>> + */
>> +
>> +#include <sys/wait.h>
>> +#include <unistd.h>
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <linux/input.h>
>> +#include <assert.h>
>> +#include <fcntl.h>
>> +#include <signal.h>
>> +#include <sys/mman.h>
>> +#include <getopt.h>
>> +#include <pthread.h>
>> +#include <wayland-cursor.h>
>> +#include "../shared/cairo-util.h"
>> +#include "../shared/config-parser.h"
>> +#include "ivi-application-client-protocol.h"
>> +#include "ivi-hmi-controller-client-protocol.h"
>> +
>> +/**
>> + * A reference implementation how to use ivi-hmi-controller
>> interface to interact
>> + * with hmi-controller. This is launched from hmi-controller by
>> using
>> + * hmi_client_start and create a pthread.
>> + *
>> + * The basic flow is as followed,
>> + * 1/ create pthread
>> + * 2/ read configuration from weston.ini.
>> + * 3/ draw png file to surface according to configuration of
>> weston.ini
>> + * 4/ set up UI by using ivi-hmi-controller protocol
>> + * 5/ Enter event loop
>> + * 6/ If a surface receives touch/pointer event, followings are
>> invoked according
>> + * ? ?to type of event and surface
>> + * 6-1/ If a surface to launch ivi_application receive touch up,
>> it execs
>> + * ? ? ?ivi-application configured in weston.ini.
>> + * 6-2/ If a surface to switch layout mode receive touch up, it
>> sends a request,
>> + * ? ? ?ivi_hmi_controller_switch_mode, to hmi-controller.
>> + * 6-3/ If a surface to show workspace having launchers, it sends
>> a request,
>> + * ? ? ?ivi_hmi_controller_home, to hmi-controller.
>> + * 6-4/ If touch down events happens in workspace,
>> + * ? ? ?ivi_hmi_controller_workspace_control is sent to slide
>> workspace.
>> + * ? ? ?When control finished, event:
>> ivi_hmi_controller_workspace_end_control
>> + * ? ? ?is received.
>> + */
>> +
>>
> +/*****************************************************************************
>> + * ?structure, globals
>> +
>>
> ****************************************************************************/
>> +enum cursor_type {
>> + ? ?CURSOR_BOTTOM_LEFT,
>> + ? ?CURSOR_BOTTOM_RIGHT,
>> + ? ?CURSOR_BOTTOM,
>> + ? ?CURSOR_DRAGGING,
>> + ? ?CURSOR_LEFT_PTR,
>> + ? ?CURSOR_LEFT,
>> + ? ?CURSOR_RIGHT,
>> + ? ?CURSOR_TOP_LEFT,
>> + ? ?CURSOR_TOP_RIGHT,
>> + ? ?CURSOR_TOP,
>> + ? ?CURSOR_IBEAM,
>> + ? ?CURSOR_HAND1,
>> + ? ?CURSOR_WATCH,
>> +
>> + ? ?CURSOR_BLANK
>> +};
>> +struct wlContextCommon {
>> + ? ?struct wl_display ? ? ?*wlDisplay;
>> + ? ?struct wl_registry ? ? *wlRegistry;
>> + ? ?struct wl_compositor ? *wlCompositor;
>> + ? ?struct wl_shm ? ? ? ? ?*wlShm;
>> + ? ?struct wl_seat ? ? ? ? *wlSeat;
>> + ? ?struct wl_pointer ? ? ?*wlPointer;
>> + ? ?struct wl_touch ? ? ? ?*wlTouch;
>> + ? ?struct ivi_application *iviApplication;
>> + ? ?struct ivi_hmi_controller ?*hmiCtrl;
>> + ? ?struct hmi_homescreen_setting *hmi_setting;
>> + ? ?struct wl_list ? ? ? ? *list_wlContextStruct;
>> + ? ?struct wl_surface ? ? ?*enterSurface;
>> + ? ?int32_t ? ? ? ? ? ? ? ? is_home_on;
>> + ? ?struct wl_cursor_theme ?*cursor_theme;
>> + ? ?struct wl_cursor ? ? ? ?**cursors;
>> + ? ?struct wl_surface ? ? ? *pointer_surface;
>> + ? ?enum ? cursor_type ? ? ?current_cursor;
>> + ? ?uint32_t ? ? ? ? ? ? ? ?enter_serial;
>> +};
>> +
>> +struct wlContextStruct {
>> + ? ?struct wlContextCommon ?cmm;
>> + ? ?struct wl_surface ? ? ? *wlSurface;
>> + ? ?struct wl_buffer ? ? ? ?*wlBuffer;
>> + ? ?uint32_t ? ? ? ? ? ? ? ?formats;
>> + ? ?cairo_surface_t ? ? ? ? *ctx_image;
>> + ? ?void ? ? ? ? ? ? ? ? ? ?*data;
>> + ? ?uint32_t ? ? ? ? ? ? ? ?id_surface;
>> + ? ?struct wl_list ? ? ? ? ?link;
>> +};
>> +
>> +struct
>> +hmi_homescreen_srf {
>> + ? ?uint32_t ? ?id;
>> + ? ?char ? ? ? ?*filePath;
>> + ? ?uint32_t ? ?color;
>> +};
>> +
>> +struct
>> +hmi_homescreen_workspace {
>> + ? ?struct wl_array ? ? launcher_id_array;
>> + ? ?struct wl_list ? ? ?link;
>> +};
>> +
>> +struct
>> +hmi_homescreen_launcher {
>> + ? ?uint32_t ? ? ? ? ? ?icon_surface_id;
>> + ? ?uint32_t ? ? ? ? ? ?workspace_id;
>> + ? ?char* ? ? ? ? ? ? ? icon;
>> + ? ?char* ? ? ? ? ? ? ? path;
>> + ? ?struct wl_list ? ? ?link;
>> +};
>> +
>> +struct
>> +hmi_homescreen_setting {
>> + ? ?struct hmi_homescreen_srf ?background;
>> + ? ?struct hmi_homescreen_srf ?panel;
>> + ? ?struct hmi_homescreen_srf ?tiling;
>> + ? ?struct hmi_homescreen_srf ?sidebyside;
>> + ? ?struct hmi_homescreen_srf ?fullscreen;
>> + ? ?struct hmi_homescreen_srf ?random;
>> + ? ?struct hmi_homescreen_srf ?home;
>> + ? ?struct hmi_homescreen_srf ?workspace_background;
>> +
>> + ? ?struct wl_list workspace_list;
>> + ? ?struct wl_list launcher_list;
>> +
>> + ? ?char ? ? *cursor_theme;
>> + ? ?int32_t ?cursor_size;
>> +};
>> +
>> +volatile int gRun = 0;
>> +
>> +static void *
>> +fail_on_null(void *p, size_t size, char* file, int32_t line)
>> +{
>> + ? ?if (size && !p) {
>> + ? ? ? ?fprintf(stderr, "%s(%d) %zd: out of memoryn", file,
>> line, size);
>> + ? ? ? ?exit(EXIT_FAILURE);
>> + ? ?}
>> +
>> + ? ?return p;
>> +}
>> +
>> +static void *
>> +mem_alloc(size_t size, char* file, int32_t line)
>> +{
>> + ? ?return fail_on_null(calloc(1, size), size, file, line);
>> +}
>> +
>> +#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
>> +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
>> +
>>
> +/*****************************************************************************
>> + * ?Event Handler
>> +
>>
> ****************************************************************************/
>> +
>> +static void
>> +shm_format(void* data, struct wl_shm* pWlShm, uint32_t format)
>> +{
>> + ? ?struct wlContextStruct* pDsp = data;
>> + ? ?pDsp->formats |= (1 << format);
>> +}
>> +
>> +static struct wl_shm_listener shm_listenter = {
>> + ? ?shm_format
>> +};
>> +
>> +static int32_t
>> +getIdOfWlSurface(struct wlContextCommon *pCtx, struct wl_surface
>> *wlSurface)
>> +{
>> + ? ?if (NULL == pCtx ||
>> + ? ? ? ?NULL == wlSurface ) {
>> + ? ? ? ?return 0;
>> + ? ?}
>> +
>> + ? ?struct wlContextStruct* pWlCtxSt = NULL;
>> + ? ?wl_list_for_each(pWlCtxSt, pCtx->list_wlContextStruct, link)
>> {
>> + ? ? ? ?if (pWlCtxSt->wlSurface == wlSurface) {
>> + ? ? ? ? ? ?return pWlCtxSt->id_surface;
>> + ? ? ? ?}
>> + ? ? ? ?continue;
>> + ? ?}
>> + ? ?return -1;
>> +}
>> +
>> +static void
>> +set_pointer_image(struct wlContextCommon *pCtx, uint32_t index)
>> +{
>> + ? ?if (!pCtx->wlPointer ||
>> + ? ? ? ?!pCtx->cursors) {
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?if (CURSOR_BLANK == pCtx->current_cursor) {
>> + ? ? ? ?wl_pointer_set_cursor(pCtx->wlPointer,
>> pCtx->enter_serial,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?NULL, 0, 0);
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?struct wl_cursor *cursor =
>> pCtx->cursors[pCtx->current_cursor];
>> + ? ?if (!cursor) {
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?if (cursor->image_count <= index) {
>> + ? ? ? ?fprintf(stderr, "cursor index out of rangen");
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?struct wl_cursor_image *image = cursor->images[index];
>> + ? ?struct wl_buffer *buffer =
>> wl_cursor_image_get_buffer(image);
>> +
>> + ? ?if (!buffer) {
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ?pCtx->pointer_surface,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ?image->hotspot_x,
>> image->hotspot_y);
>> +
>> + ? ?wl_surface_attach(pCtx->pointer_surface, buffer, 0, 0);
>> +
>> + ? ?wl_surface_damage(pCtx->pointer_surface, 0, 0,
>> + ? ? ? ? ? ? ? ? ? ? ?image->width, image->height);
>> +
>> + ? ?wl_surface_commit(pCtx->pointer_surface);
>> +}
>> +
>> +static void
>> +PointerHandleEnter(void* data, struct wl_pointer* wlPointer,
>> uint32_t serial,
>> + ? ? ? ? ? ? ? ? ? struct wl_surface* wlSurface,
>> wl_fixed_t sx, wl_fixed_t sy)
>> +{
>> + ? ?(void)wlPointer;
>> + ? ?(void)serial;
>> +
>> + ? ?struct wlContextCommon *pCtx = data;
>> + ? ?pCtx->enter_serial = serial;
>> + ? ?pCtx->enterSurface = wlSurface;
>> + ? ?set_pointer_image(pCtx, 0);
>> +#ifdef _DEBUG
>> + ? ?printf("ENTER PointerHandleEnter: x(%d), y(%d)n", sx, sy);
>> +#endif
>> +}
>> +
>> +static void
>> +PointerHandleLeave(void* data, struct wl_pointer* wlPointer,
>> uint32_t serial,
>> + ? ? ? ? ? ? ? ? ? struct wl_surface* wlSurface)
>> +{
>> + ? ?(void)wlPointer;
>> + ? ?(void)wlSurface;
>> +
>> + ? ?struct wlContextCommon *pCtx = data;
>> + ? ?pCtx->enterSurface = NULL;
>> +
>> +#ifdef _DEBUG
>> + ? ?printf("ENTER PointerHandleLeave: serial(%d)n", serial);
>> +#endif
>> +}
>> +
>> +static void
>> +PointerHandleMotion(void* data, struct wl_pointer* wlPointer,
>> uint32_t time,
>> + ? ? ? ? ? ? ? ? ? ?wl_fixed_t sx, wl_fixed_t sy)
>> +{
>> + ? ?(void)data;
>> + ? ?(void)wlPointer;
>> + ? ?(void)time;
>> +
>> +#ifdef _DEBUG
>> + ? ?printf("ENTER PointerHandleMotion: x(%d), y(%d)n",
>> gPointerX, gPointerY);
>> +#endif
>> +}
>> +
>> +/**
>> + * if a surface assigned as launcher receives touch-off event,
>> invoking
>> + * ivi-application which configured in weston.ini with path to
>> binary.
>> + */
>> +extern char **environ; /*defied by libc */
>> +
>> +static pid_t execute_process(char* path, char *argv[])
>> +{
>> + ? ?pid_t pid = fork();
>> + ? ?if (pid < 0) {
>> + ? ? ? ?fprintf(stderr, "Failed to forkn");
>> + ? ?}
>> +
>> + ? ?if (pid) {
>> + ? ? ? ?return pid;
>> + ? ?}
>> +
>> + ? ?if (-1 == execve(path, argv, environ)) {
>> + ? ? ? ?fprintf(stderr, "Failed to execve %sn", path);
>> + ? ? ? ?exit(1);
>> + ? ?}
>> +
>> + ? ?return pid;
>> +}
>> +
>> +static int32_t
>> +launcher_button(uint32_t surfaceId, struct wl_list *launcher_list)
>> +{
>> + ? ?struct hmi_homescreen_launcher *launcher = NULL;
>> +
>> + ? ?wl_list_for_each(launcher, launcher_list, link) {
>> + ? ? ? ?if (surfaceId != launcher->icon_surface_id) {
>> + ? ? ? ? ? ?continue;
>> + ? ? ? ?}
>> +
>> + ? ? ? ?char *argv[] = {NULL};
>> + ? ? ? ?execute_process(launcher->path, argv);
>> +
>> + ? ? ? ?return 1;
>> + ? ?}
>> +
>> + ? ?return 0;
>> +}
>> +
>> +/**
>> + * is-method to identify a surface set as launcher in workspace or
>> workspace
>> + * itself. This is-method is used to decide whether request;
>> + * ivi_hmi_controller_workspace_control is sent or not.
>> + */
>> +static int32_t
>> +isWorkspaceSurface(uint32_t id, struct hmi_homescreen_setting
>> *hmi_setting)
>> +{
>> + ? ?if (id == hmi_setting->workspace_background.id [2]) {
>> + ? ? ? ?return 1;
>> + ? ?}
>> +
>> + ? ?struct hmi_homescreen_launcher *launcher = NULL;
>> + ? ?wl_list_for_each(launcher, &hmi_setting->launcher_list,
>> link) {
>> + ? ? ? ?if (id == launcher->icon_surface_id) {
>> + ? ? ? ? ? ?return 1;
>> + ? ? ? ?}
>> + ? ?}
>> +
>> + ? ?return 0;
>> +}
>> +
>> +/**
>> + * Decide which request is sent to hmi-controller
>> + */
>> +static void
>> +touch_up(struct ivi_hmi_controller *hmi_ctrl, uint32_t id_surface,
>> + ? ? ? ? int32_t *is_home_on, struct hmi_homescreen_setting*
>> hmi_setting)
>> +{
>> + ? ?if (launcher_button(id_surface,
>> &hmi_setting->launcher_list)) {
>> + ? ? ? ?*is_home_on = 0;
>> + ? ? ? ?ivi_hmi_controller_home(hmi_ctrl,
>> IVI_HMI_CONTROLLER_HOME_OFF);
>> + ? ?} else if (id_surface == hmi_setting->tiling.id [3]) {
>> + ? ? ? ?ivi_hmi_controller_switch_mode(
>> + ? ? ? ? ? ? ? ? ? ?hmi_ctrl,
>> IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING);
>> + ? ?} else if (id_surface == hmi_setting->sidebyside.id [4]) {
>> + ? ? ? ?ivi_hmi_controller_switch_mode(
>> + ? ? ? ? ? ? ? ? ? ?hmi_ctrl,
>> IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE);
>> + ? ?} else if (id_surface == hmi_setting->fullscreen.id [5]) {
>> + ? ? ? ?ivi_hmi_controller_switch_mode(
>> + ? ? ? ? ? ? ? ? ? ?hmi_ctrl,
>> IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN);
>> + ? ?} else if (id_surface == hmi_setting->random.id [6]) {
>> + ? ? ? ?ivi_hmi_controller_switch_mode(
>> + ? ? ? ? ? ? ? ? ? ?hmi_ctrl,
>> IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM);
>> + ? ?} else if (id_surface == hmi_setting->home.id [7]) {
>> + ? ? ? ?*is_home_on = !(*is_home_on);
>> + ? ? ? ?if (*is_home_on) {
>> + ? ? ? ? ? ?ivi_hmi_controller_home(hmi_ctrl,
>> IVI_HMI_CONTROLLER_HOME_ON);
>> + ? ? ? ?} else {
>> + ? ? ? ? ? ?ivi_hmi_controller_home(hmi_ctrl,
>> IVI_HMI_CONTROLLER_HOME_OFF);
>> + ? ? ? ?}
>> + ? ?}
>> +}
>> +
>> +/**
>> + * Even handler of Pointer event. IVI system is usually
>> manipulated by touch
>> + * screen. However, some systems also have pointer device.
>> + * Release is the same behavior as touch off
>> + * Pressed is the same behavior as touch on
>> + */
>> +static void
>> +PointerHandleButton(void* data, struct wl_pointer* wlPointer,
>> uint32_t serial,
>> + ? ? ? ? ? ? ? ? ? ?uint32_t time, uint32_t button,
>> uint32_t state)
>> +{
>> + ? ?(void)wlPointer;
>> + ? ?(void)serial;
>> + ? ?(void)time;
>> + ? ?struct wlContextCommon *pCtx = data;
>> + ? ?struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
>> +
>> + ? ?if (BTN_RIGHT == button) {
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?const uint32_t id_surface = getIdOfWlSurface(pCtx,
>> pCtx->enterSurface);
>> +
>> + ? ?switch (state) {
>> + ? ?case WL_POINTER_BUTTON_STATE_RELEASED:
>> + ? ? ? ?touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on,
>> pCtx->hmi_setting);
>> + ? ? ? ?break;
>> +
>> + ? ?case WL_POINTER_BUTTON_STATE_PRESSED:
>> +
>> + ? ? ? ?if (isWorkspaceSurface(id_surface, pCtx->hmi_setting))
>> {
>> + ? ? ? ? ? ?ivi_hmi_controller_workspace_control(hmi_ctrl,
>> pCtx->wlSeat, serial);
>> + ? ? ? ?}
>> +
>> + ? ? ? ?break;
>> + ? ?}
>> +#ifdef _DEBUG
>> + ? ?printf("ENTER PointerHandleButton: button(%d), state(%d)n",
>> button, state);
>> +#endif
>> +}
>> +
>> +static void
>> +PointerHandleAxis(void* data, struct wl_pointer* wlPointer,
>> uint32_t time,
>> + ? ? ? ? ? ? ? ? ?uint32_t axis, wl_fixed_t value)
>> +{
>> + ? ?(void)data;
>> + ? ?(void)wlPointer;
>> + ? ?(void)time;
>> +#ifdef _DEBUG
>> + ? ?printf("ENTER PointerHandleAxis: axis(%d), value(%d)n",
>> axis, value);
>> +#endif
>> +}
>> +
>> +static struct wl_pointer_listener pointer_listener = {
>> + ? ?PointerHandleEnter,
>> + ? ?PointerHandleLeave,
>> + ? ?PointerHandleMotion,
>> + ? ?PointerHandleButton,
>> + ? ?PointerHandleAxis
>> +};
>> +
>> +/**
>> + * Even handler of touch event
>> + */
>> +static void
>> +TouchHandleDown(void *data, struct wl_touch *wlTouch, uint32_t
>> serial, uint32_t time,
>> + ? ? ? ? ? ? ? ?struct wl_surface *surface, int32_t id,
>> wl_fixed_t x_w, wl_fixed_t y_w)
>> +{
>> + ? ?struct wlContextCommon *pCtx = data;
>> + ? ?struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
>> +
>> + ? ?if (0 == id){
>> + ? ? ? ?pCtx->enterSurface = surface;
>> + ? ?}
>> +
>> + ? ?const uint32_t id_surface = getIdOfWlSurface(pCtx,
>> pCtx->enterSurface);
>> +
>> + ? ?/**
>> + ? ? * When touch down happens on surfaces of workspace, ask
>> hmi-controller to start
>> + ? ? * control workspace to select page of workspace.
>> + ? ? * After sending seat to hmi-controller by
>> ivi_hmi_controller_workspace_control,
>> + ? ? * hmi-controller-homescreen doesn't receive any event till
>> hmi-controller sends
>> + ? ? * back it.
>> + ? ? */
>> + ? ?if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
>> + ? ? ? ?ivi_hmi_controller_workspace_control(hmi_ctrl,
>> pCtx->wlSeat, serial);
>> + ? ?}
>> +}
>> +
>> +static void
>> +TouchHandleUp(void *data, struct wl_touch *wlTouch, uint32_t
>> serial, uint32_t time,
>> + ? ? ? ? ? ? ?int32_t id)
>> +{
>> + ? ?(void)serial;
>> + ? ?(void)time;
>> + ? ?struct wlContextCommon *pCtx = data;
>> + ? ?struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
>> +
>> + ? ?const uint32_t id_surface = getIdOfWlSurface(pCtx,
>> pCtx->enterSurface);
>> +
>> + ? ?/**
>> + ? ? * triggering event according to touch-up happening on which
>> surface.
>> + ? ? */
>> + ? ?if (id == 0){
>> + ? ? ? ?touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on,
>> pCtx->hmi_setting);
>> + ? ?}
>> +}
>> +
>> +static void
>> +TouchHandleMotion(void *data, struct wl_touch *wlTouch, uint32_t
>> time,
>> + ? ? ? ? ? ? ? ? ?int32_t id, wl_fixed_t x_w, wl_fixed_t
>> y_w)
>> +{
>> +}
>> +
>> +static void
>> +TouchHandleFrame(void *data, struct wl_touch *wlTouch)
>> +{
>> +}
>> +
>> +static void
>> +TouchHandleCancel(void *data, struct wl_touch *wlTouch)
>> +{
>> +}
>> +
>> +static struct wl_touch_listener touch_listener = {
>> + ? ?TouchHandleDown,
>> + ? ?TouchHandleUp,
>> + ? ?TouchHandleMotion,
>> + ? ?TouchHandleFrame,
>> + ? ?TouchHandleCancel,
>> +};
>> +
>> +/**
>> + * Handler of capabilities
>> + */
>> +static void
>> +seat_handle_capabilities(void* data, struct wl_seat* seat,
>> uint32_t caps)
>> +{
>> + ? ?(void)seat;
>> + ? ?struct wlContextCommon* p_wlCtx = (struct
>> wlContextCommon*)data;
>> + ? ?struct wl_seat* wlSeat = p_wlCtx->wlSeat;
>> + ? ?struct wl_pointer* wlPointer = p_wlCtx->wlPointer;
>> + ? ?struct wl_touch* wlTouch = p_wlCtx->wlTouch;
>> +
>> + ? ?if (p_wlCtx->hmi_setting->cursor_theme) {
>> + ? ? ? ?if ((caps & WL_SEAT_CAPABILITY_POINTER) &&
>> !wlPointer){
>> + ? ? ? ? ? ?wlPointer = wl_seat_get_pointer(wlSeat);
>> + ? ? ? ? ? ?wl_pointer_set_user_data(wlPointer, data);
>> + ? ? ? ? ? ?wl_pointer_add_listener(wlPointer,
>> &pointer_listener, data);
>> + ? ? ? ?} else
>> + ? ? ? ?if (!(caps & WL_SEAT_CAPABILITY_POINTER) &&
>> wlPointer){
>> + ? ? ? ? ? ?wl_pointer_destroy(wlPointer);
>> + ? ? ? ? ? ?wlPointer = NULL;
>> + ? ? ? ?}
>> + ? ? ? ?p_wlCtx->wlPointer = wlPointer;
>> + ? ?}
>> +
>> + ? ?if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wlTouch){
>> + ? ? ? ?wlTouch = wl_seat_get_touch(wlSeat);
>> + ? ? ? ?wl_touch_set_user_data(wlTouch, data);
>> + ? ? ? ?wl_touch_add_listener(wlTouch, &touch_listener, data);
>> + ? ?} else
>> + ? ?if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wlTouch){
>> + ? ? ? ?wl_touch_destroy(wlTouch);
>> + ? ? ? ?wlTouch = NULL;
>> + ? ?}
>> + ? ?p_wlCtx->wlTouch = wlTouch;
>> +}
>> +
>> +static struct wl_seat_listener seat_Listener = {
>> + ? ?seat_handle_capabilities,
>> +};
>> +
>> +/**
>> + * Registration of event
>> + * This event is received when hmi-controller server finished
>> controlling
>> + * workspace.
>> + */
>> +static void
>> +ivi_hmi_controller_workspace_end_control(void *data,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct
>> ivi_hmi_controller *hmi_ctrl,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int32_t
>> is_controlled)
>> +{
>> + ? ?if (is_controlled) {
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?struct wlContextCommon *pCtx = data;
>> + ? ?const uint32_t id_surface = getIdOfWlSurface(pCtx,
>> pCtx->enterSurface);
>> +
>> + ? ?/**
>> + ? ? * During being controlled by hmi-controller, any input
>> event is not
>> + ? ? * notified. So when control ends with touch up, it invokes
>> launcher
>> + ? ? * if up event happens on a launcher surface.
>> + ? ? *
>> + ? ? */
>> + ? ?if (launcher_button(id_surface,
>> &pCtx->hmi_setting->launcher_list)) {
>> + ? ? ? ?pCtx->is_home_on = 0;
>> + ? ? ? ?ivi_hmi_controller_home(hmi_ctrl,
>> IVI_HMI_CONTROLLER_HOME_OFF);
>> + ? ?}
>> +}
>> +
>> +static const struct ivi_hmi_controller_listener
>> hmi_controller_listener = {
>> + ? ?ivi_hmi_controller_workspace_end_control
>> +};
>> +
>> +/**
>> + * Registration of interfaces
>> + */
>> +static void
>> +registry_handle_global(void* data, struct wl_registry* registry,
>> uint32_t name,
>> + ? ? ? ? ? ? ? ? ? ? ? const char *interface, uint32_t
>> version)
>> +{
>> + ? ?(void)version;
>> + ? ?struct wlContextCommon* p_wlCtx = (struct
>> wlContextCommon*)data;
>> +
>> + ? ?do {
>> + ? ? ? ?if (!strcmp(interface, "wl_compositor")) {
>> + ? ? ? ? ? ?p_wlCtx->wlCompositor =
>> wl_registry_bind(registry, name, &wl_compositor_interface, 1);
>> + ? ? ? ? ? ?break;
>> + ? ? ? ?}
>> + ? ? ? ?if (!strcmp(interface, "wl_shm")) {
>> + ? ? ? ? ? ?p_wlCtx->wlShm = wl_registry_bind(registry,
>> name, &wl_shm_interface, 1);
>> + ? ? ? ? ? ?wl_shm_add_listener(p_wlCtx->wlShm,
>> &shm_listenter, p_wlCtx);
>> + ? ? ? ? ? ?break;
>> + ? ? ? ?}
>> + ? ? ? ?if (!strcmp(interface, "wl_seat")) {
>> + ? ? ? ? ? ?p_wlCtx->wlSeat = wl_registry_bind(registry,
>> name, &wl_seat_interface, 1);
>> + ? ? ? ? ? ?wl_seat_add_listener(p_wlCtx->wlSeat,
>> &seat_Listener, data);
>> + ? ? ? ? ? ?break;
>> + ? ? ? ?}
>> + ? ? ? ?if (!strcmp(interface, "ivi_application")) {
>> + ? ? ? ? ? ?p_wlCtx->iviApplication =
>> wl_registry_bind(registry, name, &ivi_application_interface, 1);
>> + ? ? ? ? ? ?break;
>> + ? ? ? ?}
>> + ? ? ? ?if (!strcmp(interface, "ivi_hmi_controller")) {
>> + ? ? ? ? ? ?p_wlCtx->hmiCtrl = wl_registry_bind(registry,
>> name, &ivi_hmi_controller_interface, 1);
>> +
>> + ? ? ? ? ? ?if (p_wlCtx->hmiCtrl) {
>> + ? ? ? ? ? ? ?
>> ?ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl,
>> &hmi_controller_listener, p_wlCtx);
>> + ? ? ? ? ? ?}
>> + ? ? ? ? ? ?break;
>> + ? ? ? ?}
>> +
>> + ? ?} while(0);
>> +}
>> +
>> +static const struct wl_registry_listener registry_listener = {
>> + ? ?registry_handle_global,
>> + ? ?NULL
>> +};
>> +
>> +static void
>> +frame_listener_func(void *data, struct wl_callback *callback,
>> uint32_t time)
>> +{
>> + ? ?if (callback) {
>> + ? ? ? ?wl_callback_destroy(callback);
>> + ? ?}
>> +}
>> +
>> +static const struct wl_callback_listener frame_listener = {
>> + ? ?frame_listener_func
>> +};
>> +
>> +/*
>> + * The following correspondences between file names and cursors
>> was copied
>> + * from: https://bugs.kde.org/attachment.cgi?id=67313 [8]
>> + */
>> +static const char *bottom_left_corners[] = {
>> + ? ?"bottom_left_corner",
>> + ? ?"sw-resize",
>> + ? ?"size_bdiag"
>> +};
>> +
>> +static const char *bottom_right_corners[] = {
>> + ? ?"bottom_right_corner",
>> + ? ?"se-resize",
>> + ? ?"size_fdiag"
>> +};
>> +
>> +static const char *bottom_sides[] = {
>> + ? ?"bottom_side",
>> + ? ?"s-resize",
>> + ? ?"size_ver"
>> +};
>> +
>> +static const char *grabbings[] = {
>> + ? ?"grabbing",
>> + ? ?"closedhand",
>> + ? ?"208530c400c041818281048008011002"
>> +};
>> +
>> +static const char *left_ptrs[] = {
>> + ? ?"left_ptr",
>> + ? ?"default",
>> + ? ?"top_left_arrow",
>> + ? ?"left-arrow"
>> +};
>> +
>> +static const char *left_sides[] = {
>> + ? ?"left_side",
>> + ? ?"w-resize",
>> + ? ?"size_hor"
>> +};
>> +
>> +static const char *right_sides[] = {
>> + ? ?"right_side",
>> + ? ?"e-resize",
>> + ? ?"size_hor"
>> +};
>> +
>> +static const char *top_left_corners[] = {
>> + ? ?"top_left_corner",
>> + ? ?"nw-resize",
>> + ? ?"size_fdiag"
>> +};
>> +
>> +static const char *top_right_corners[] = {
>> + ? ?"top_right_corner",
>> + ? ?"ne-resize",
>> + ? ?"size_bdiag"
>> +};
>> +
>> +static const char *top_sides[] = {
>> + ? ?"top_side",
>> + ? ?"n-resize",
>> + ? ?"size_ver"
>> +};
>> +
>> +static const char *xterms[] = {
>> + ? ?"xterm",
>> + ? ?"ibeam",
>> + ? ?"text"
>> +};
>> +
>> +static const char *hand1s[] = {
>> + ? ?"hand1",
>> + ? ?"pointer",
>> + ? ?"pointing_hand",
>> + ? ?"e29285e634086352946a0e7090d73106"
>> +};
>> +
>> +static const char *watches[] = {
>> + ? ?"watch",
>> + ? ?"wait",
>> + ? ?"0426c94ea35c87780ff01dc239897213"
>> +};
>> +
>> +struct cursor_alternatives {
>> + ? ?const char **names;
>> + ? ?size_t count;
>> +};
>> +
>> +static const struct cursor_alternatives cursors[] = {
>> + ? ?{bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
>> + ? ?{bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
>> + ? ?{bottom_sides, ARRAY_LENGTH(bottom_sides)},
>> + ? ?{grabbings, ARRAY_LENGTH(grabbings)},
>> + ? ?{left_ptrs, ARRAY_LENGTH(left_ptrs)},
>> + ? ?{left_sides, ARRAY_LENGTH(left_sides)},
>> + ? ?{right_sides, ARRAY_LENGTH(right_sides)},
>> + ? ?{top_left_corners, ARRAY_LENGTH(top_left_corners)},
>> + ? ?{top_right_corners, ARRAY_LENGTH(top_right_corners)},
>> + ? ?{top_sides, ARRAY_LENGTH(top_sides)},
>> + ? ?{xterms, ARRAY_LENGTH(xterms)},
>> + ? ?{hand1s, ARRAY_LENGTH(hand1s)},
>> + ? ?{watches, ARRAY_LENGTH(watches)},
>> +};
>> +
>> +static void
>> +create_cursors(struct wlContextCommon *cmm)
>> +{
>> + ? ?uint32_t i = 0;
>> + ? ?uint32_t j = 0;
>> + ? ?struct wl_cursor *cursor = NULL;
>> + ? ?char* cursor_theme = cmm->hmi_setting->cursor_theme;
>> + ? ?int32_t cursor_size = cmm->hmi_setting->cursor_size;
>> +
>> + ? ?cmm->cursor_theme = wl_cursor_theme_load(cursor_theme,
>> cursor_size, cmm->wlShm);
>> +
>> + ? ?cmm->cursors = MEM_ALLOC(ARRAY_LENGTH(cursors) *
>> sizeof(cmm->cursors[0]));
>> +
>> + ? ?for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
>> + ? ? ? ?cursor = NULL;
>> +
>> + ? ? ? ?for (j = 0; !cursor && j < cursors[i].count; ++j) {
>> + ? ? ? ? ? ?cursor = wl_cursor_theme_get_cursor(
>> + ? ? ? ? ? ? ? ?cmm->cursor_theme, cursors[i].names[j]);
>> + ? ? ? ?}
>> +
>> + ? ? ? ?if (!cursor) {
>> + ? ? ? ? ? ?fprintf(stderr, "could not load cursor '%s'n",
>> + ? ? ? ? ? ? ? ? ? ?cursors[i].names[0]);
>> + ? ? ? ?}
>> +
>> + ? ? ? ?cmm->cursors[i] = cursor;
>> + ? ?}
>> +}
>> +
>> +static void
>> +destroy_cursors(struct wlContextCommon *cmm)
>> +{
>> + ? ?if (cmm->cursor_theme) {
>> + ? ? ? ?wl_cursor_theme_destroy(cmm->cursor_theme);
>> + ? ?}
>> +
>> + ? ?free(cmm->cursors);
>> +}
>> +
>> +/**
>> + * Internal method to prepare parts of UI
>> + */
>> +static void
>> +createShmBuffer(struct wlContextStruct *p_wlCtx)
>> +{
>> + ? ?struct wl_shm_pool *pool;
>> +
>> + ? ?char filename[] = "/tmp/wayland-shm-XXXXXX";
>> + ? ?int fd = -1;
>> + ? ?int size = 0;
>> + ? ?int width = 0;
>> + ? ?int height = 0;
>> + ? ?int stride = 0;
>> +
>> + ? ?fd = mkstemp(filename);
>> + ? ?if (fd < 0) {
>> + ? ? ? ?fprintf(stderr, "open %s failed: %mn", filename);
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?width ?= cairo_image_surface_get_width(p_wlCtx->ctx_image);
>> + ? ?height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
>> + ? ?stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
>> +
>> + ? ?size = stride * height;
>> + ? ?if (ftruncate(fd, size) < 0) {
>> + ? ? ? ?fprintf(stderr, "ftruncate failed: %mn");
>> + ? ? ? ?close(fd);
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?p_wlCtx->data = mmap(NULL, size, PROT_READ | PROT_WRITE,
>> MAP_SHARED, fd, 0);
>> +
>> + ? ?if (MAP_FAILED == p_wlCtx->data) {
>> + ? ? ? ?fprintf(stderr, "mmap failed: %mn");
>> + ? ? ? ?close(fd);
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?pool = wl_shm_create_pool(p_wlCtx->cmm.wlShm, fd, size);
>> + ? ?p_wlCtx->wlBuffer = wl_shm_pool_create_buffer(pool, 0,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
>> ? ? ?width,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
>> ? ? ?height,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
>> ? ? ?stride,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
>> ? ? ?WL_SHM_FORMAT_ARGB8888);
>> +
>> + ? ?if (NULL == p_wlCtx->wlBuffer) {
>> + ? ? ? ?fprintf(stderr, "wl_shm_create_buffer failed: %mn");
>> + ? ? ? ?close(fd);
>> + ? ? ? ?return;
>> + ? ?}
>> + ? ?wl_shm_pool_destroy(pool);
>> + ? ?close(fd);
>> +
>> + ? ?return;
>> +}
>> +
>> +static void
>> +destroyWLContextCommon(struct wlContextCommon *p_wlCtx)
>> +{
>> + ? ?destroy_cursors(p_wlCtx);
>> +
>> + ? ?if (p_wlCtx->pointer_surface) {
>> + ? ? ? ?wl_surface_destroy(p_wlCtx->pointer_surface);
>> + ? ?}
>> +
>> + ? ?if (p_wlCtx->wlCompositor) {
>> + ? ? ? ?wl_compositor_destroy(p_wlCtx->wlCompositor);
>> + ? ?}
>> +}
>> +
>> +static void
>> +destroyWLContextStruct(struct wlContextStruct *p_wlCtx)
>> +{
>> + ? ?if (p_wlCtx->wlSurface) {
>> + ? ? ? ?wl_surface_destroy(p_wlCtx->wlSurface);
>> + ? ?}
>> +
>> + ? ?if (p_wlCtx->ctx_image) {
>> + ? ? ? ?cairo_surface_destroy(p_wlCtx->ctx_image);
>> + ? ? ? ?p_wlCtx->ctx_image = NULL;
>> + ? ?}
>> +}
>> +
>> +static int
>> +createWLContext(struct wlContextStruct *p_wlCtx)
>> +{
>> + ? ?wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
>> +
>> + ? ?p_wlCtx->wlSurface =
>> wl_compositor_create_surface(p_wlCtx->cmm.wlCompositor);
>> + ? ?if (NULL == p_wlCtx->wlSurface) {
>> + ? ? ? ?printf("Error: wl_compositor_create_surface
>> failed.n");
>> + ? ? ? ?destroyWLContextCommon(&p_wlCtx->cmm);
>> + ? ? ? ?abort();
>> + ? ?}
>> +
>> +
>> + ? ?createShmBuffer(p_wlCtx);
>> +
>> + ? ?wl_display_flush(p_wlCtx->cmm.wlDisplay);
>> + ? ?wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
>> +
>> + ? ?return 0;
>> +}
>> +
>> +static void
>> +drawImage(struct wlContextStruct *p_wlCtx)
>> +{
>> + ? ?struct wl_callback *callback;
>> +
>> + ? ?int width = 0;
>> + ? ?int height = 0;
>> + ? ?int stride = 0;
>> + ? ?void *data = NULL;
>> +
>> + ? ?width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
>> + ? ?height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
>> + ? ?stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
>> + ? ?data = cairo_image_surface_get_data(p_wlCtx->ctx_image);
>> +
>> + ? ?memcpy(p_wlCtx->data, data, stride * height);
>> +
>> + ? ?wl_surface_attach(p_wlCtx->wlSurface, p_wlCtx->wlBuffer, 0,
>> 0);
>> + ? ?wl_surface_damage(p_wlCtx->wlSurface, 0, 0, width, height);
>> +
>> + ? ?callback = wl_surface_frame(p_wlCtx->wlSurface);
>> + ? ?wl_callback_add_listener(callback, &frame_listener, NULL);
>> +
>> + ? ?wl_surface_commit(p_wlCtx->wlSurface);
>> +
>> + ? ?wl_display_flush(p_wlCtx->cmm.wlDisplay);
>> + ? ?wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
>> +}
>> +
>> +static void
>> +create_ivisurface(struct wlContextStruct *p_wlCtx,
>> + ? ? ? ? ? ? ? ? ?uint32_t id_surface,
>> + ? ? ? ? ? ? ? ? ?cairo_surface_t* surface)
>> +{
>> + ? ?struct ivi_surface *ivisurf = NULL;
>> +
>> + ? ?p_wlCtx->ctx_image = surface;
>> +
>> + ? ?p_wlCtx->id_surface = id_surface;
>> + ? ?wl_list_init(&p_wlCtx->link);
>> + ? ?wl_list_insert(p_wlCtx->cmm.list_wlContextStruct,
>> &p_wlCtx->link);
>> +
>> + ? ?createWLContext(p_wlCtx);
>> +
>> + ? ?ivisurf =
>> ivi_application_surface_create(p_wlCtx->cmm.iviApplication,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
>> id_surface, p_wlCtx->wlSurface);
>> + ? ?if (ivisurf == NULL) {
>> + ? ? ? ?fprintf(stderr, "Failed to create
>> ivi_client_surfacen");
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?drawImage(p_wlCtx);
>> +
>> + ? ?wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
>> +}
>> +
>> +static void
>> +create_ivisurfaceFromFile(struct wlContextStruct *p_wlCtx,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ?uint32_t id_surface,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ?const char* imageFile)
>> +{
>> + ? ?cairo_surface_t* surface = load_cairo_surface(imageFile);
>> +
>> + ? ?if (NULL == surface) {
>> + ? ? ? ?fprintf(stderr, "Failed to load_cairo_surface %sn",
>> imageFile);
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?create_ivisurface(p_wlCtx, id_surface, surface);
>> +}
>> +
>> +static void
>> +set_hex_color(cairo_t *cr, uint32_t color)
>> +{
>> + ? ?cairo_set_source_rgba(cr,
>> + ? ? ? ?((color >> 16) & 0xff) / 255.0,
>> + ? ? ? ?((color >> ?8) & 0xff) / 255.0,
>> + ? ? ? ?((color >> ?0) & 0xff) / 255.0,
>> + ? ? ? ?((color >> 24) & 0xff) / 255.0);
>> +}
>> +
>> +static void
>> +create_ivisurfaceFromColor(struct wlContextStruct *p_wlCtx,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? uint32_t id_surface,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? uint32_t width, uint32_t
>> height,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? uint32_t color)
>> +{
>> + ? ?cairo_surface_t *surface = NULL;
>> + ? ?cairo_t *cr = NULL;
>> +
>> + ? ?surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
>> width, height);
>> +
>> + ? ?cr = cairo_create(surface);
>> + ? ?cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
>> + ? ?cairo_rectangle(cr, 0, 0, width, height);
>> + ? ?set_hex_color(cr, color);
>> + ? ?cairo_fill(cr);
>> + ? ?cairo_destroy(cr);
>> +
>> + ? ?create_ivisurface(p_wlCtx, id_surface, surface);
>> +}
>> +
>> +static void
>> +UI_ready(struct ivi_hmi_controller *controller)
>> +{
>> + ? ?ivi_hmi_controller_UI_ready(controller);
>> +}
>> +
>> +/**
>> + * Internal method to set up UI by using ivi-hmi-controller
>> + */
>> +static void
>> +create_background(struct wlContextStruct *p_wlCtx, const uint32_t
>> id_surface,
>> + ? ? ? ? ? ? ? ? ?const char* imageFile)
>> +{
>> + ? ?create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
>> +}
>> +
>> +static void
>> +create_panel(struct wlContextStruct *p_wlCtx, const uint32_t
>> id_surface,
>> + ? ? ? ? ? ? const char* imageFile)
>> +{
>> + ? ?create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
>> +}
>> +
>> +static void
>> +create_button(struct wlContextStruct *p_wlCtx, const uint32_t
>> id_surface,
>> + ? ? ? ? ? ? ?const char* imageFile, uint32_t number)
>> +{
>> + ? ?create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
>> +}
>> +
>> +static void
>> +create_home_button(struct wlContextStruct *p_wlCtx, const uint32_t
>> id_surface,
>> + ? ? ? ? ? ? ? ? ? const char* imageFile)
>> +{
>> + ? ?create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
>> +}
>> +
>> +static void
>> +create_workspace_background(
>> + ? ?struct wlContextStruct *p_wlCtx, struct hmi_homescreen_srf
>> *srf)
>> +{
>> + ? ?create_ivisurfaceFromColor(p_wlCtx, srf->id, 1, 1,
>> srf->color);
>> +}
>> +
>> +static void
>> +create_launchers(struct wlContextCommon *cmm, struct wl_list
>> *launcher_list)
>> +{
>> + ? ?int launcher_count = wl_list_length(launcher_list);
>> +
>> + ? ?if (0 == launcher_count) {
>> + ? ? ? ?return;
>> + ? ?}
>> +
>> + ? ?struct hmi_homescreen_launcher** launchers;
>> + ? ?launchers = MEM_ALLOC(launcher_count * sizeof(*launchers));
>> +
>> + ? ?int ii = 0;
>> + ? ?struct hmi_homescreen_launcher *launcher = NULL;
>> +
>> + ? ?wl_list_for_each(launcher, launcher_list, link) {
>> + ? ? ? ?launchers[ii] = launcher;
>> + ? ? ? ?ii++;
>> + ? ?}
>> +
>> + ? ?int start = 0;
>> +
>> + ? ?for (ii = 0; ii < launcher_count; ii++) {
>> +
>> + ? ? ? ?if (ii != launcher_count -1 &&
>> + ? ? ? ? ? ?launchers[ii]->workspace_id == launchers[ii +
>> 1]->workspace_id) {
>> + ? ? ? ? ? ?continue;
>> + ? ? ? ?}
>> +
>> + ? ? ? ?int jj = 0;
>> + ? ? ? ?for (jj = start; jj <= ii; jj++) {
>> + ? ? ? ? ? ?struct wlContextStruct *p_wlCtx =
>> MEM_ALLOC(sizeof(*p_wlCtx));
>> + ? ? ? ? ? ?p_wlCtx->cmm = *cmm;
>> + ? ? ? ? ?
>> ?create_ivisurfaceFromFile(p_wlCtx,launchers[jj]->icon_surface_id,
>> launchers[jj]->icon);
>> + ? ? ? ?}
>> +
>> + ? ? ? ?start = ii + 1;
>> + ? ?}
>> +
>> + ? ?free(launchers);
>> +}
>> +
>> +static void sigFunc(int signum)
>> +{
>> + ? ?gRun = 0;
>> +}
>> +
>> +/**
>> + * Internal method to read out weston.ini to get configuration
>> + */
>> +static struct hmi_homescreen_setting*
>> +hmi_homescreen_setting_create(void)
>> +{
>> + ? ?struct hmi_homescreen_setting* setting =
>> MEM_ALLOC(sizeof(*setting));
>> +
>> + ? ?wl_list_init(&setting->workspace_list);
>> + ? ?wl_list_init(&setting->launcher_list);
>> +
>> + ? ?struct weston_config *config = NULL;
>> + ? ?config = weston_config_parse("weston.ini");
>> +
>> + ? ?struct weston_config_section *shellSection = NULL;
>> + ? ?shellSection = weston_config_get_section(config,
>> "ivi-shell", NULL, NULL);
>> +
>> + ? ?weston_config_section_get_string(
>> + ? ? ? ? ? ?shellSection, "cursor-theme",
>> &setting->cursor_theme, NULL);
>> +
>> + ? ?weston_config_section_get_int(shellSection, "cursor-size",
>> &setting->cursor_size, 32);
>> +
>> + ? ?uint32_t workspace_layer_id;
>> + ? ?weston_config_section_get_uint(
>> + ? ? ? ?shellSection, "workspace-layer-id",
>> &workspace_layer_id, 3000);
>> +
>> + ? ?weston_config_section_get_string(
>> + ? ? ? ?shellSection, "background-image",
>> &setting->background.filePath,
>> + ? ? ? ?DATADIR "/weston/background.png");
>> +
>> + ? ?weston_config_section_get_uint(
>> + ? ? ? ?shellSection, "background-id", &setting->background.id
>> [9], 1001);
>> +
>> + ? ?weston_config_section_get_string(
>> + ? ? ? ?shellSection, "panel-image", &setting->panel.filePath,
>> + ? ? ? ?DATADIR "/weston/panel.png");
>> +
>> + ? ?weston_config_section_get_uint(
>> + ? ? ? ?shellSection, "panel-id", &setting->panel.id [10],
>> 1002);
>> +
>> + ? ?weston_config_section_get_string(
>> + ? ? ? ?shellSection, "tiling-image",
>> &setting->tiling.filePath,
>> + ? ? ? ?DATADIR "/weston/tiling.png");
>> +
>> + ? ?weston_config_section_get_uint(
>> + ? ? ? ?shellSection, "tiling-id", &setting->tiling.id [3],
>> 1003);
>> +
>> + ? ?weston_config_section_get_string(
>> + ? ? ? ?shellSection, "sidebyside-image",
>> &setting->sidebyside.filePath,
>> + ? ? ? ?DATADIR "/weston/sidebyside.png");
>> +
>> + ? ?weston_config_section_get_uint(
>> + ? ? ? ?shellSection, "sidebyside-id", &setting->sidebyside.id
>> [4], 1004);
>> +
>> + ? ?weston_config_section_get_string(
>> + ? ? ? ?shellSection, "fullscreen-image",
>> &setting->fullscreen.filePath,
>> + ? ? ? ?DATADIR "/weston/fullscreen.png");
>> +
>> + ? ?weston_config_section_get_uint(
>> + ? ? ? ?shellSection, "fullscreen-id", &setting->fullscreen.id
>> [5], 1005);
>> +
>> + ? ?weston_config_section_get_string(
>> + ? ? ? ?shellSection, "random-image",
>> &setting->random.filePath,
>> + ? ? ? ?DATADIR "/weston/random.png");
>> +
>> + ? ?weston_config_section_get_uint(
>> + ? ? ? ?shellSection, "random-id", &setting->random.id [6],
>> 1006);
>> +
>> + ? ?weston_config_section_get_string(
>> + ? ? ? ?shellSection, "home-image", &setting->home.filePath,
>> + ? ? ? ?DATADIR "/weston/home.png");
>> +
>> + ? ?weston_config_section_get_uint(
>> + ? ? ? ?shellSection, "home-id", &setting->home.id [7], 1007);
>> +
>> + ? ?weston_config_section_get_uint(
>> + ? ? ? ?shellSection, "workspace-background-color",
>> + ? ? ? ?&setting->workspace_background.color, 0x99000000);
>> +
>> + ? ?weston_config_section_get_uint(
>> + ? ? ? ?shellSection, "workspace-background-id",
>> + ? ? ? ?&setting->workspace_background.id [2], 2001);
>> +
>> + ? ?struct weston_config_section *section = NULL;
>> + ? ?const char *name = NULL;
>> +
>> + ? ?uint32_t icon_surface_id = workspace_layer_id + 1;
>> +
>> + ? ?while (weston_config_next_section(config, &section, &name))
>> {
>> +
>> + ? ? ? ?if (0 == strcmp(name, "ivi-launcher")) {
>> +
>> + ? ? ? ? ? ?struct hmi_homescreen_launcher *launcher = NULL;
>> + ? ? ? ? ? ?launcher = MEM_ALLOC(sizeof(*launcher));
>> + ? ? ? ? ? ?wl_list_init(&launcher->link);
>> +
>> + ? ? ? ? ? ?weston_config_section_get_string(section,
>> "icon", &launcher->icon, NULL);
>> + ? ? ? ? ? ?weston_config_section_get_string(section,
>> "path", &launcher->path, NULL);
>> + ? ? ? ? ? ?weston_config_section_get_uint(section,
>> "workspace-id", &launcher->workspace_id, 0);
>> + ? ? ? ? ? ?weston_config_section_get_uint(section,
>> "icon-id", &launcher->icon_surface_id, icon_surface_id);
>> + ? ? ? ? ? ?icon_surface_id++;
>> +
>> + ? ? ? ? ? ?wl_list_insert(setting->launcher_list.prev,
>> &launcher->link);
>> + ? ? ? ?}
>> + ? ?}
>> +
>> + ? ?weston_config_destroy(config);
>> + ? ?return setting;
>> +}
>> +
>> +/**
>> + * Main thread
>> + *
>> + * The basic flow are as followed,
>> + * 1/ read configuration from weston.ini by
>> hmi_homescreen_setting_create
>> + * 2/ draw png file to surface according to configuration of
>> weston.ini and
>> + * ? ?set up UI by using ivi-hmi-controller protocol by each
>> create_* method
>> + */
>> +int main(int argc, char **argv)
>> +{
>> + ? ?struct wlContextCommon wlCtxCommon;
>> + ? ?struct wlContextStruct wlCtx_BackGround;
>> + ? ?struct wlContextStruct wlCtx_Panel;
>> + ? ?struct wlContextStruct wlCtx_Button_1;
>> + ? ?struct wlContextStruct wlCtx_Button_2;
>> + ? ?struct wlContextStruct wlCtx_Button_3;
>> + ? ?struct wlContextStruct wlCtx_Button_4;
>> + ? ?struct wlContextStruct wlCtx_HomeButton;
>> + ? ?struct wlContextStruct wlCtx_WorkSpaceBackGround;
>> + ? ?struct wl_list ? ? ? ? launcher_wlCtxList;
>> +
>> + ? ?memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon));
>> + ? ?memset(&wlCtx_BackGround, 0x00, sizeof(wlCtx_BackGround));
>> + ? ?memset(&wlCtx_Panel, ? ? ?0x00, sizeof(wlCtx_Panel));
>> + ? ?memset(&wlCtx_Button_1, ? 0x00, sizeof(wlCtx_Button_1));
>> + ? ?memset(&wlCtx_Button_2, ? 0x00, sizeof(wlCtx_Button_2));
>> + ? ?memset(&wlCtx_Button_3, ? 0x00, sizeof(wlCtx_Button_3));
>> + ? ?memset(&wlCtx_Button_4, ? 0x00, sizeof(wlCtx_Button_4));
>> + ? ?memset(&wlCtx_HomeButton, 0x00, sizeof(wlCtx_HomeButton));
>> + ? ?memset(&wlCtx_WorkSpaceBackGround, 0x00,
>> sizeof(wlCtx_WorkSpaceBackGround));
>> + ? ?wl_list_init(&launcher_wlCtxList);
>> + ? ?wlCtxCommon.list_wlContextStruct = MEM_ALLOC(sizeof(struct
>> wl_list));
>> + ? ?assert(wlCtxCommon.list_wlContextStruct);
>> + ? ?wl_list_init(wlCtxCommon.list_wlContextStruct);
>> +
>> + ? ?struct hmi_homescreen_setting *hmi_setting =
>> hmi_homescreen_setting_create();
>> + ? ?wlCtxCommon.hmi_setting = hmi_setting;
>> +
>> + ? ?gRun = 1;
>> +
>> + ? ?wlCtxCommon.wlDisplay = wl_display_connect(NULL);
>> + ? ?if (NULL == wlCtxCommon.wlDisplay) {
>> + ? ? ? ?printf("Error: wl_display_connect failed.n");
>> + ? ? ? ?return -1;
>> + ? ?}
>> +
>> + ? ?/* get wl_registry */
>> + ? ?wlCtxCommon.wlRegistry =
>> wl_display_get_registry(wlCtxCommon.wlDisplay);
>> + ? ?wl_registry_add_listener(wlCtxCommon.wlRegistry,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? &registry_listener,
>> &wlCtxCommon);
>> + ? ?wl_display_dispatch(wlCtxCommon.wlDisplay);
>> + ? ?wl_display_roundtrip(wlCtxCommon.wlDisplay);
>> +
>> + ? ?if (wlCtxCommon.hmi_setting->cursor_theme) {
>> + ? ? ? ?create_cursors(&wlCtxCommon);
>> +
>> + ? ? ? ?wlCtxCommon.pointer_surface =
>> + ? ? ? ? ?
>> ?wl_compositor_create_surface(wlCtxCommon.wlCompositor);
>> +
>> + ? ? ? ?wlCtxCommon.current_cursor = CURSOR_LEFT_PTR;
>> + ? ?}
>> +
>> + ? ?wlCtx_BackGround.cmm = wlCtxCommon;
>> + ? ?wlCtx_Panel.cmm ? ? ?= wlCtxCommon;
>> + ? ?wlCtx_Button_1.cmm ? = wlCtxCommon;
>> + ? ?wlCtx_Button_2.cmm ? = wlCtxCommon;
>> + ? ?wlCtx_Button_3.cmm ? = wlCtxCommon;
>> + ? ?wlCtx_Button_4.cmm ? = wlCtxCommon;
>> + ? ?wlCtx_HomeButton.cmm = wlCtxCommon;
>> + ? ?wlCtx_WorkSpaceBackGround.cmm = wlCtxCommon;
>> +
>> + ? ?/* create desktop widgets */
>> + ? ?create_background(&wlCtx_BackGround,
>> hmi_setting->background.id [9],
>> + ? ? ? ? ? ? ? ? ? ?
>> ?hmi_setting->background.filePath);
>> +
>> + ? ?create_panel(&wlCtx_Panel, hmi_setting->panel.id [10],
>> + ? ? ? ? ? ? ? ? hmi_setting->panel.filePath);
>> +
>> + ? ?create_button(&wlCtx_Button_1, hmi_setting->tiling.id [3],
>> + ? ? ? ? ? ? ? ? ?hmi_setting->tiling.filePath, 0);
>> +
>> + ? ?create_button(&wlCtx_Button_2, hmi_setting->sidebyside.id
>> [4],
>> + ? ? ? ? ? ? ? ? ?hmi_setting->sidebyside.filePath, 1);
>> +
>> + ? ?create_button(&wlCtx_Button_3, hmi_setting->fullscreen.id
>> [5],
>> + ? ? ? ? ? ? ? ? ?hmi_setting->fullscreen.filePath, 2);
>> +
>> + ? ?create_button(&wlCtx_Button_4, hmi_setting->random.id [6],
>> + ? ? ? ? ? ? ? ? ?hmi_setting->random.filePath, 3);
>> +
>> + ? ?create_workspace_background(&wlCtx_WorkSpaceBackGround,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
>> ?&hmi_setting->workspace_background);
>> +
>> + ? ?create_launchers(&wlCtxCommon, &hmi_setting->launcher_list);
>> +
>> + ? ?create_home_button(&wlCtx_HomeButton, hmi_setting->home.id
>> [7],
>> + ? ? ? ? ? ? ? ? ? ? ? hmi_setting->home.filePath);
>> +
>> + ? ?UI_ready(wlCtxCommon.hmiCtrl);
>> +
>> + ? ?/* signal handling */
>> + ? ?signal(SIGINT, ?sigFunc);
>> + ? ?signal(SIGKILL, sigFunc);
>> +
>> + ? ?while(gRun) {
>> + ? ? ? ?wl_display_dispatch(wlCtxCommon.wlDisplay);
>> + ? ?}
>> +
>> + ? ?struct wlContextStruct* pWlCtxSt = NULL;
>> + ? ?wl_list_for_each(pWlCtxSt, wlCtxCommon.list_wlContextStruct,
>> link) {
>> + ? ? ? ?destroyWLContextStruct(pWlCtxSt);
>> + ? ?}
>> +
>> + ? ?destroyWLContextCommon(&wlCtxCommon);
>> + ? ?free(wlCtxCommon.list_wlContextStruct);
>> +
>> + ? ?return 0;
>> +}
>> diff --git a/ivi-shell/hmi-controller.c
>> b/ivi-shell/hmi-controller.c
>> index 4e4e7c0..86db700 100644
>> --- a/ivi-shell/hmi-controller.c
>> +++ b/ivi-shell/hmi-controller.c
>> @@ -134,6 +134,7 @@ hmi_server_setting {
>> ? ? ?uint32_t ? ?workspace_background_layer_id;
>> ? ? ?uint32_t ? ?workspace_layer_id;
>> ? ? ?uint32_t ? ?panel_height;
>> + ? ?char ? ? ? *ivi_homescreen;
>> ?};
>>
>> ?struct hmi_controller
>> @@ -151,6 +152,10 @@ struct hmi_controller
>> ? ? ?int32_t ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
>> workspace_count;
>> ? ? ?struct wl_array ? ? ? ? ? ? ? ? ? ? ui_widgets;
>> ? ? ?int32_t ? ? ? ? ? ? ? ? ? ? ? ? ? ?
>> is_initialized;
>> +
>> + ? ?struct weston_compositor ? ? ? ? ? *compositor;
>> + ? ?struct weston_process ? ? ? ? ? ? ? process;
>> + ? ?struct wl_listener ? ? ? ? ? ? ? ?
>> ?destroy_listener;
>> ?};
>>
>> ?struct launcher_info
>> @@ -830,6 +835,9 @@ hmi_server_setting_create(void)
>>
>> ? ? ?setting->panel_height = 70;
>>
>> + ? ?weston_config_section_get_string(
>> + ? ? ? ? ? ?shellSection, "ivi-shell-user-interface",
>> &setting->ivi_homescreen, NULL);
>> +
>> ? ? ?weston_config_destroy(config);
>>
>> ? ? ?return setting;
>> @@ -1896,9 +1904,36 @@ bind_hmi_controller(struct wl_client
>> *client,
>> ?}
>>
>> ?static void
>> -launch_hmi_client(void *data)
>> +handle_hmi_client_process_sigchld(struct weston_process *proc, int
>> status)
>> +{
>> + ? ?proc->pid = 0;
>> +}
>> +
>> +static void
>> +hmi_client_destroy(struct wl_listener *listener, void *data)
>> +{
>> + ? ?struct hmi_controller *hmi_ctrl =
>> + ? ? ? ?container_of(listener, struct hmi_controller,
>> destroy_listener);
>> +
>> + ? ?kill(hmi_ctrl->process.pid, SIGTERM);
>> + ? ?hmi_ctrl->process.pid = 0;
>> +}
>> +
>> +static void
>> +launch_hmi_client_process(void *data)
>> ?{
>> - ? ?/*Nothing to do here*/
>> + ? ?struct hmi_controller *hmi_ctrl =
>> + ? ? ? ?(struct hmi_controller *)data;
>> +
>> + ? ?weston_client_launch(hmi_ctrl->compositor,
>> + ? ? ? ? ? ? ? ? ? ? ? ? &hmi_ctrl->process,
>> + ? ? ? ? ? ? ? ? ? ? ? ?
>> hmi_ctrl->hmi_setting->ivi_homescreen,
>> + ? ? ? ? ? ? ? ? ? ? ? ?
>> handle_hmi_client_process_sigchld);
>> +
>> + ? ?hmi_ctrl->destroy_listener.notify = hmi_client_destroy;
>> + ? ?wl_signal_add(&hmi_ctrl->compositor->destroy_signal,
>> &hmi_ctrl->destroy_listener);
>> +
>> + ? ?free(hmi_ctrl->hmi_setting->ivi_homescreen);
>> ?}
>>
>>
> ?/*****************************************************************************
>> @@ -1910,6 +1945,7 @@ module_init(struct weston_compositor *ec,
>> ? ? ? ? ? ? ?int *argc, char *argv[])
>> ?{
>> ? ? ?struct hmi_controller *hmi_ctrl =
>> hmi_controller_create(ec);
>> + ? ?hmi_ctrl->compositor = ec;
>>
>> ? ? ?if (wl_global_create(ec->wl_display,
>> ? ? ? ? ? ? ? ? ? &ivi_hmi_controller_interface, 1,
>> @@ -1918,7 +1954,7 @@ module_init(struct weston_compositor *ec,
>> ? ? ?}
>>
>> ? ? ?struct wl_event_loop *loop =
>> wl_display_get_event_loop(ec->wl_display);
>> - ? ?wl_event_loop_add_idle(loop, launch_hmi_client, ec);
>> + ? ?wl_event_loop_add_idle(loop, launch_hmi_client_process,
>> hmi_ctrl);
>>
>> ? ? ?return 0;
>> ?}
>> --
>> 1.8.3.1
>>
>> _______________________________________________
>> wayland-devel mailing list
>> wayland-devel at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/wayland-devel [11]
>
> --
>
> Regards,
>
> MANUEL BACHMANN
> Tizen Project
> VANNES-FR
>
>
> Links:
> ------
> [1] http://libtoytoolkit.la
> [2] http://workspace_background.id
> [3] http://tiling.id
> [4] http://sidebyside.id
> [5] http://fullscreen.id
> [6] http://random.id
> [7] http://home.id
> [8] https://bugs.kde.org/attachment.cgi?id=67313
> [9] http://background.id
> [10] http://panel.id
> [11] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Nobuhiko Tanibata
2014-05-20 04:30:47 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3, v4, and v5:
- nothing. Version number aligned to the first patch

data/Makefile.am | 14 +++++++++++++-
data/background.png | Bin 0 -> 245579 bytes
data/fullscreen.png | Bin 0 -> 3406 bytes
data/home.png | Bin 0 -> 4629 bytes
data/icon_ivi_clickdot.png | Bin 0 -> 39523 bytes
data/icon_ivi_flower.png | Bin 0 -> 24475 bytes
data/icon_ivi_simple-egl.png | Bin 0 -> 29316 bytes
data/icon_ivi_simple-shm.png | Bin 0 -> 71120 bytes
data/icon_ivi_smoke.png | Bin 0 -> 46577 bytes
data/panel.png | Bin 0 -> 41955 bytes
data/random.png | Bin 0 -> 4891 bytes
data/sidebyside.png | Bin 0 -> 3929 bytes
data/tiling.png | Bin 0 -> 5620 bytes
13 files changed, 13 insertions(+), 1 deletion(-)
create mode 100644 data/background.png
create mode 100644 data/fullscreen.png
create mode 100644 data/home.png
create mode 100644 data/icon_ivi_clickdot.png
create mode 100644 data/icon_ivi_flower.png
create mode 100644 data/icon_ivi_simple-egl.png
create mode 100644 data/icon_ivi_simple-shm.png
create mode 100644 data/icon_ivi_smoke.png
create mode 100644 data/panel.png
create mode 100644 data/random.png
create mode 100644 data/sidebyside.png
create mode 100644 data/tiling.png

--
1.8.3.1
Nobuhiko Tanibata
2014-05-20 04:35:28 UTC
Permalink
Hi,

I removed binary from patch as review comment.
Image files can be downloaded from,
https://github.com/ntanibata/weston-ivi-shell/tree/weston-ivi-shell-1.4.93-v3/data

BR,
Nobuhiko

2014-05-20 13:30 ? Nobuhiko Tanibata ????????:
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - squash Makefile to this patch
>
> Changes for v3, v4, and v5:
> - nothing. Version number aligned to the first patch
>
> data/Makefile.am | 14 +++++++++++++-
> data/background.png | Bin 0 -> 245579 bytes
> data/fullscreen.png | Bin 0 -> 3406 bytes
> data/home.png | Bin 0 -> 4629 bytes
> data/icon_ivi_clickdot.png | Bin 0 -> 39523 bytes
> data/icon_ivi_flower.png | Bin 0 -> 24475 bytes
> data/icon_ivi_simple-egl.png | Bin 0 -> 29316 bytes
> data/icon_ivi_simple-shm.png | Bin 0 -> 71120 bytes
> data/icon_ivi_smoke.png | Bin 0 -> 46577 bytes
> data/panel.png | Bin 0 -> 41955 bytes
> data/random.png | Bin 0 -> 4891 bytes
> data/sidebyside.png | Bin 0 -> 3929 bytes
> data/tiling.png | Bin 0 -> 5620 bytes
> 13 files changed, 13 insertions(+), 1 deletion(-)
> create mode 100644 data/background.png
> create mode 100644 data/fullscreen.png
> create mode 100644 data/home.png
> create mode 100644 data/icon_ivi_clickdot.png
> create mode 100644 data/icon_ivi_flower.png
> create mode 100644 data/icon_ivi_simple-egl.png
> create mode 100644 data/icon_ivi_simple-shm.png
> create mode 100644 data/icon_ivi_smoke.png
> create mode 100644 data/panel.png
> create mode 100644 data/random.png
> create mode 100644 data/sidebyside.png
> create mode 100644 data/tiling.png
Manuel Bachmann
2014-06-25 09:48:15 UTC
Permalink
Hello Tanibata-San,

I think your forget to include the changes to "Makefile.am" in this series.
What is more, as Weston has now a unique "Makefile.am" in the root directory

I modified the patch this way :

--- a/Makefile.am
+++ b/Makefile.am
@@ -638,7 +638,19 @@ dist_westondata_DATA = \
data/icon_window.png \
data/sign_close.png \
data/sign_maximize.png \
- data/sign_minimize.png
+ data/sign_minimize.png \
+ data/background.png \
+ data/tiling.png \
+ data/fullscreen.png \
+ data/panel.png \
+ data/random.png \
+ data/sidebyside.png \
+ data/home.png \
+ data/icon_ivi_clickdot.png \
+ data/icon_ivi_flower.png \
+ data/icon_ivi_simple-egl.png \
+ data/icon_ivi_simple-shm.png \
+ data/icon_ivi_smoke.png

Hope this helps !

Regards,


2014-05-20 6:35 GMT+02:00 Nobuhiko Tanibata <
nobuhiko_tanibata at xddp.denso.co.jp>:

> Hi,
>
> I removed binary from patch as review comment.
> Image files can be downloaded from,
> https://github.com/ntanibata/weston-ivi-shell/tree/weston-
> ivi-shell-1.4.93-v3/data
>
> BR,
> Nobuhiko
>
> 2014-05-20 13:30 ? Nobuhiko Tanibata ????????:
>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2:
>> - squash Makefile to this patch
>>
>> Changes for v3, v4, and v5:
>> - nothing. Version number aligned to the first patch
>>
>> data/Makefile.am | 14 +++++++++++++-
>> data/background.png | Bin 0 -> 245579 bytes
>> data/fullscreen.png | Bin 0 -> 3406 bytes
>> data/home.png | Bin 0 -> 4629 bytes
>> data/icon_ivi_clickdot.png | Bin 0 -> 39523 bytes
>> data/icon_ivi_flower.png | Bin 0 -> 24475 bytes
>> data/icon_ivi_simple-egl.png | Bin 0 -> 29316 bytes
>> data/icon_ivi_simple-shm.png | Bin 0 -> 71120 bytes
>> data/icon_ivi_smoke.png | Bin 0 -> 46577 bytes
>> data/panel.png | Bin 0 -> 41955 bytes
>> data/random.png | Bin 0 -> 4891 bytes
>> data/sidebyside.png | Bin 0 -> 3929 bytes
>> data/tiling.png | Bin 0 -> 5620 bytes
>> 13 files changed, 13 insertions(+), 1 deletion(-)
>> create mode 100644 data/background.png
>> create mode 100644 data/fullscreen.png
>> create mode 100644 data/home.png
>> create mode 100644 data/icon_ivi_clickdot.png
>> create mode 100644 data/icon_ivi_flower.png
>> create mode 100644 data/icon_ivi_simple-egl.png
>> create mode 100644 data/icon_ivi_simple-shm.png
>> create mode 100644 data/icon_ivi_smoke.png
>> create mode 100644 data/panel.png
>> create mode 100644 data/random.png
>> create mode 100644 data/sidebyside.png
>> create mode 100644 data/tiling.png
>>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>



--
Regards,



*Manuel BACHMANN Tizen Project VANNES-FR*
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20140625/78a7b733/attachment.html>
Nobuhiko Tanibata
2014-06-25 11:38:21 UTC
Permalink
Hi Manuel,

Thank you!
I will resend my patches.

BR,
Nobuhiko

2014-06-25 18:48 ? Manuel Bachmann ????????:
> Hello Tanibata-San,
>
> I think your forget to include the changes to "Makefile.am" in this
> series. What is more, as Weston has now a unique "Makefile.am" in the
> root directory
>
> I modified the patch this way :
>
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -638,7 +638,19 @@ dist_westondata_DATA
> =????????????????????????????
> ???????
> data/icon_window.png???????????????????
> ???????
> data/sign_close.png????????????????????
> ???????
> data/sign_maximize.png?????????????????
> -?????? data/sign_minimize.png
> +?????? data/sign_minimize.png?????????????????
>
> +??????
> data/background.png????????????????????
> +??????
> data/tiling.png????????????????????????
> +??????
> data/fullscreen.png????????????????????
> +??????
> data/panel.png?????????????????????????
> +??????
> data/random.png????????????????????????
> +??????
> data/sidebyside.png????????????????????
> +??????
> data/home.png??????????????????????????
> +?????? data/icon_ivi_clickdot.png?????????????
> +?????? data/icon_ivi_flower.png???????????????
> +?????? data/icon_ivi_simple-egl.png???????????
> +?????? data/icon_ivi_simple-shm.png???????????
> +?????? data/icon_ivi_smoke.png
>
> Hope this helps !
>
> Regards,
>
> 2014-05-20 6:35 GMT+02:00 Nobuhiko Tanibata
> <nobuhiko_tanibata at xddp.denso.co.jp>:
>
>> Hi,
>>
>> I removed binary from patch as review comment.
>> Image files can be downloaded from,
>>
> https://github.com/ntanibata/weston-ivi-shell/tree/weston-ivi-shell-1.4.93-v3/data
>> [1]
>>
>> BR,
>> Nobuhiko
>>
>> 2014-05-20 13:30 ? Nobuhiko Tanibata ????????:
>>
>>> Signed-off-by: Nobuhiko Tanibata
>>> <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>>> ---
>>>
>>> Changes for v2:
>>> ?- squash Makefile to this patch
>>>
>>> Changes for v3, v4, and v5:
>>> ?- nothing. Version number aligned to the first patch
>>>
>>> ?data/Makefile.am ? ? ? ? ? ? | ?14 +++++++++++++-
>>> ?data/background.png ? ? ? ? ?| Bin 0 -> 245579 bytes
>>> ?data/fullscreen.png ? ? ? ? ?| Bin 0 -> 3406 bytes
>>> ?data/home.png ? ? ? ? ? ? ? ?| Bin 0 -> 4629 bytes
>>> ?data/icon_ivi_clickdot.png ? | Bin 0 -> 39523 bytes
>>> ?data/icon_ivi_flower.png ? ? | Bin 0 -> 24475 bytes
>>> ?data/icon_ivi_simple-egl.png | Bin 0 -> 29316 bytes
>>> ?data/icon_ivi_simple-shm.png | Bin 0 -> 71120 bytes
>>> ?data/icon_ivi_smoke.png ? ? ?| Bin 0 -> 46577 bytes
>>> ?data/panel.png ? ? ? ? ? ? ? | Bin 0 -> 41955 bytes
>>> ?data/random.png ? ? ? ? ? ? ?| Bin 0 -> 4891 bytes
>>> ?data/sidebyside.png ? ? ? ? ?| Bin 0 -> 3929 bytes
>>> ?data/tiling.png ? ? ? ? ? ? ?| Bin 0 -> 5620 bytes
>>> ?13 files changed, 13 insertions(+), 1 deletion(-)
>>> ?create mode 100644 data/background.png
>>> ?create mode 100644 data/fullscreen.png
>>> ?create mode 100644 data/home.png
>>> ?create mode 100644 data/icon_ivi_clickdot.png
>>> ?create mode 100644 data/icon_ivi_flower.png
>>> ?create mode 100644 data/icon_ivi_simple-egl.png
>>> ?create mode 100644 data/icon_ivi_simple-shm.png
>>> ?create mode 100644 data/icon_ivi_smoke.png
>>> ?create mode 100644 data/panel.png
>>> ?create mode 100644 data/random.png
>>> ?create mode 100644 data/sidebyside.png
>>> ?create mode 100644 data/tiling.png
>>
>> _______________________________________________
>> wayland-devel mailing list
>> wayland-devel at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/wayland-devel [2]
>
> --
>
> Regards,
>
> MANUEL BACHMANN
> Tizen Project
> VANNES-FR
>
>
> Links:
> ------
> [1]
> https://github.com/ntanibata/weston-ivi-shell/tree/weston-ivi-shell-1.4.93-v3/data
> [2] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Nobuhiko Tanibata
2014-05-20 04:31:12 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4:
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch

Makefile.am | 13 +++++--
ivi-shell/weston.ini.in | 91 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 101 insertions(+), 3 deletions(-)
create mode 100644 ivi-shell/weston.ini.in

diff --git a/Makefile.am b/Makefile.am
index 46c5e3d..c4fca52 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,7 +8,7 @@ BUILT_SOURCES =

DISTCHECK_CONFIGURE_FLAGS = --disable-setuid-install

-EXTRA_DIST = weston.ini.in
+EXTRA_DIST = weston.ini.in ivi-shell/weston.ini.in

weston.ini : $(srcdir)/weston.ini.in
$(AM_V_GEN)$(SED) \
@@ -17,7 +17,14 @@ weston.ini : $(srcdir)/weston.ini.in
-e 's|@libexecdir[@]|$(libexecdir)|g' \
$< > $@

-all-local : weston.ini
+ivi-shell/weston.ini : $(srcdir)/ivi-shell/weston.ini.in
+ $(AM_V_GEN)$(SED) \
+ -e 's|@bindir[@]|$(bindir)|g' \
+ -e 's|@abs_top_builddir[@]|$(abs_top_builddir)|g' \
+ -e 's|@libexecdir[@]|$(libexecdir)|g' \
+ $< > $@
+
+all-local : weston.ini ivi-shell/weston.ini

AM_CFLAGS = $(GCC_CFLAGS)

@@ -33,7 +40,7 @@ AM_CPPFLAGS = \
-DLIBEXECDIR='"$(libexecdir)"' \
-DBINDIR='"$(bindir)"'

-CLEANFILES = weston.ini $(BUILT_SOURCES)
+CLEANFILES = weston.ini ivi-shell/weston.ini $(BUILT_SOURCES)

bin_PROGRAMS += weston

diff --git a/ivi-shell/weston.ini.in b/ivi-shell/weston.ini.in
new file mode 100644
index 0000000..3c9fb6a
--- /dev/null
+++ b/ivi-shell/weston.ini.in
@@ -0,0 +1,91 @@
+[core]
+shell=ivi-shell.so
+
+[ivi-shell]
+ivi-module=hmi-controller.so
+ivi-shell-user-interface=@abs_top_builddir@/weston-ivi-shell-user-interface
+
+cursor-theme=default
+cursor-size=32
+
+base-layer-id=1000
+workspace-background-layer-id=2000
+workspace-layer-id=3000
+application-layer-id=4000
+
+background-image=@abs_top_builddir@/data/background.png
+background-id=1001
+panel-image=@abs_top_builddir@/data/panel.png
+panel-id=1002
+tiling-image=@abs_top_builddir@/data/tiling.png
+tiling-id=1003
+sidebyside-image=@abs_top_builddir@/data/sidebyside.png
+sidebyside-id=1004
+fullscreen-image=@abs_top_builddir@/data/fullscreen.png
+fullscreen-id=1005
+random-image=@abs_top_builddir@/data/random.png
+random-id=1006
+home-image=@abs_top_builddir@/data/home.png
+home-id=1007
+workspace-background-color=0x99000000
+workspace-background-id=2001
+
+[ivi-launcher]
+workspace-id=0
+icon-id=4001
+icon=@abs_top_builddir@/data/icon_ivi_flower.png
+path=@abs_top_builddir@/clients/weston-flower
+
+[ivi-launcher]
+workspace-id=0
+icon-id=4002
+icon=@abs_top_builddir@/data/icon_ivi_clickdot.png
+path=@abs_top_builddir@/clients/weston-clickdot
+
+[ivi-launcher]
+workspace-id=1
+icon-id=4003
+icon=@abs_top_builddir@/data/icon_ivi_simple-egl.png
+path=@abs_top_builddir@/clients/weston-simple-egl
+
+[ivi-launcher]
+workspace-id=1
+icon-id=4004
+icon=@abs_top_builddir@/data/icon_ivi_simple-shm.png
+path=@abs_top_builddir@/clients/weston-simple-shm
+
+[ivi-launcher]
+workspace-id=2
+icon-id=4005
+icon=@abs_top_builddir@/data/icon_ivi_smoke.png
+path=@abs_top_builddir@/clients/weston-smoke
+
+[ivi-launcher]
+workspace-id=3
+icon-id=4006
+icon=@abs_top_builddir@/data/icon_ivi_flower.png
+path=@abs_top_builddir@/clients/weston-flower
+
+[ivi-launcher]
+workspace-id=3
+icon-id=4007
+icon=@abs_top_builddir@/data/icon_ivi_clickdot.png
+path=@abs_top_builddir@/clients/weston-clickdot
+
+[ivi-launcher]
+workspace-id=3
+icon-id=4008
+icon=@abs_top_builddir@/data/icon_ivi_simple-egl.png
+path=@abs_top_builddir@/clients/weston-simple-egl
+
+[ivi-launcher]
+workspace-id=3
+icon-id=4009
+icon=@abs_top_builddir@/data/icon_ivi_simple-shm.png
+path=@abs_top_builddir@/clients/weston-simple-shm
+
+[ivi-launcher]
+workspace-id=3
+icon-id=4010
+icon=@abs_top_builddir@/data/icon_ivi_smoke.png
+path=@abs_top_builddir@/clients/weston-smoke
--
1.8.3.1
Nobuhiko Tanibata
2014-05-20 04:31:35 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2, v3 and v4:
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- remove Macros to enable ivi-application

Makefile.am | 12 ++++++--
clients/simple-egl.c | 70 +++++++++++++++++++++++++++++++++++--------
clients/simple-shm.c | 34 ++++++++++++++++++++-
clients/window.c | 84 ++++++++++++++++++++++++++++++++++++++--------------
4 files changed, 161 insertions(+), 39 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index c4fca52..49c9519 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -402,7 +402,9 @@ nodist_weston_simple_shm_SOURCES = \
protocol/xdg-shell-protocol.c \
protocol/xdg-shell-client-protocol.h \
protocol/fullscreen-shell-protocol.c \
- protocol/fullscreen-shell-client-protocol.h
+ protocol/fullscreen-shell-client-protocol.h \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-client-protocol.h
weston_simple_shm_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS)
weston_simple_shm_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la

@@ -420,7 +422,9 @@ demo_clients += weston-simple-egl
weston_simple_egl_SOURCES = clients/simple-egl.c
nodist_weston_simple_egl_SOURCES = \
protocol/xdg-shell-protocol.c \
- protocol/xdg-shell-client-protocol.h
+ protocol/xdg-shell-client-protocol.h \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-client-protocol.h
weston_simple_egl_CFLAGS = $(AM_CFLAGS) $(SIMPLE_EGL_CLIENT_CFLAGS)
weston_simple_egl_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
endif
@@ -439,7 +443,9 @@ nodist_libtoytoolkit_la_SOURCES = \
protocol/workspaces-protocol.c \
protocol/workspaces-client-protocol.h \
protocol/xdg-shell-protocol.c \
- protocol/xdg-shell-client-protocol.h
+ protocol/xdg-shell-client-protocol.h \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-client-protocol.h

BUILT_SOURCES += $(nodist_libtoytoolkit_la_SOURCES)

diff --git a/clients/simple-egl.c b/clients/simple-egl.c
index 0d4673b..92f2dc2 100644
--- a/clients/simple-egl.c
+++ b/clients/simple-egl.c
@@ -41,6 +41,10 @@
#include <EGL/eglext.h>

#include "xdg-shell-client-protocol.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include "protocol/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000

#ifndef EGL_EXT_swap_buffers_with_damage
#define EGL_EXT_swap_buffers_with_damage 1
@@ -74,6 +78,7 @@ struct display {
EGLConfig conf;
} egl;
struct window *window;
+ struct ivi_application *ivi_application;

PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
};
@@ -95,6 +100,7 @@ struct window {
struct wl_egl_window *native;
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
+ struct ivi_surface *ivi_surface;
EGLSurface egl_surface;
struct wl_callback *callback;
int fullscreen, opaque, buffer_size, frame_sync;
@@ -254,7 +260,7 @@ init_gl(struct window *window)
}

glUseProgram(program);
-
+
window->gl.pos = 0;
window->gl.col = 1;

@@ -333,13 +339,8 @@ create_surface(struct window *window)
{
struct display *display = window->display;
EGLBoolean ret;
-
- window->surface = wl_compositor_create_surface(display->compositor);
- window->xdg_surface = xdg_shell_get_xdg_surface(display->shell,
- window->surface);

- xdg_surface_add_listener(window->xdg_surface,
- &xdg_surface_listener, window);
+ window->surface = wl_compositor_create_surface(display->compositor);

window->native =
wl_egl_window_create(window->surface,
@@ -350,7 +351,28 @@ create_surface(struct window *window)
display->egl.conf,
window->native, NULL);

- xdg_surface_set_title(window->xdg_surface, "simple-egl");
+ if (display->shell) {
+ window->xdg_surface = xdg_shell_get_xdg_surface(display->shell,
+ window->surface);
+
+ xdg_surface_add_listener(window->xdg_surface,
+ &xdg_surface_listener, window);
+
+ xdg_surface_set_title(window->xdg_surface, "simple-egl");
+ } else if (display->ivi_application ) {
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ window->ivi_surface =
+ ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ handle_surface_configure(window, NULL, 250, 250);
+
+ if (window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+ } else {
+ assert(0);
+ }

ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
window->egl_surface, window->display->egl.ctx);
@@ -359,9 +381,12 @@ create_surface(struct window *window)
if (!window->frame_sync)
eglSwapInterval(display->egl.dpy, 0);

- xdg_surface_request_change_state(window->xdg_surface,
- XDG_SURFACE_STATE_FULLSCREEN,
- window->fullscreen, 0);
+ if (display->shell)
+ {
+ xdg_surface_request_change_state(window->xdg_surface,
+ XDG_SURFACE_STATE_FULLSCREEN,
+ window->fullscreen, 0);
+ }
}

static void
@@ -536,8 +561,13 @@ pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
struct display *display = data;

if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
- xdg_surface_move(display->window->xdg_surface,
- display->seat, serial);
+ {
+ if (display->shell)
+ {
+ xdg_surface_move(display->window->xdg_surface,
+ display->seat, serial);
+ }
+ }
}

static void
@@ -730,6 +760,11 @@ registry_handle_global(void *data, struct wl_registry *registry,
// TODO: abort ?
}
}
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application =
+ wl_registry_bind(registry, name,
+ &ivi_application_interface, 1);
+ }
}

static void
@@ -824,6 +859,12 @@ main(int argc, char **argv)

fprintf(stderr, "simple-egl exiting\n");

+ if (window.display->ivi_application)
+ {
+ ivi_surface_destroy(window.ivi_surface);
+ ivi_application_destroy(window.display->ivi_application);
+ }
+
destroy_surface(&window);
fini_egl(&display);

@@ -838,6 +879,9 @@ main(int argc, char **argv)
wl_compositor_destroy(display.compositor);

wl_registry_destroy(display.registry);
+ if (window.display->ivi_application)
+ wl_display_roundtrip(display.display);
+
wl_display_flush(display.display);
wl_display_disconnect(display.display);

diff --git a/clients/simple-shm.c b/clients/simple-shm.c
index 2087a0e..c54b5d7 100644
--- a/clients/simple-shm.c
+++ b/clients/simple-shm.c
@@ -37,6 +37,10 @@
#include "xdg-shell-client-protocol.h"
#include "fullscreen-shell-client-protocol.h"

+#include <sys/types.h>
+#include "ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+
struct display {
struct wl_display *display;
struct wl_registry *registry;
@@ -45,6 +49,7 @@ struct display {
struct _wl_fullscreen_shell *fshell;
struct wl_shm *shm;
uint32_t formats;
+ struct ivi_application *ivi_application;
};

struct buffer {
@@ -58,6 +63,7 @@ struct window {
int width, height;
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
+ struct ivi_surface *ivi_surface;
struct buffer buffers[2];
struct buffer *prev_buffer;
struct wl_callback *callback;
@@ -179,11 +185,21 @@ create_window(struct display *display, int width, int height)
&xdg_surface_listener, window);

xdg_surface_set_title(window->xdg_surface, "simple-shm");
+
} else if (display->fshell) {
_wl_fullscreen_shell_present_surface(display->fshell,
window->surface,
_WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT,
NULL);
+ } else if (display->ivi_application ) {
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ window->ivi_surface =
+ ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ if (window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
} else {
assert(0);
}
@@ -369,6 +385,11 @@ registry_handle_global(void *data, struct wl_registry *registry,
id, &wl_shm_interface, 1);
wl_shm_add_listener(d->shm, &shm_listener, d);
}
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application =
+ wl_registry_bind(registry, id,
+ &ivi_application_interface, 1);
+ }
}

static void
@@ -413,7 +434,7 @@ create_display(void)
}

wl_display_get_fd(display->display);
-
+
return display;
}

@@ -433,6 +454,10 @@ destroy_display(struct display *display)
wl_compositor_destroy(display->compositor);

wl_registry_destroy(display->registry);
+
+ if (display->ivi_application)
+ wl_display_roundtrip(display->display);
+
wl_display_flush(display->display);
wl_display_disconnect(display->display);
free(display);
@@ -472,6 +497,13 @@ main(int argc, char **argv)
ret = wl_display_dispatch(display->display);

fprintf(stderr, "simple-shm exiting\n");
+
+ if (window->display->ivi_application)
+ {
+ ivi_surface_destroy(window->ivi_surface);
+ ivi_application_destroy(window->display->ivi_application);
+ }
+
destroy_window(window);
destroy_display(display);

diff --git a/clients/window.c b/clients/window.c
index 4592ef9..47434dc 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -72,6 +72,10 @@ typedef void *EGLContext;

#include "window.h"

+#include <sys/types.h>
+#include "ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+
struct shm_pool;

struct global {
@@ -133,6 +137,7 @@ struct display {

int has_rgb565;
int seat_version;
+ struct ivi_application *ivi_application;
};

struct window_output {
@@ -245,6 +250,7 @@ struct window {
struct xdg_popup *xdg_popup;

struct window *transient_for;
+ struct ivi_surface *ivi_surface;

struct window_frame *frame;

@@ -1373,6 +1379,20 @@ surface_create_surface(struct surface *surface, uint32_t flags)
struct display *display = surface->window->display;
struct rectangle allocation = surface->allocation;

+ if (display->ivi_application)
+ {
+ if (!surface->toysurface) {
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ surface->window->ivi_surface =
+ ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, surface->surface);
+ if (surface->window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+ }
+ }
+
if (!surface->toysurface && display->dpy &&
surface->buffer_type == WINDOW_BUFFER_TYPE_EGL_WINDOW) {
surface->toysurface =
@@ -1476,6 +1496,12 @@ surface_destroy(struct surface *surface)
if (surface->toysurface)
surface->toysurface->destroy(surface->toysurface);

+ if (surface->window->display->ivi_application)
+ {
+ ivi_surface_destroy(surface->window->ivi_surface);
+ ivi_application_destroy(surface->window->display->ivi_application);
+ }
+
wl_list_remove(&surface->link);
free(surface);
}
@@ -1490,7 +1516,7 @@ window_destroy(struct window *window)

wl_list_remove(&window->redraw_task.link);

- wl_list_for_each(input, &display->input_list, link) {
+ wl_list_for_each(input, &display->input_list, link) {
if (input->touch_focus == window)
input->touch_focus = NULL;
if (input->pointer_focus == window)
@@ -3006,7 +3032,7 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
wl_list_insert(&input->touch_point_list, &tp->link);

if (widget->touch_down_handler)
- (*widget->touch_down_handler)(widget, input,
+ (*widget->touch_down_handler)(widget, input,
serial, time, id,
sx, sy,
widget->user_data);
@@ -4386,7 +4412,7 @@ window_create_internal(struct display *display, int custom)
surface = surface_create(window);
window->main_surface = surface;

- assert(custom || display->xdg_shell);
+ assert(custom || display->xdg_shell || display->ivi_application);

window->custom = custom;
window->preferred_format = WINDOW_PREFERRED_FORMAT_NONE;
@@ -4409,14 +4435,17 @@ window_create(struct display *display)

window = window_create_internal(display, 0);

- window->xdg_surface =
- xdg_shell_get_xdg_surface(window->display->xdg_shell,
- window->main_surface->surface);
- fail_on_null(window->xdg_surface);
+ if (window->display->xdg_shell)
+ {
+ window->xdg_surface =
+ xdg_shell_get_xdg_surface(window->display->xdg_shell,
+ window->main_surface->surface);
+ fail_on_null(window->xdg_surface);

- xdg_surface_set_user_data(window->xdg_surface, window);
- xdg_surface_add_listener(window->xdg_surface,
- &xdg_surface_listener, window);
+ xdg_surface_set_user_data(window->xdg_surface, window);
+ xdg_surface_add_listener(window->xdg_surface,
+ &xdg_surface_listener, window);
+ }

return window;
}
@@ -4634,19 +4663,22 @@ window_show_menu(struct display *display,

frame_interior(menu->frame, &ix, &iy, NULL, NULL);

- window->xdg_popup = xdg_shell_get_xdg_popup(display->xdg_shell,
- window->main_surface->surface,
- parent->main_surface->surface,
- input->seat,
- display_get_serial(window->display),
- window->x - ix,
- window->y - iy,
- 0);
- fail_on_null(window->xdg_popup);
+ if (display->xdg_shell)
+ {
+ window->xdg_popup = xdg_shell_get_xdg_popup(display->xdg_shell,
+ window->main_surface->surface,
+ parent->main_surface->surface,
+ input->seat,
+ display_get_serial(window->display),
+ window->x - ix,
+ window->y - iy,
+ 0);
+ fail_on_null(window->xdg_popup);

- xdg_popup_set_user_data(window->xdg_popup, window);
- xdg_popup_add_listener(window->xdg_popup,
- &xdg_popup_listener, window);
+ xdg_popup_set_user_data(window->xdg_popup, window);
+ xdg_popup_add_listener(window->xdg_popup,
+ &xdg_popup_listener, window);
+ }
}

void
@@ -5091,6 +5123,11 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
wl_registry_bind(registry, id,
&wl_subcompositor_interface, 1);
}
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application =
+ wl_registry_bind(registry, id,
+ &ivi_application_interface, 1);
+ }

if (d->global_handler)
d->global_handler(d, id, interface, version, d->user_data);
@@ -5400,6 +5437,9 @@ display_destroy(struct display *display)

close(display->epoll_fd);

+ if (display->ivi_application)
+ wl_display_roundtrip(display->display);
+
if (!(display->display_fd_events & EPOLLERR) &&
!(display->display_fd_events & EPOLLHUP))
wl_display_flush(display->display);
--
1.8.3.1
Nobuhiko Tanibata
2014-06-25 11:58:13 UTC
Permalink
Hi,

I apply recent comments from Manuel Bachmann.
Additionally, I also apply feedback of bug fix from TIZEN IVI and
GENIVI.
If I should separately send a series of patches following v5 series, I
can do it.

BR,
Nobuhiko

2014-05-20 13:13 ? Nobuhiko Tanibata ????????:
> 2014-04-26 01:05 ? Pekka Paalanen ????????:
>> On Fri, 25 Apr 2014 22:34:27 +0900
>> Nobuhiko Tanibata <nobuhiko_tanibata at xddp.denso.co.jp> wrote:
>>
>>> 2014-04-23 19:40 ? Pekka Paalanen ????????:
>>> > This is looking good, mostly just some details in the wording
>>> > to be tuned. :-)
>>> >
>>> > I will see if I can review more of the patches, but I would also
>>> > suggest the following, in case you are still interested in
>>> > pushing this upstream.
>>> >
>>> > Wait for Weston 1.5 to be released. We are currently in freeze,
>>> > so there is no point in re-sending until that is done. Check
>>> > that the 1.5 stable branch has been created, or at least the
>>> > release has been made, before you rebase and re-send this
>>> > series.
>>> >
>>> Hi pq,
>>>
>>> Yes, I am still interested in pushing them. I will rabase them
>>> and re-send them after weston 1.5 branch has been created.
>>> I am also confirming your comments for other patches as well.
>>> Btw, do you have a date when the branch is made?
>>
>> Hi,
>>
>> good to hear. :-)
>>
>> I don't know of a date, but I suppose early May, perhaps.
>>
>
> Hi,
>
> I am re-sending them which are re-based based on Weston 1.5.
> Additionally, I applied review comments from pq. Thank you for many
> comments.
> They are very use full for me!
>
> BR,
> Nobuhiko
>
>>
>> Thanks,
>> pq
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: weston_ivi_shell_contribution.png
Type: image/png
Size: 110550 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/wayland-devel/attachments/20140625/abbfc064/attachment-0001.png>
Nobuhiko Tanibata
2014-06-25 12:04:16 UTC
Permalink
ivi_applicatoin extension creates ivi_surface objects tied
to a given wl_surface with a given id. The given id can be used in a
shell to identify which application is assigned to a wl_surface and
layout the surface wherever the shell wants. ivi_surface objects can
be used to receive status of wl_surface in the scenegraph of the
compositor.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
Changes for v2:
- Rename "error" to "warning" because meaning of "error" in wayland is fatal.

Changes for v3:
- Move "warning" from ivi_application to ivi_surface.
- Squash Makefile.
- Add description to ivi_surface:destroy.
- Update description of ivi_application:surface_create.

Changes for v4:
- Remove detail description of server side from ivi_surface::destroy
- Add clear discripton what client shall do if it encounters warning in ivi_surface
::warning.
- Add decription what happens when client tries to tie a wl_surface to multiple
ivi_surfaces.

Changes for v5:
- apply review comments from mailing list

Changes for v6:
- the same as v5

protocol/Makefile.am | 3 +-
protocol/ivi-application.xml | 101 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 103 insertions(+), 1 deletion(-)
create mode 100644 protocol/ivi-application.xml

diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 5e331a7..9913f16 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -8,7 +8,8 @@ protocol_sources = \
text-cursor-position.xml \
wayland-test.xml \
xdg-shell.xml \
- scaler.xml
+ scaler.xml \
+ ivi-application.xml

if HAVE_XMLLINT
.PHONY: validate
diff --git a/protocol/ivi-application.xml b/protocol/ivi-application.xml
new file mode 100644
index 0000000..833fd38
--- /dev/null
+++ b/protocol/ivi-application.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ivi_application">
+
+ <copyright>
+ Copyright (C) 2013 DENSO CORPORATION
+ Copyright (c) 2013 BMW Car IT GmbH
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ </copyright>
+
+ <interface name="ivi_surface" version="1">
+ <description summary="application interface to surface in ivi compositor"/>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy ivi_surface">
+ This removes link from ivi_id to wl_surface and destroys ivi_surface.
+ </description>
+ </request>
+
+ <event name="visibility">
+ <description summary="visibility of surface in ivi compositor has changed">
+ The new visibility state is provided in argument visibility.
+ If visibility is 0, the surface has become invisible.
+ If visibility is not 0, the surface has become visible.
+ </description>
+ <arg name="visibility" type="int"/>
+ </event>
+
+ <enum name="warning_code">
+ <description summary="possible warning codes returned by ivi compositor">
+ These define all possible warning codes returned by ivi compositor on server-side warnings.
+ invalid_wl_surface:
+ - wl_surface already has a another role.
+ - wl_surface is destroyed before the ivi_surface is destroyed.
+ ivi_id_in_use: ivi_id is already assigned by another application.
+ </description>
+ <entry name="invalid_wl_surface" value="1" summary="wl_surface is invalid"/>
+ <entry name="ivi_id_in_use" value="2" summary="ivi_id is in use and can not be shared"/>
+ </enum>
+
+ <event name="warning">
+ <description summary="server-side warning detected">
+ The ivi compositor encountered warning while processing a request by this
+ application. The warning is defined by argument warning_code and optional
+ warning_text. If the warning is detected, client shall destroy the ivi_surface
+ object.
+
+ When a warning event is sent, the compositor turns the ivi_surface object inert.
+ The ivi_surface will not deliver further events, all requests on it are ignored
+ except 'destroy', and the association to the ivi_id is removed. The client
+ should destroy the ivi_surface object. If an inert ivi_surface object is used as
+ an argument to any other object's request, that request will [produce a fatal
+ error / produce a warning / be ignored].
+ </description>
+ <arg name="warning_code" type="int"/>
+ <arg name="warning_text" type="string" allow-null="true"/>
+ </event>
+
+ </interface>
+
+ <interface name="ivi_application" version="1">
+ <description summary="create ivi-style surfaces">
+ This interface is implemented by servers that provide desktop-style user interfaces.
+ It allows clients to associate a ivi_surface with a basic surface.
+ </description>
+
+ <request name="surface_create">
+ <description summary="create ivi_surface with numeric ID in ivi compositor">
+ surface_create will create a interface:ivi_surface with numeric ID; ivi_id in
+ ivi compositor. These ivi_ids are defined as unique in the system to identify
+ it inside of ivi compositor. The ivi compositor implements business logic how to
+ set properties of the surface with ivi_id according to status of the system.
+ E.g. a unique ID for Car Navigation application is used for implementing special
+ logic of the application about where it shall be located.
+ if a wl_surface which already has another role is set, the server regards this as
+ error and disconnects the client.
+ </description>
+ <arg name="ivi_id" type="uint"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="id" type="new_id" interface="ivi_surface"/>
+ </request>
+
+ </interface>
+
+</protocol>
--
1.8.3.1
Nobuhiko Tanibata
2014-06-25 12:06:19 UTC
Permalink
In-Vehicle Infotainment system traditionally manages surfaces with global
identification. A protocol, ivi_application, supports such a feature by
implementing a request, ivi_application::surface_creation defined in
ivi_application.xml.

The ivi-shell explicitly loads ivi-layout.so and a module to add business
logic like how to layout surfaces by using ivi-layout APIs.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
Changes for v2:
- apply review comments of mailing list.
- squash update of Makefile into this patch.
- move this patch after patch of weston-layout.
- support inherit propoerties of id_surface when client attaches another
wl_surface with id_surface after destroying ivi_surface once.

Changes for v3:
- squash internal method, configure, to ivi_shell_surface_configure.

Changes for v4:
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- apply review comments from mailing list

Changes for v6:
- apply bug fixes found in TIZEN IVI and GENIVI
- apply review comments from Mailing list
- use signed integers except flags, bitfields, object ids.

Makefile.am | 22 +++
configure.ac | 12 ++
ivi-shell/ivi-layout.h | 75 +++++++++
ivi-shell/ivi-shell.c | 413 +++++++++++++++++++++++++++++++++++++++++++++++++
ivi-shell/ivi-shell.h | 35 +++++
5 files changed, 557 insertions(+)
create mode 100644 ivi-shell/ivi-layout.h
create mode 100644 ivi-shell/ivi-shell.c
create mode 100644 ivi-shell/ivi-shell.h

diff --git a/Makefile.am b/Makefile.am
index 343adc6..279fffc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -700,6 +700,28 @@ nodist_fullscreen_shell_la_SOURCES = \
BUILT_SOURCES += $(nodist_fullscreen_shell_la_SOURCES)
endif

+if ENABLE_IVI_SHELL
+
+module_LTLIBRARIES += \
+ $(ivi_shell)
+
+ivi_shell = ivi-shell.la
+ivi_shell_la_LDFLAGS = -module -avoid-version
+ivi_shell_la_LIBADD = $(COMPOSITOR_LIBS) $(IVI_SHELL_LIBS) libshared.la
+ivi_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(IVI_SHELL_CFLAGS)
+ivi_shell_la_SOURCES = \
+ ivi-shell/ivi-shell.h \
+ ivi-shell/ivi-shell.c \
+ ivi-shell/ivi-layout.h
+nodist_ivi_shell_la_SOURCES = \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-server-protocol.h
+
+BUILT_SOURCES += $(nodist_ivi_shell_la_SOURCES)
+
+endif
+
+
if ENABLE_SCREEN_SHARING

module_LTLIBRARIES += screen-share.la
diff --git a/configure.ac b/configure.ac
index 031a26f..23e6ba5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -433,6 +433,16 @@ if test "x$enable_dbus" != "xno"; then
fi
AM_CONDITIONAL(ENABLE_DBUS, test "x$enable_dbus" = "xyes")

+# ivi-shell support
+AC_ARG_ENABLE(ivi-shell,
+ AS_HELP_STRING([--disable-ivi-shell],
+ [do not build ivi-shell server plugin and client]),,
+ enable_ivi_shell=yes)
+AM_CONDITIONAL(ENABLE_IVI_SHELL, test "x$enable_ivi_shell" = "xyes")
+if test x$enable_ivi_shell = xyes; then
+ PKG_CHECK_MODULES(IVI_SHELL, [cairo])
+fi
+
AC_ARG_ENABLE(wcap-tools, [ --disable-wcap-tools],, enable_wcap_tools=yes)
AM_CONDITIONAL(BUILD_WCAP_TOOLS, test x$enable_wcap_tools = xyes)
if test x$enable_wcap_tools = xyes; then
@@ -522,6 +532,8 @@ AC_MSG_RESULT([
XWayland ${enable_xwayland}
dbus ${enable_dbus}

+ ivi-shell ${enable_ivi_shell}
+
Build wcap utility ${enable_wcap_tools}
Build Fullscreen Shell ${enable_fullscreen_shell}

diff --git a/ivi-shell/ivi-layout.h b/ivi-shell/ivi-layout.h
new file mode 100644
index 0000000..2027d89
--- /dev/null
+++ b/ivi-shell/ivi-layout.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * The ivi-layout library supports API set of controlling properties of
+ * surface and layer which groups surfaces. An unique ID whose type is integer
+ * is required to create surface and layer. With the unique ID, surface and
+ * layer are identified to control them. The API set consists of APIs to control
+ * properties of surface and layers about followings,
+ * - visibility.
+ * - opacity.
+ * - clipping (x,y,width,height).
+ * - position and size of it to be displayed.
+ * - orientation per 90 degree.
+ * - add or remove surfaces to a layer.
+ * - order of surfaces/layers in layer/screen to be displayed.
+ * - commit to apply property changes.
+ * - notifications of property change.
+ *
+ * Management of surfaces and layers grouping these surfaces are common way in
+ * In-Vehicle Infotainment system, which integrate several domains in one system.
+ * A layer is allocated to a domain in order to control application surfaces
+ * grouped to the layer all together.
+ */
+
+#ifndef _IVI_LAYOUT_H_
+#define _IVI_LAYOUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "compositor.h"
+
+struct ivi_layout_surface;
+
+struct ivi_layout_interface {
+ struct weston_view* (*get_weston_view)(struct ivi_layout_surface *surface);
+ void (*surfaceConfigure)(struct ivi_layout_surface *ivisurf,
+ int32_t width, int32_t height);
+ int32_t (*surfaceSetNativeContent)(struct weston_surface *wl_surface,
+ int32_t width,
+ int32_t height,
+ uint32_t id_surface);
+ struct ivi_layout_surface* (*surfaceCreate)(struct weston_surface *wl_surface,
+ uint32_t id_surface);
+ void (*initWithCompositor)(struct weston_compositor *ec);
+};
+
+WL_EXPORT struct ivi_layout_interface ivi_layout_interface;
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _IVI_LAYOUT_H_ */
diff --git a/ivi-shell/ivi-shell.c b/ivi-shell/ivi-shell.c
new file mode 100644
index 0000000..1f188ce
--- /dev/null
+++ b/ivi-shell/ivi-shell.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/**
+ * ivi-shell supports a type of shell for In-Vehicle Infotainment system.
+ * In-Vehicle Infotainment system traditionally manages surfaces with global
+ * identification. A protocol, ivi_application, supports such a feature
+ * by implementing a request, ivi_application::surface_creation defined in
+ * ivi_application.xml.
+ *
+ * The ivi-shell explicitly loads a module to add business logic like how to
+ * layout surfaces by using internal ivi-layout APIs.
+ */
+#include "config.h"
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <dlfcn.h>
+#include <limits.h>
+
+#include "ivi-shell.h"
+#include "ivi-application-server-protocol.h"
+#include "ivi-layout.h"
+
+#include "../shared/os-compatibility.h"
+
+struct ivi_shell_surface
+{
+ struct ivi_shell *shell;
+ struct ivi_layout_surface *layout_surface;
+
+ struct weston_surface *surface;
+ uint32_t id_surface;
+
+ int32_t width;
+ int32_t height;
+
+ struct wl_list link;
+};
+
+struct ivi_shell_setting
+{
+ char *ivi_module;
+};
+
+static struct ivi_layout_interface *ivi_layout;
+
+/* ------------------------------------------------------------------------- */
+
+ /* common functions */
+/* ------------------------------------------------------------------------- */
+
+/**
+ * Implementation of ivi_surface
+ */
+
+static void
+ivi_shell_surface_configure(struct weston_surface *, int32_t, int32_t);
+
+static struct ivi_shell_surface *
+get_ivi_shell_surface(struct weston_surface *surface)
+{
+ if (surface->configure == ivi_shell_surface_configure) {
+ return surface->configure_private;
+ } else {
+ return NULL;
+ }
+}
+
+static void
+ivi_shell_surface_configure(struct weston_surface *surface,
+ int32_t sx, int32_t sy)
+{
+ struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(surface);
+ struct weston_view *view = NULL;
+ float from_x = 0.0f;
+ float from_y = 0.0f;
+ float to_x = 0.0f;
+ float to_y = 0.0f;
+
+ if ((surface->width == 0) || (surface->height == 0) || (ivisurf == NULL)) {
+ return;
+ }
+
+ view = ivi_layout->get_weston_view(ivisurf->layout_surface);
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->width != surface->width || ivisurf->height != surface->height) {
+
+ ivisurf->width = surface->width;
+ ivisurf->height = surface->height;
+
+ weston_view_to_global_float(view, 0, 0, &from_x, &from_y);
+ weston_view_to_global_float(view, sx, sy, &to_x, &to_y);
+
+ weston_view_set_position(view,
+ view->geometry.x + to_x - from_x,
+ view->geometry.y + to_y - from_y);
+ weston_view_update_transform(view);
+
+ ivi_layout->surfaceConfigure(ivisurf->layout_surface, surface->width, surface->height);
+ }
+}
+
+static void
+surface_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource);
+ if (ivisurf != NULL) {
+ ivisurf->surface->configure = NULL;
+ ivisurf->surface->configure_private = NULL;
+ ivisurf->surface = NULL;
+ ivi_layout->surfaceSetNativeContent(NULL, 0, 0, ivisurf->id_surface);
+ }
+
+ wl_resource_destroy(resource);
+}
+
+static const struct ivi_surface_interface surface_implementation = {
+ surface_destroy,
+};
+
+static struct ivi_shell_surface *
+is_surf_in_surfaces(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct ivi_shell_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+static const struct {
+ uint32_t warning_code; /* enum ivi_surface_warning_code */
+ const char *msg;
+} warning_strings[] = {
+ {IVI_SURFACE_WARNING_CODE_INVALID_WL_SURFACE, "wl_surface is invalid"},
+ {IVI_SURFACE_WARNING_CODE_IVI_ID_IN_USE, "surface_id is already assigned by another app"}
+};
+
+/**
+ * Implementation of ivi_application::surface_create.
+ * Creating new ivi_shell_surface with identification to identify the surface
+ * in the system.
+ */
+static void
+application_surface_create(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface,
+ struct wl_resource *surface_resource,
+ uint32_t id)
+{
+ struct ivi_shell *shell = wl_resource_get_user_data(resource);
+ struct ivi_shell_surface *ivisurf = NULL;
+ struct ivi_layout_surface *layout_surface = NULL;
+ struct weston_surface *weston_surface = wl_resource_get_user_data(surface_resource);
+ struct wl_resource *res;
+ int32_t warn_idx = -1;
+
+ if (weston_surface != NULL) {
+
+ /* check if a surface already has another role*/
+ if (weston_surface->configure) {
+ wl_resource_post_error(weston_surface->resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "surface->configure already "
+ "set");
+ return;
+ }
+
+ layout_surface = ivi_layout->surfaceCreate(weston_surface, id_surface);
+
+ if (layout_surface == NULL)
+ warn_idx = 1;
+ } else {
+ warn_idx = 0;
+ }
+
+ res = wl_resource_create(client, &ivi_surface_interface, 1, id);
+ if (res == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ if (warn_idx >= 0) {
+ wl_resource_set_implementation(res, &surface_implementation,
+ NULL, NULL);
+ ivi_surface_send_warning(res,
+ warning_strings[warn_idx].warning_code,
+ warning_strings[warn_idx].msg);
+ return;
+ }
+
+ ivisurf = is_surf_in_surfaces(&shell->ivi_surface_list, id_surface);
+ if (ivisurf == NULL) {
+ ivisurf = zalloc(sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ wl_resource_post_no_memory(res);
+ return;
+ }
+
+ wl_list_init(&ivisurf->link);
+ wl_list_insert(&shell->ivi_surface_list, &ivisurf->link);
+
+ ivisurf->shell = shell;
+ ivisurf->id_surface = id_surface;
+ }
+
+ ivisurf->width = 0;
+ ivisurf->height = 0;
+ ivisurf->layout_surface = layout_surface;
+ ivisurf->surface = weston_surface;
+
+ weston_surface->configure = ivi_shell_surface_configure;
+ weston_surface->configure_private = ivisurf;
+
+ wl_resource_set_implementation(res, &surface_implementation,
+ ivisurf, NULL);
+}
+
+static const struct ivi_application_interface application_implementation = {
+ application_surface_create
+};
+
+static void
+bind_ivi_application(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct ivi_shell *shell = data;
+ struct wl_resource *resource = NULL;
+
+ resource = wl_resource_create(client, &ivi_application_interface, 1, id);
+
+ wl_resource_set_implementation(resource,
+ &application_implementation,
+ shell, NULL);
+}
+
+/**
+ * Initialization/destruction method of ivi-shell
+ */
+static void
+shell_destroy(struct wl_listener *listener, void *data)
+{
+ struct ivi_shell *shell =
+ container_of(listener, struct ivi_shell, destroy_listener);
+ struct ivi_shell_surface *ivisurf, *next;
+
+ wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) {
+ wl_list_remove(&ivisurf->link);
+ free(ivisurf);
+ }
+
+ free(shell);
+}
+
+static void
+init_ivi_shell(struct weston_compositor *compositor, struct ivi_shell *shell)
+{
+ shell->compositor = compositor;
+
+ wl_list_init(&shell->ivi_surface_list);
+}
+
+static int
+ivi_shell_setting_create(struct ivi_shell_setting *dest)
+{
+ int result = 0;
+ struct weston_config *config = NULL;
+ struct weston_config_section *section = NULL;
+
+ if (NULL == dest) {
+ return -1;
+ }
+
+ config = weston_config_parse("weston.ini");
+ section = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ if (weston_config_section_get_string(
+ section, "ivi-module", (char **)&dest->ivi_module, NULL) != 0)
+ {
+ result = -1;
+ }
+
+ weston_config_destroy(config);
+ return result;
+}
+
+/**
+ * Initialization of ivi-shell.
+ */
+static int
+ivi_load_modules(struct weston_compositor *compositor, const char *modules,
+ int *argc, char *argv[])
+{
+ const char *p, *end;
+ char buffer[256];
+ int (*module_init)(struct weston_compositor *compositor,
+ int *argc, char *argv[]);
+
+ if (modules == NULL)
+ return 0;
+
+ p = modules;
+ while (*p) {
+ end = strchrnul(p, ',');
+ snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p);
+ module_init = weston_load_module(buffer, "module_init");
+ if (module_init)
+ module_init(compositor, argc, argv);
+ p = end;
+ while (*p == ',')
+ p++;
+
+ }
+
+ return 0;
+}
+
+WL_EXPORT int
+module_init(struct weston_compositor *compositor,
+ int *argc, char *argv[])
+{
+ struct ivi_shell *shell = NULL;
+ char ivi_layout_path[PATH_MAX];
+ void *module;
+ struct ivi_shell_setting setting = { };
+
+ shell = zalloc(sizeof *shell);
+ if (shell == NULL) {
+ return -1;
+ }
+
+ init_ivi_shell(compositor, shell);
+
+ shell->destroy_listener.notify = shell_destroy;
+ wl_signal_add(&compositor->destroy_signal, &shell->destroy_listener);
+
+ if (wl_global_create(compositor->wl_display, &ivi_application_interface, 1,
+ shell, bind_ivi_application) == NULL) {
+ return -1;
+ }
+
+ if (ivi_shell_setting_create(&setting) != 0) {
+ return 0;
+ }
+
+ /*load module:ivi-layout*/
+ /*ivi_layout_interface is referred by ivi-shell to use ivi-layout*/
+ snprintf(ivi_layout_path, sizeof ivi_layout_path, "%s/%s", MODULEDIR, "ivi-layout.so");
+ module = dlopen(ivi_layout_path, RTLD_NOW | RTLD_NOLOAD);
+ if (module) {
+ weston_log("ivi-shell: Module '%s' already loaded\n", ivi_layout_path);
+ dlclose(module);
+ return -1;
+ }
+
+ weston_log("ivi-shell: Loading module '%s'\n", ivi_layout_path);
+ module = dlopen(ivi_layout_path, RTLD_NOW | RTLD_GLOBAL);
+ if (!module) {
+ weston_log("ivi-shell: Failed to load module: %s\n", dlerror());
+ return -1;
+ }
+
+ ivi_layout = dlsym(module,"ivi_layout_interface");
+ if (!ivi_layout){
+ weston_log("ivi-shell: couldn't find ivi_layout_interface in '%s'\n", ivi_layout_path);
+ free(setting.ivi_module);
+ return -1;
+ }
+ else{
+ ivi_layout->initWithCompositor(compositor);
+ }
+
+ /*Call module_init of ivi-modules which are defined in weston.ini*/
+ if (ivi_load_modules(compositor,setting.ivi_module,argc,argv) < 0){
+ free(setting.ivi_module);
+ return -1;
+ }
+
+ free(setting.ivi_module);
+ return 0;
+}
diff --git a/ivi-shell/ivi-shell.h b/ivi-shell/ivi-shell.h
new file mode 100644
index 0000000..157c5ae
--- /dev/null
+++ b/ivi-shell/ivi-shell.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+
+#include "compositor.h"
+
+struct ivi_shell
+{
+ struct wl_resource *resource;
+ struct wl_listener destroy_listener;
+
+ struct weston_compositor *compositor;
+
+ struct wl_list ivi_surface_list; /* struct ivi_shell_surface::link */
+};
--
1.8.3.1
Nobuhiko Tanibata
2014-06-25 12:06:41 UTC
Permalink
API set of controlling properties of surface and layer which groups
surfaces. An unique ID whose type is integer is required to create
surface and layer. With the unique ID, surface and layer are identified
to control them. The API set consists of APIs to control properties of
surface and layers about followings,

- visibility.
- opacity.
- clipping (x,y,width,height).
- position and size of it to be displayed.
- orientation per 90 degree.
- add or remove surfaces to a layer.
- order of surfaces/layers in layer/screen to be displayed.
- commit to apply property changes.
- notifications of property change.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---
Changes for v2:
- move this patch in front of ivi-shell patch to be compiled successfully.
- unsupport weston_layout_takeSurfaceScreenshot because implementation needs to
be discussed more. It is pending.
- support inherit propoerties of id_surface when client attaches another
wl_surface with id_surface after destroying ivi_surface once.
- bug fix of https://bugs.tizen.org/jira/browse/TIVI-2882

Changes for v3 and v4
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- apply review comments from mailing list

Changes for v6:
- apply bug fixes found in TIZEN IVI and GENIVI
- apply review comments from Mailing list
- use signed integers except flags, bitfields, object ids.
- access views via weston_surface
- access width_from_buffer and height_from_buffer via weston_surface
- remove dependency on CAIRO

Makefile.am | 17 +-
ivi-shell/ivi-layout-export.h | 952 +++++++++++++
ivi-shell/ivi-layout.c | 2940 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 3908 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/ivi-layout-export.h
create mode 100644 ivi-shell/ivi-layout.c

diff --git a/Makefile.am b/Makefile.am
index 279fffc..e8bcb1b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -703,7 +703,8 @@ endif
if ENABLE_IVI_SHELL

module_LTLIBRARIES += \
- $(ivi_shell)
+ $(ivi_shell) \
+ $(ivi_layout)

ivi_shell = ivi-shell.la
ivi_shell_la_LDFLAGS = -module -avoid-version
@@ -719,6 +720,20 @@ nodist_ivi_shell_la_SOURCES = \

BUILT_SOURCES += $(nodist_ivi_shell_la_SOURCES)

+ivi_layout = ivi-layout.la
+ivi_layout_la_LDFLAGS = -module -avoid-version
+ivi_layout_la_LIBADD = $(COMPOSITOR_LIBS) $(IVI_SHELL_LIBS) libshared.la
+ivi_layout_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(IVI_SHELL_CFLAGS)
+ivi_layout_la_SOURCES = \
+ ivi-shell/ivi-layout.h \
+ ivi-shell/ivi-layout-export.h \
+ ivi-shell/ivi-layout.c
+nodist_ivi_layout_la_SOURCES = \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-server-protocol.h
+
+BUILT_SOURCES += $(nodist_ivi_layout_la_SOURCES)
+
endif


diff --git a/ivi-shell/ivi-layout-export.h b/ivi-shell/ivi-layout-export.h
new file mode 100644
index 0000000..796dd96
--- /dev/null
+++ b/ivi-shell/ivi-layout-export.h
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * The ivi-layout library supports API set of controlling properties of
+ * surface and layer which groups surfaces. An unique ID whose type is integer
+ * is required to create surface and layer. With the unique ID, surface and
+ * layer are identified to control them. The API set consists of APIs to control
+ * properties of surface and layers about followings,
+ * - visibility.
+ * - opacity.
+ * - clipping (x,y,width,height).
+ * - position and size of it to be displayed.
+ * - orientation per 90 degree.
+ * - add or remove surfaces to a layer.
+ * - order of surfaces/layers in layer/screen to be displayed.
+ * - commit to apply property changes.
+ * - notifications of property change.
+ *
+ * Management of surfaces and layers grouping these surfaces are common way in
+ * In-Vehicle Infotainment system, which integrate several domains in one system.
+ * A layer is allocated to a domain in order to control application surfaces
+ * grouped to the layer all together.
+ */
+
+#ifndef _IVI_LAYOUT_EXPORT_H_
+#define _IVI_LAYOUT_EXPORT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "compositor.h"
+#include "ivi-layout.h"
+
+struct ivi_layout_SurfaceProperties
+{
+ float opacity;
+ int32_t sourceX;
+ int32_t sourceY;
+ int32_t sourceWidth;
+ int32_t sourceHeight;
+ int32_t origSourceWidth;
+ int32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ int32_t destWidth;
+ int32_t destHeight;
+ int32_t orientation;
+ int32_t visibility;
+ int32_t frameCounter;
+ int32_t drawCounter;
+ int32_t updateCounter;
+ int32_t pixelformat;
+ int32_t nativeSurface;
+ int32_t inputDevicesAcceptance;
+ int32_t chromaKeyEnabled;
+ int32_t chromaKeyRed;
+ int32_t chromaKeyGreen;
+ int32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct ivi_layout_LayerProperties
+{
+ float opacity;
+ int32_t sourceX;
+ int32_t sourceY;
+ int32_t sourceWidth;
+ int32_t sourceHeight;
+ int32_t origSourceWidth;
+ int32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ int32_t destWidth;
+ int32_t destHeight;
+ int32_t orientation;
+ int32_t visibility;
+ int32_t type;
+ int32_t chromaKeyEnabled;
+ int32_t chromaKeyRed;
+ int32_t chromaKeyGreen;
+ int32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct ivi_layout_layer;
+struct ivi_layout_screen;
+
+enum ivi_layout_notification_mask {
+ IVI_NOTIFICATION_NONE = 0,
+ IVI_NOTIFICATION_OPACITY = (1 << 1),
+ IVI_NOTIFICATION_SOURCE_RECT = (1 << 2),
+ IVI_NOTIFICATION_DEST_RECT = (1 << 3),
+ IVI_NOTIFICATION_DIMENSION = (1 << 4),
+ IVI_NOTIFICATION_POSITION = (1 << 5),
+ IVI_NOTIFICATION_ORIENTATION = (1 << 6),
+ IVI_NOTIFICATION_VISIBILITY = (1 << 7),
+ IVI_NOTIFICATION_PIXELFORMAT = (1 << 8),
+ IVI_NOTIFICATION_ADD = (1 << 9),
+ IVI_NOTIFICATION_REMOVE = (1 << 10),
+ IVI_NOTIFICATION_ALL = 0xFFFF
+};
+
+typedef void(*layerPropertyNotificationFunc)(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_LayerProperties*,
+ enum ivi_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*surfacePropertyNotificationFunc)(struct ivi_layout_surface *ivisurf,
+ struct ivi_layout_SurfaceProperties*,
+ enum ivi_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*layerCreateNotificationFunc)(struct ivi_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*layerRemoveNotificationFunc)(struct ivi_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*surfaceCreateNotificationFunc)(struct ivi_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceRemoveNotificationFunc)(struct ivi_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceConfigureNotificationFunc)(struct ivi_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*ivi_controller_surface_content_callback)(struct ivi_layout_surface *ivisurf,
+ int32_t content,
+ void *userdata);
+
+/**
+ * \brief to be called by ivi-shell in order to set initail view of
+ * weston_surface.
+ */
+/*
+struct weston_view *
+ivi_layout_get_weston_view(struct ivi_layout_surface *surface);
+*/
+
+/**
+ * \brief initialize ivi-layout
+ */
+/*
+void
+ivi_layout_initWithCompositor(struct weston_compositor *ec);
+*/
+
+/**
+ * \brief register for notification when layer is created
+ */
+int32_t
+ivi_layout_addNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata);
+
+void
+ivi_layout_removeNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when layer is removed
+ */
+int32_t
+ivi_layout_addNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata);
+
+void
+ivi_layout_removeNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is created
+ */
+int32_t
+ivi_layout_addNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata);
+
+void
+ivi_layout_removeNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is removed
+ */
+int32_t
+ivi_layout_addNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata);
+
+void
+ivi_layout_removeNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is configured
+ */
+int32_t
+ivi_layout_addNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata);
+
+void
+ivi_layout_removeNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief get id of surface from ivi_layout_surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+uint32_t
+ivi_layout_getIdOfSurface(struct ivi_layout_surface *ivisurf);
+
+/**
+ * \brief get id of layer from ivi_layout_layer
+ *
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+uint32_t
+ivi_layout_getIdOfLayer(struct ivi_layout_layer *ivilayer);
+
+/**
+ * \brief get ivi_layout_layer from id of layer
+ *
+ * \return (struct ivi_layout_layer *)
+ * if the method call was successful
+ * \return NULL if the method call was failed
+ */
+struct ivi_layout_layer *
+ivi_layout_getLayerFromId(uint32_t id_layer);
+
+/**
+ * \brief get ivi_layout_surface from id of surface
+ *
+ * \return (struct ivi_layout_surface *)
+ * if the method call was successful
+ * \return NULL if the method call was failed
+ */
+struct ivi_layout_surface *
+ivi_layout_getSurfaceFromId(uint32_t id_surface);
+
+/**
+ * \brief get ivi_layout_screen from id of screen
+ *
+ * \return (struct ivi_layout_screen *)
+ * if the method call was successful
+ * \return NULL if the method call was failed
+ */
+struct ivi_layout_screen *
+ivi_layout_getScreenFromId(uint32_t id_screen);
+
+/**
+ * \brief Get the screen resolution of a specific screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getScreenResolution(struct ivi_layout_screen *iviscrn,
+ int32_t *pWidth,
+ int32_t *pHeight);
+
+/**
+ * \brief register for notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceAddNotification(struct ivi_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceRemoveNotification(struct ivi_layout_surface *ivisurf);
+
+/**
+ * \brief Create a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+/*
+struct ivi_layout_surface *
+ivi_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface);
+*/
+
+/**
+ * \brief Set the native content of an application to be used as surface content.
+ * If wl_surface is NULL, remove the native content of a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+/*
+int32_t
+ivi_layout_surfaceSetNativeContent(struct weston_surface *wl_surface,
+ uint32_t width,
+ uint32_t height,
+ uint32_t id_surface);
+*/
+
+/**
+ * \brief Set an observer callback for surface content status change.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetContentObserver(struct ivi_layout_surface *ivisurf,
+ ivi_controller_surface_content_callback callback,
+ void* userdata);
+
+/**
+ * \brief initialize ivi_layout_surface dest/source width and height
+ */
+/*
+void
+ivi_layout_surfaceConfigure(struct ivi_layout_surface *ivisurf,
+ uint32_t width, uint32_t height);
+*/
+
+/**
+ * \brief Remove a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceRemove(struct ivi_layout_surface *ivisurf);
+
+/**
+ * \brief Set from which kind of devices the surface can accept input events.
+ * By default, a surface accept input events from all kind of devices (keyboards, pointer, ...)
+ * By calling this function, you can adjust surface preferences. Note that this function only
+ * adjust the acceptance for the specified devices. Non specified are keept untouched.
+ *
+ * Typicall use case for this function is when dealing with pointer or touch events.
+ * Those are normally dispatched to the first visible surface below the coordinate.
+ * If you want a different behavior (i.e. forward events to an other surface below the coordinate,
+ * you can set all above surfaces to refuse input events)
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_UpdateInputEventAcceptanceOn(struct ivi_layout_surface *ivisurf,
+ int32_t devices,
+ int32_t acceptance);
+
+/**
+ * \brief Get the layer properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getPropertiesOfLayer(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_LayerProperties *pLayerProperties);
+
+/**
+ * \brief Get the number of hardware layers of a screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ int32_t *pNumberOfHardwareLayers);
+
+/**
+ * \brief Get the screens
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getScreens(int32_t *pLength, struct ivi_layout_screen ***ppArray);
+
+/**
+ * \brief Get the screens under the given layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getScreensUnderLayer(struct ivi_layout_layer *ivilayer,
+ int32_t *pLength,
+ struct ivi_layout_screen ***ppArray);
+
+/**
+ * \brief Get all Layers which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getLayers(int32_t *pLength, struct ivi_layout_layer ***ppArray);
+
+/**
+ * \brief Get all Layers of the given screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getLayersOnScreen(struct ivi_layout_screen *iviscrn,
+ int32_t *pLength,
+ struct ivi_layout_layer ***ppArray);
+
+/**
+ * \brief Get all Layers under the given surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getLayersUnderSurface(struct ivi_layout_surface *ivisurf,
+ int32_t *pLength,
+ struct ivi_layout_layer ***ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getSurfaces(int32_t *pLength, struct ivi_layout_surface ***ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered to a given layer and are managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getSurfacesOnLayer(struct ivi_layout_layer *ivilayer,
+ int32_t *pLength,
+ struct ivi_layout_surface ***ppArray);
+
+/**
+ * \brief Create a layer which should be managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+struct ivi_layout_layer *
+ivi_layout_layerCreateWithDimension(uint32_t id_layer,
+ int32_t width, int32_t height);
+
+/**
+ * \brief Removes a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerRemove(struct ivi_layout_layer *ivilayer);
+
+/**
+ * \brief Get the current type of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetType(struct ivi_layout_layer *ivilayer,
+ int32_t *pLayerType);
+
+/**
+ * \brief Set the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetVisibility(struct ivi_layout_layer *ivilayer,
+ int32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetVisibility(struct ivi_layout_layer *ivilayer,
+ int32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetOpacity(struct ivi_layout_layer *ivilayer, float opacity);
+
+/**
+ * \brief Get the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetOpacity(struct ivi_layout_layer *ivilayer, float *pOpacity);
+
+/**
+ * \brief Set the area of a layer which should be used for the rendering.
+ * Only this part will be visible.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetSourceRectangle(struct ivi_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height);
+
+/**
+ * \brief Set the destination area on the display for a layer.
+ * The layer will be scaled and positioned to this rectangle for rendering
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetDestinationRectangle(struct ivi_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetDimension(struct ivi_layout_layer *ivilayer,
+ int32_t *pDimension);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetDimension(struct ivi_layout_layer *ivilayer,
+ int32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetPosition(struct ivi_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetPosition(struct ivi_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetOrientation(struct ivi_layout_layer *ivilayer,
+ int32_t orientation);
+
+/**
+ * \brief Gets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetOrientation(struct ivi_layout_layer *ivilayer,
+ int32_t *pOrientation);
+
+/**
+ * \brief Sets the color value which defines the transparency value.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetChromaKey(struct ivi_layout_layer *ivilayer,
+ int32_t* pColor);
+
+/**
+ * \brief Sets render order of surfaces within one layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerSetRenderOrder(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface **pSurface,
+ int32_t number);
+
+/**
+ * \brief Get the capabilities of a layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerGetCapabilities(struct ivi_layout_layer *ivilayer,
+ int32_t *pCapabilities);
+
+/**
+ * \brief Get the possible capabilities of a layertype
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerTypeGetCapabilities(int32_t layerType,
+ int32_t *pCapabilities);
+
+/**
+ * \brief Create the logical surface, which has no native buffer associated
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceInitialize(struct ivi_layout_surface **pSurface);
+
+/**
+ * \brief Set the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetVisibility(struct ivi_layout_surface *ivisurf,
+ int32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetVisibility(struct ivi_layout_surface *ivisurf,
+ int32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetOpacity(struct ivi_layout_surface *ivisurf,
+ float opacity);
+
+/**
+ * \brief Get the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetOpacity(struct ivi_layout_surface *ivisurf,
+ float *pOpacity);
+
+/**
+ * \brief Set the keyboard focus on a certain surface
+ * To receive keyboard events, 2 conditions must be fulfilled:
+ * 1- The surface must accept events from keyboard. See ilm_UpdateInputEventAcceptanceOn
+ * 2- The keyboard focus must be set on that surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_SetKeyboardFocusOn(struct ivi_layout_surface *ivisurf);
+
+/**
+ * \brief Get the indentifier of the surface which hold the keyboard focus
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_GetKeyboardFocusSurfaceId(struct ivi_layout_surface **pSurfaceId);
+
+/**
+ * \brief Set the destination area of a surface within a layer for rendering.
+ * The surface will be scaled to this rectangle for rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetDestinationRectangle(struct ivi_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetDimension(struct ivi_layout_surface *ivisurf,
+ int32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetDimension(struct ivi_layout_surface *ivisurf,
+ int32_t *pDimension);
+
+/**
+ * \brief Sets the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetPosition(struct ivi_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Get the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetPosition(struct ivi_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetOrientation(struct ivi_layout_surface *ivisurf,
+ int32_t orientation);
+
+/**
+ * \brief Gets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetOrientation(struct ivi_layout_surface *ivisurf,
+ int32_t *pOrientation);
+
+/**
+ * \brief Gets the pixelformat of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceGetPixelformat(struct ivi_layout_layer *ivisurf,
+ int32_t *pPixelformat);
+
+/**
+ * \brief Sets the color value which defines the transparency value of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetChromaKey(struct ivi_layout_surface *ivisurf,
+ int32_t* pColor);
+
+/**
+ * \brief Add a layer to a screen which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_screenAddLayer(struct ivi_layout_screen *iviscrn,
+ struct ivi_layout_layer *addlayer);
+
+/**
+ * \brief Sets render order of layers on a display
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_screenSetRenderOrder(struct ivi_layout_screen *iviscrn,
+ struct ivi_layout_layer **pLayer,
+ const int32_t number);
+
+/**
+ * \brief Enable or disable a rendering optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_SetOptimizationMode(uint32_t id, int32_t mode);
+
+/**
+ * \brief Get the current enablement for an optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_GetOptimizationMode(uint32_t id, int32_t *pMode);
+
+/**
+ * \brief register for notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerAddNotification(struct ivi_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerRemoveNotification(struct ivi_layout_layer *ivilayer);
+
+/**
+ * \brief Get the surface properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_getPropertiesOfSurface(struct ivi_layout_surface *ivisurf,
+ struct ivi_layout_SurfaceProperties *pSurfaceProperties);
+
+/**
+ * \brief Add a surface to a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerAddSurface(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *addsurf);
+
+/**
+ * \brief Removes a surface from a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_layerRemoveSurface(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *remsurf);
+
+/**
+ * \brief Set the area of a surface which should be used for the rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_surfaceSetSourceRectangle(struct ivi_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height);
+
+/**
+ * \brief get weston_output from ivi_layout_screen.
+ *
+ * \return (struct weston_screen *)
+ * if the method call was successful
+ * \return NULL if the method call was failed
+ */
+struct weston_output *
+ivi_layout_screenGetOutput(struct ivi_layout_screen *);
+
+/**
+ * \brief Commit all changes and execute all enqueued commands since last commit.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the method call was failed
+ */
+int32_t
+ivi_layout_commitChanges(void);
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _IVI_LAYOUT_EXPORT_H_ */
diff --git a/ivi-shell/ivi-layout.c b/ivi-shell/ivi-layout.c
new file mode 100644
index 0000000..af9e73e
--- /dev/null
+++ b/ivi-shell/ivi-layout.c
@@ -0,0 +1,2940 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * Implementation of ivi-layout library. The actual view on screen is
+ * not updated till calling ivi_layout_commitChanges. A overview from
+ * calling API for updating properties of surfaces/layer to asking compositor
+ * to compose them by using weston_compositor_schedule_repaint,
+ * 0/ initialize this library by ivi_layout_initWithCompositor
+ * with (struct weston_compositor *ec) from ivi-shell.
+ * 1/ When a API for updating properties of surface/layer, it updates
+ * pending prop of ivi_layout_surface/layer/screen which are structure to
+ * store properties.
+ * 2/ Before calling commitChanges, in case of calling a API to get a property,
+ * return current property, not pending property.
+ * 3/ At the timing of calling ivi_layout_commitChanges, pending properties
+ * are applied
+ * to properties.
+ * 4/ According properties, set transformation by using weston_matrix and
+ * weston_view per surfaces and layers in while loop.
+ * 5/ Set damage and trigger transform by using weston_view_geometry_dirty and
+ * weston_view_geometry_dirty.
+ * 6/ Notify update of properties.
+ * 7/ Trigger composition by weston_compositor_schedule_repaint.
+ *
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+
+#include "compositor.h"
+#include "ivi-layout.h"
+#include "ivi-layout-export.h"
+
+enum ivi_layout_surface_orientation {
+ IVI_LAYOUT_SURFACE_ORIENTATION_0_DEGREES = 0,
+ IVI_LAYOUT_SURFACE_ORIENTATION_90_DEGREES = 1,
+ IVI_LAYOUT_SURFACE_ORIENTATION_180_DEGREES = 2,
+ IVI_LAYOUT_SURFACE_ORIENTATION_270_DEGREES = 3,
+};
+
+enum ivi_layout_surface_pixelformat {
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_R_8 = 0,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGB_888 = 1,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888 = 2,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGB_565 = 3,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_5551 = 4,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_6661 = 5,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_4444 = 6,
+ IVI_LAYOUT_SURFACE_PIXELFORMAT_UNKNOWN = 7,
+};
+
+struct link_layer {
+ struct ivi_layout_layer *ivilayer;
+ struct wl_list link;
+ struct wl_list link_to_layer;
+};
+
+struct link_screen {
+ struct ivi_layout_screen *iviscrn;
+ struct wl_list link;
+ struct wl_list link_to_screen;
+};
+
+struct link_layerPropertyNotification {
+ layerPropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfacePropertyNotification {
+ surfacePropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerCreateNotification {
+ layerCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerRemoveNotification {
+ layerRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceCreateNotification {
+ surfaceCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceRemoveNotification {
+ surfaceRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceConfigureNotification {
+ surfaceConfigureNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct ivi_layout;
+
+struct ivi_layout_surface {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_layer;
+ int32_t update_count;
+ uint32_t id_surface;
+
+ struct ivi_layout *layout;
+ struct weston_surface *surface;
+
+ struct wl_listener surface_destroy_listener;
+ struct weston_transform surface_rotation;
+ struct weston_transform layer_rotation;
+ struct weston_transform surface_pos;
+ struct weston_transform layer_pos;
+ struct weston_transform scaling;
+ struct ivi_layout_SurfaceProperties prop;
+ int32_t pixelformat;
+ uint32_t event_mask;
+
+ struct {
+ struct ivi_layout_SurfaceProperties prop;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list link;
+ struct wl_list list_layer;
+ } order;
+
+ struct {
+ ivi_controller_surface_content_callback callback;
+ void* userdata;
+ } content_observer;
+};
+
+struct ivi_layout_layer {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_screen;
+ struct wl_list link_to_surface;
+ uint32_t id_layer;
+
+ struct ivi_layout *layout;
+
+ struct ivi_layout_LayerProperties prop;
+ uint32_t event_mask;
+
+ struct {
+ struct ivi_layout_LayerProperties prop;
+ struct wl_list list_surface;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_surface;
+ struct wl_list link;
+ } order;
+};
+
+struct ivi_layout_screen {
+ struct wl_list link;
+ struct wl_list link_to_layer;
+ uint32_t id_screen;
+
+ struct ivi_layout *layout;
+ struct weston_output *output;
+
+ uint32_t event_mask;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } order;
+};
+
+struct ivi_layout {
+ struct weston_compositor *compositor;
+
+ struct wl_list list_surface;
+ struct wl_list list_layer;
+ struct wl_list list_screen;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ } layer_notification;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ struct wl_list list_configure;
+ } surface_notification;
+
+ struct weston_layer layout_layer;
+};
+
+static struct ivi_layout ivilayout = {0};
+
+static struct ivi_layout *
+get_instance(void)
+{
+ return &ivilayout;
+}
+
+/**
+ * Internal API to add/remove a link to surface from layer.
+ */
+static void
+add_link_to_surface(struct ivi_layout_layer *ivilayer,
+ struct link_layer *link_layer)
+{
+ struct link_layer *link = NULL;
+ int found = 0;
+
+ wl_list_for_each(link, &ivilayer->link_to_surface, link_to_layer) {
+ if (link == link_layer) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found == 0) {
+ wl_list_init(&link_layer->link_to_layer);
+ wl_list_insert(&ivilayer->link_to_surface, &link_layer->link_to_layer);
+ }
+}
+
+static void
+remove_link_to_surface(struct ivi_layout_layer *ivilayer)
+{
+ struct link_layer *link = NULL;
+ struct link_layer *next = NULL;
+
+ wl_list_for_each_safe(link, next, &ivilayer->link_to_surface, link_to_layer) {
+ if (!wl_list_empty(&link->link_to_layer)) {
+ wl_list_remove(&link->link_to_layer);
+ }
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+ free(link);
+ }
+
+ wl_list_init(&ivilayer->link_to_surface);
+}
+
+/**
+ * Internal API to add a link to layer from screen.
+ */
+static void
+add_link_to_layer(struct ivi_layout_screen *iviscrn,
+ struct link_screen *link_screen)
+{
+ wl_list_init(&link_screen->link_to_screen);
+ wl_list_insert(&iviscrn->link_to_layer, &link_screen->link_to_screen);
+}
+
+/**
+ * Internal API to add/remove a surface from layer.
+ */
+static void
+add_ordersurface_to_layer(struct ivi_layout_surface *ivisurf,
+ struct ivi_layout_layer *ivilayer)
+{
+ struct link_layer *link_layer = NULL;
+
+ link_layer = malloc(sizeof *link_layer);
+ if (link_layer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_layer->ivilayer = ivilayer;
+ wl_list_init(&link_layer->link);
+ wl_list_insert(&ivisurf->list_layer, &link_layer->link);
+ add_link_to_surface(ivilayer, link_layer);
+}
+
+static void
+remove_ordersurface_from_layer(struct ivi_layout_surface *ivisurf)
+{
+ struct link_layer *link_layer = NULL;
+ struct link_layer *next = NULL;
+
+ wl_list_for_each_safe(link_layer, next, &ivisurf->list_layer, link) {
+ if (!wl_list_empty(&link_layer->link)) {
+ wl_list_remove(&link_layer->link);
+ }
+ if (!wl_list_empty(&link_layer->link_to_layer)) {
+ wl_list_remove(&link_layer->link_to_layer);
+ }
+ free(link_layer);
+ }
+ wl_list_init(&ivisurf->list_layer);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static void
+add_orderlayer_to_screen(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_screen *iviscrn)
+{
+ struct link_screen *link_scrn = NULL;
+
+ link_scrn = malloc(sizeof *link_scrn);
+ if (link_scrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_scrn->iviscrn = iviscrn;
+ wl_list_init(&link_scrn->link);
+ wl_list_insert(&ivilayer->list_screen, &link_scrn->link);
+ add_link_to_layer(iviscrn, link_scrn);
+}
+
+static void
+remove_orderlayer_from_screen(struct ivi_layout_layer *ivilayer)
+{
+ struct link_screen *link_scrn = NULL;
+ struct link_screen *next = NULL;
+
+ wl_list_for_each_safe(link_scrn, next, &ivilayer->list_screen, link) {
+ if (!wl_list_empty(&link_scrn->link)) {
+ wl_list_remove(&link_scrn->link);
+ }
+ if (!wl_list_empty(&link_scrn->link_to_screen)) {
+ wl_list_remove(&link_scrn->link_to_screen);
+ }
+ free(link_scrn);
+ }
+ wl_list_init(&ivilayer->list_screen);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static struct ivi_layout_surface *
+get_surface(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct ivi_layout_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+static struct ivi_layout_layer *
+get_layer(struct wl_list *list_layer, uint32_t id_layer)
+{
+ struct ivi_layout_layer *ivilayer;
+
+ wl_list_for_each(ivilayer, list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Called at destruction of ivi_surface
+ */
+static void
+westonsurface_destroy_from_ivisurface(struct wl_listener *listener, void *data)
+{
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ ivisurf = container_of(listener, struct ivi_layout_surface,
+ surface_destroy_listener);
+
+ wl_list_init(&ivisurf->surface_rotation.link);
+ wl_list_init(&ivisurf->layer_rotation.link);
+ wl_list_init(&ivisurf->surface_pos.link);
+ wl_list_init(&ivisurf->layer_pos.link);
+ wl_list_init(&ivisurf->scaling.link);
+
+ ivisurf->surface = NULL;
+ ivi_layout_surfaceRemove(ivisurf);
+}
+
+/**
+ * Internal API to check layer/surface already added in layer/screen.
+ * Called by ivi_layout_layerAddSurface/ivi_layout_screenAddLayer
+ */
+static int
+is_surface_in_layer(struct ivi_layout_surface *ivisurf,
+ struct ivi_layout_layer *ivilayer)
+{
+ struct ivi_layout_surface *surf = NULL;
+
+ wl_list_for_each(surf, &ivilayer->pending.list_surface, pending.link) {
+ if (surf->id_surface == ivisurf->id_surface) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+is_layer_in_screen(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_screen *iviscrn)
+{
+ struct ivi_layout_layer *layer = NULL;
+
+ wl_list_for_each(layer, &iviscrn->pending.list_layer, pending.link) {
+ if (layer->id_layer == ivilayer->id_layer) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Internal API to initialize screens found from output_list of weston_compositor.
+ * Called by ivi_layout_initWithCompositor.
+ */
+static void
+create_screen(struct weston_compositor *ec)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_screen *iviscrn = NULL;
+ struct weston_output *output = NULL;
+ int32_t count = 0;
+
+ wl_list_for_each(output, &ec->output_list, link) {
+ iviscrn = calloc(1, sizeof *iviscrn);
+ if (iviscrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ continue;
+ }
+
+ wl_list_init(&iviscrn->link);
+ iviscrn->layout = layout;
+
+ iviscrn->id_screen = count;
+ count++;
+
+ iviscrn->output = output;
+ iviscrn->event_mask = 0;
+
+ wl_list_init(&iviscrn->pending.list_layer);
+ wl_list_init(&iviscrn->pending.link);
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_init(&iviscrn->order.link);
+
+ wl_list_init(&iviscrn->link_to_layer);
+
+ wl_list_insert(&layout->list_screen, &iviscrn->link);
+ }
+}
+
+/**
+ * Internal APIs to initialize properties of surface/layer when they are created.
+ */
+static void
+init_layerProperties(struct ivi_layout_LayerProperties *prop,
+ int32_t width, int32_t height)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+ prop->destWidth = width;
+ prop->destHeight = height;
+}
+
+static void
+init_surfaceProperties(struct ivi_layout_SurfaceProperties *prop)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+}
+
+/**
+ * Internal APIs to be called from ivi_layout_commitChanges.
+ */
+static void
+update_opacity(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ double layer_alpha = wl_fixed_to_double(ivilayer->prop.opacity);
+ double surf_alpha = wl_fixed_to_double(ivisurf->prop.opacity);
+
+ if ((ivilayer->event_mask & IVI_NOTIFICATION_OPACITY) ||
+ (ivisurf->event_mask & IVI_NOTIFICATION_OPACITY)) {
+ struct weston_view *tmpview = NULL;
+ wl_list_for_each(tmpview, &ivisurf->surface->views, surface_link)
+ {
+ if (tmpview == NULL) {
+ continue;
+ }
+ tmpview->alpha = layer_alpha * surf_alpha;
+ }
+ }
+}
+
+static void
+update_surface_orientation(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ struct weston_view *view;
+ struct weston_matrix *matrix = &ivisurf->surface_rotation.matrix;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ wl_list_for_each(view, &ivisurf->surface->views, surface_link)
+ {
+ if (view != NULL) {
+ break;
+ }
+ }
+
+ if (view == NULL) {
+ return;
+ }
+
+ if ((ivilayer->prop.destWidth == 0) ||
+ (ivilayer->prop.destHeight == 0)) {
+ return;
+ }
+ width = (float)ivilayer->prop.destWidth;
+ height = (float)ivilayer->prop.destHeight;
+
+ switch (ivisurf->prop.orientation) {
+ case IVI_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->surface_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_layer_orientation(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ struct weston_surface *es = ivisurf->surface;
+ struct weston_view *view;
+ struct weston_matrix *matrix = &ivisurf->layer_rotation.matrix;
+ struct weston_output *output = NULL;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ wl_list_for_each(view, &ivisurf->surface->views, surface_link)
+ {
+ if (view != NULL) {
+ break;
+ }
+ }
+
+ if (es == NULL || view == NULL) {
+ return;
+ }
+
+ output = es->output;
+ if (output == NULL) {
+ return;
+ }
+ if ((output->width == 0) || (output->height == 0)) {
+ return;
+ }
+ width = (float)output->width;
+ height = (float)output->height;
+
+ switch (ivilayer->prop.orientation) {
+ case IVI_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case IVI_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->layer_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->layer_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_surface_position(struct ivi_layout_surface *ivisurf)
+{
+ struct weston_view *view;
+ float tx = (float)ivisurf->prop.destX;
+ float ty = (float)ivisurf->prop.destY;
+ struct weston_matrix *matrix = &ivisurf->surface_pos.matrix;
+
+ wl_list_for_each(view, &ivisurf->surface->views, surface_link)
+ {
+ if (view != NULL) {
+ break;
+ }
+ }
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->surface_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+
+#if 0
+ /* disable zoom animation */
+ weston_zoom_run(es, 0.0, 1.0, NULL, NULL);
+#endif
+
+}
+
+static void
+update_layer_position(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ struct weston_view *view;
+ struct weston_matrix *matrix = &ivisurf->layer_pos.matrix;
+ float tx = (float)ivilayer->prop.destX;
+ float ty = (float)ivilayer->prop.destY;
+
+ wl_list_for_each(view, &ivisurf->surface->views, surface_link)
+ {
+ if (view != NULL) {
+ break;
+ }
+ }
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->layer_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(
+ &view->geometry.transformation_list,
+ &ivisurf->layer_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_scale(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ struct weston_view *view;
+ struct weston_matrix *matrix = &ivisurf->scaling.matrix;
+ float sx = 0.0f;
+ float sy = 0.0f;
+ float lw = 0.0f;
+ float sw = 0.0f;
+ float lh = 0.0f;
+ float sh = 0.0f;
+
+ wl_list_for_each(view, &ivisurf->surface->views, surface_link)
+ {
+ if (view != NULL) {
+ break;
+ }
+ }
+
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->prop.sourceWidth == 0 && ivisurf->prop.sourceHeight == 0) {
+ ivisurf->prop.sourceWidth = ivisurf->surface->width_from_buffer;
+ ivisurf->prop.sourceHeight = ivisurf->surface->height_from_buffer;
+
+ if (ivisurf->prop.destWidth == 0 && ivisurf->prop.destHeight == 0) {
+ ivisurf->prop.destWidth = ivisurf->surface->width_from_buffer;
+ ivisurf->prop.destHeight = ivisurf->surface->height_from_buffer;
+ }
+ }
+
+ lw = ((float)ivilayer->prop.destWidth / ivilayer->prop.sourceWidth );
+ sw = ((float)ivisurf->prop.destWidth / ivisurf->prop.sourceWidth );
+ lh = ((float)ivilayer->prop.destHeight / ivilayer->prop.sourceHeight);
+ sh = ((float)ivisurf->prop.destHeight / ivisurf->prop.sourceHeight );
+ sx = sw * lw;
+ sy = sh * lh;
+
+ wl_list_remove(&ivisurf->scaling.link);
+ weston_matrix_init(matrix);
+ weston_matrix_scale(matrix, sx, sy, 1.0f);
+
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->scaling.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_prop(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *ivisurf)
+{
+ if (ivilayer->event_mask | ivisurf->event_mask) {
+ update_opacity(ivilayer, ivisurf);
+ update_layer_orientation(ivilayer, ivisurf);
+ update_layer_position(ivilayer, ivisurf);
+ update_surface_position(ivisurf);
+ update_surface_orientation(ivilayer, ivisurf);
+ update_scale(ivilayer, ivisurf);
+
+ ivisurf->update_count++;
+
+ struct weston_view *tmpview;
+ wl_list_for_each(tmpview, &ivisurf->surface->views, surface_link)
+ {
+ if (tmpview != NULL) {
+ break;
+ }
+ }
+
+ if (tmpview != NULL) {
+ weston_view_geometry_dirty(tmpview);
+ }
+
+ if (ivisurf->surface != NULL) {
+ weston_surface_damage(ivisurf->surface);
+ }
+ }
+}
+
+static void
+commit_changes(struct ivi_layout *layout)
+{
+ struct ivi_layout_screen *iviscrn = NULL;
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ update_prop(ivilayer, ivisurf);
+ }
+ }
+ }
+}
+
+static void
+commit_list_surface(struct ivi_layout *layout)
+{
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ ivisurf->prop = ivisurf->pending.prop;
+ }
+}
+
+static void
+commit_list_layer(struct ivi_layout *layout)
+{
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_surface *next = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ ivilayer->prop = ivilayer->pending.prop;
+
+ if (!(ivilayer->event_mask &
+ (IVI_NOTIFICATION_ADD | IVI_NOTIFICATION_REMOVE)) ) {
+ continue;
+ }
+
+ if (ivilayer->event_mask & IVI_NOTIFICATION_REMOVE) {
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->order.list_surface, order.link) {
+ remove_ordersurface_from_layer(ivisurf);
+
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivisurf->order.link);
+ ivisurf->event_mask |= IVI_NOTIFICATION_REMOVE;
+ }
+
+ wl_list_init(&ivilayer->order.list_surface);
+ }
+
+ if (ivilayer->event_mask & IVI_NOTIFICATION_ADD) {
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->order.list_surface, order.link) {
+ remove_ordersurface_from_layer(ivisurf);
+
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_for_each(ivisurf, &ivilayer->pending.list_surface,
+ pending.link) {
+ if(!wl_list_empty(&ivisurf->order.link)){
+ wl_list_remove(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_insert(&ivilayer->order.list_surface,
+ &ivisurf->order.link);
+ add_ordersurface_to_layer(ivisurf, ivilayer);
+ ivisurf->event_mask |= IVI_NOTIFICATION_ADD;
+ }
+ }
+ }
+}
+
+static void
+commit_list_screen(struct ivi_layout *layout)
+{
+ struct ivi_layout_screen *iviscrn = NULL;
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_layer *next = NULL;
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ if (iviscrn->event_mask & IVI_NOTIFICATION_REMOVE) {
+ wl_list_for_each_safe(ivilayer, next,
+ &iviscrn->order.list_layer, order.link) {
+ remove_orderlayer_from_screen(ivilayer);
+
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.link);
+ ivilayer->event_mask |= IVI_NOTIFICATION_REMOVE;
+ }
+ }
+
+ if (iviscrn->event_mask & IVI_NOTIFICATION_ADD) {
+ wl_list_for_each_safe(ivilayer, next,
+ &iviscrn->order.list_layer, order.link) {
+ remove_orderlayer_from_screen(ivilayer);
+
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.link);
+ }
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_for_each(ivilayer, &iviscrn->pending.list_layer,
+ pending.link) {
+ wl_list_insert(&iviscrn->order.list_layer,
+ &ivilayer->order.link);
+ add_orderlayer_to_screen(ivilayer, iviscrn);
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+ }
+ }
+
+ iviscrn->event_mask = 0;
+
+ /* Clear view list of layout layer */
+ wl_list_init(&layout->layout_layer.view_list);
+
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+
+ if (ivilayer->prop.visibility == 0)
+ continue;
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ struct weston_view *tmpview = NULL;
+ wl_list_for_each(tmpview, &ivisurf->surface->views, surface_link)
+ {
+ if (tmpview != NULL) {
+ break;
+ }
+ }
+
+ if (ivisurf->prop.visibility == 0)
+ continue;
+ if (ivisurf->surface == NULL || tmpview == NULL)
+ continue;
+
+ wl_list_insert(&layout->layout_layer.view_list,
+ &tmpview->layer_link);
+
+ ivisurf->surface->output = iviscrn->output;
+ }
+ }
+
+ break;
+ }
+}
+
+static void
+send_surface_prop(struct ivi_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivisurf->list_notification, link) {
+ notification->callback(ivisurf, &ivisurf->prop,
+ ivisurf->event_mask,
+ notification->userdata);
+ }
+
+ ivisurf->event_mask = 0;
+}
+
+static void
+send_layer_prop(struct ivi_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivilayer->list_notification, link) {
+ notification->callback(ivilayer, &ivilayer->prop,
+ ivilayer->event_mask,
+ notification->userdata);
+ }
+
+ ivilayer->event_mask = 0;
+}
+
+static void
+send_prop(struct ivi_layout *layout)
+{
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each_reverse(ivilayer, &layout->list_layer, link) {
+ send_layer_prop(ivilayer);
+ }
+
+ wl_list_for_each_reverse(ivisurf, &layout->list_surface, link) {
+ send_surface_prop(ivisurf);
+ }
+}
+
+static void
+clear_surface_pending_list(struct ivi_layout_layer *ivilayer)
+{
+ struct ivi_layout_surface *surface_link = NULL;
+ struct ivi_layout_surface *surface_next = NULL;
+
+ wl_list_for_each_safe(surface_link, surface_next,
+ &ivilayer->pending.list_surface, pending.link) {
+ if (!wl_list_empty(&surface_link->pending.link)) {
+ wl_list_remove(&surface_link->pending.link);
+ }
+
+ wl_list_init(&surface_link->pending.link);
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_REMOVE;
+}
+
+static void
+clear_surface_order_list(struct ivi_layout_layer *ivilayer)
+{
+ struct ivi_layout_surface *surface_link = NULL;
+ struct ivi_layout_surface *surface_next = NULL;
+
+ wl_list_for_each_safe(surface_link, surface_next,
+ &ivilayer->order.list_surface, order.link) {
+ if (!wl_list_empty(&surface_link->order.link)) {
+ wl_list_remove(&surface_link->order.link);
+ }
+
+ wl_list_init(&surface_link->order.link);
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_REMOVE;
+}
+
+/**
+ * Exported APIs of ivi-layout library are implemented from here.
+ * Brief of APIs is described in ivi-layout-export.h.
+ */
+WL_EXPORT int32_t
+ivi_layout_addNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_layerCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("ivi_layout_addNotificationCreateLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT void
+ivi_layout_removeNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_layerCreateNotification *link = NULL;
+ struct link_layerCreateNotification *next = NULL;
+
+ wl_list_for_each_safe(link, next, &layout->layer_notification.list_create, link) {
+ if ((link->callback == callback) &&
+ (link->userdata == userdata)) {
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+
+ free(link);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+ivi_layout_addNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("ivi_layout_addNotificationRemoveLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT void
+ivi_layout_removeNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_layerRemoveNotification *link = NULL;
+ struct link_layerRemoveNotification *next = NULL;
+
+ wl_list_for_each_safe(link, next, &layout->layer_notification.list_remove, link) {
+ if ((link->callback == callback) &&
+ (link->userdata == userdata)) {
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+
+ free(link);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+ivi_layout_addNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("ivi_layout_addNotificationCreateSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT void
+ivi_layout_removeNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *link = NULL;
+ struct link_surfaceCreateNotification *next = NULL;
+
+ wl_list_for_each_safe(link, next, &layout->surface_notification.list_create, link) {
+ if ((link->callback == callback) &&
+ (link->userdata == userdata)) {
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+
+ free(link);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+ivi_layout_addNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("ivi_layout_addNotificationRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT void
+ivi_layout_removeNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *link = NULL;
+ struct link_surfaceRemoveNotification *next = NULL;
+
+ wl_list_for_each_safe(link, next, &layout->surface_notification.list_remove, link) {
+ if ((link->callback == callback) &&
+ (link->userdata == userdata)) {
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+
+ free(link);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+ivi_layout_addNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceConfigureNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("ivi_layout_addNotificationConfigureSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_configure, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT void
+ivi_layout_removeNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceConfigureNotification *link = NULL;
+ struct link_surfaceConfigureNotification *next = NULL;
+
+ wl_list_for_each_safe(link, next, &layout->surface_notification.list_configure, link) {
+ if ((link->callback == callback) &&
+ (link->userdata == userdata)) {
+ if (!wl_list_empty(&link->link)) {
+ wl_list_remove(&link->link);
+ }
+
+ free(link);
+ }
+ }
+}
+
+WL_EXPORT uint32_t
+ivi_layout_getIdOfSurface(struct ivi_layout_surface *ivisurf)
+{
+ return ivisurf->id_surface;
+}
+
+WL_EXPORT uint32_t
+ivi_layout_getIdOfLayer(struct ivi_layout_layer *ivilayer)
+{
+ return ivilayer->id_layer;
+}
+
+WL_EXPORT struct ivi_layout_layer *
+ivi_layout_getLayerFromId(uint32_t id_layer)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_layer *ivilayer = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct ivi_layout_surface *
+ivi_layout_getSurfaceFromId(uint32_t id_surface)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct ivi_layout_screen *
+ivi_layout_getScreenFromId(uint32_t id_screen)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_screen *iviscrn = NULL;
+ (void)id_screen;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+//FIXME : select iviscrn from list_screen by id_screen
+ return iviscrn;
+ break;
+ }
+
+ return NULL;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getScreenResolution(struct ivi_layout_screen *iviscrn,
+ int32_t *pWidth, int32_t *pHeight)
+{
+ struct weston_output *output = NULL;
+
+ if (pWidth == NULL || pHeight == NULL) {
+ weston_log("ivi_layout_getScreenResolution: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ *pWidth = output->current_mode->width;
+ *pHeight = output->current_mode->height;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceAddNotification(struct ivi_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ if (ivisurf == NULL || callback == NULL) {
+ weston_log("ivi_layout_surfaceAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivisurf->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceRemoveNotification(struct ivi_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+ struct link_surfacePropertyNotification *next = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivisurf->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ }
+ wl_list_init(&ivisurf->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceRemove(struct ivi_layout_surface *ivisurf)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceRemove: invalid argument\n");
+ return -1;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+ if (!wl_list_empty(&ivisurf->link)) {
+ wl_list_remove(&ivisurf->link);
+ }
+ remove_ordersurface_from_layer(ivisurf);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+ ivi_layout_surfaceRemoveNotification(ivisurf);
+
+ free(ivisurf);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_UpdateInputEventAcceptanceOn(struct ivi_layout_surface *ivisurf,
+ int32_t devices, int32_t acceptance)
+{
+ /* TODO */
+ (void)ivisurf;
+ (void)devices;
+ (void)acceptance;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceInitialize(struct ivi_layout_surface **pSurfaceId)
+{
+ /* TODO */
+ (void)pSurfaceId;
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getPropertiesOfLayer(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_LayerProperties *pLayerProperties)
+{
+ if (ivilayer == NULL || pLayerProperties == NULL) {
+ weston_log("ivi_layout_getPropertiesOfLayer: invalid argument\n");
+ return -1;
+ }
+
+ *pLayerProperties = ivilayer->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ int32_t *pNumberOfHardwareLayers)
+{
+ /* TODO */
+ (void)id_screen;
+ (void)pNumberOfHardwareLayers;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getScreens(int32_t *pLength, struct ivi_layout_screen ***ppArray)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_screen *iviscrn = NULL;
+ int32_t length = 0;
+ int32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getScreens: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(struct ivi_layout_screen *));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ (*ppArray)[n++] = iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getScreensUnderLayer(struct ivi_layout_layer *ivilayer,
+ int32_t *pLength,
+ struct ivi_layout_screen ***ppArray)
+{
+ struct link_screen *link_scrn = NULL;
+ int32_t length = 0;
+ int32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getScreensUnderLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(struct ivi_layout_screen *));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_scrn, &ivilayer->list_screen, link) {
+ (*ppArray)[n++] = link_scrn->iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getLayers(int32_t *pLength, struct ivi_layout_layer ***ppArray)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_layer *ivilayer = NULL;
+ int32_t length = 0;
+ int32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(struct ivi_layout_layer *));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getLayersOnScreen(struct ivi_layout_screen *iviscrn,
+ int32_t *pLength,
+ struct ivi_layout_layer ***ppArray)
+{
+ struct ivi_layout_layer *ivilayer = NULL;
+ int32_t length = 0;
+ int32_t n = 0;
+
+ if (iviscrn == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getLayersOnScreen: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&iviscrn->order.list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(struct ivi_layout_layer *));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getLayersUnderSurface(struct ivi_layout_surface *ivisurf,
+ int32_t *pLength,
+ struct ivi_layout_layer ***ppArray)
+{
+ struct link_layer *link_layer = NULL;
+ int32_t length = 0;
+ int32_t n = 0;
+
+ if (ivisurf == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivisurf->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(struct ivi_layout_layer *));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_layer, &ivisurf->list_layer, link) {
+ (*ppArray)[n++] = link_layer->ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getSurfaces(int32_t *pLength, struct ivi_layout_surface ***ppArray)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t length = 0;
+ int32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getSurfaces: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_surface);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(struct ivi_layout_surface *));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getSurfacesOnLayer(struct ivi_layout_layer *ivilayer,
+ int32_t *pLength,
+ struct ivi_layout_surface ***ppArray)
+{
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t length = 0;
+ int32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("ivi_layout_getSurfaceIDsOnLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->order.list_surface);
+
+ if (length != 0) {
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(struct ivi_layout_surface *));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT struct ivi_layout_layer *
+ivi_layout_layerCreateWithDimension(uint32_t id_layer,
+ int32_t width, int32_t height)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct link_layerCreateNotification *notification = NULL;
+
+ ivilayer = get_layer(&layout->list_layer, id_layer);
+ if (ivilayer != NULL) {
+ weston_log("id_layer is already created\n");
+ return ivilayer;
+ }
+
+ ivilayer = calloc(1, sizeof *ivilayer);
+ if (ivilayer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivilayer->link);
+ wl_list_init(&ivilayer->list_notification);
+ wl_list_init(&ivilayer->list_screen);
+ wl_list_init(&ivilayer->link_to_surface);
+ ivilayer->layout = layout;
+ ivilayer->id_layer = id_layer;
+
+ init_layerProperties(&ivilayer->prop, width, height);
+ ivilayer->event_mask = 0;
+
+ wl_list_init(&ivilayer->pending.list_surface);
+ wl_list_init(&ivilayer->pending.link);
+ ivilayer->pending.prop = ivilayer->prop;
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_init(&ivilayer->order.link);
+
+ wl_list_insert(&layout->list_layer, &ivilayer->link);
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ return ivilayer;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerRemove(struct ivi_layout_layer *ivilayer)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerRemove: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ clear_surface_pending_list(ivilayer);
+ clear_surface_order_list(ivilayer);
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+ if (!wl_list_empty(&ivilayer->link)) {
+ wl_list_remove(&ivilayer->link);
+ }
+ remove_orderlayer_from_screen(ivilayer);
+ remove_link_to_surface(ivilayer);
+ ivi_layout_layerRemoveNotification(ivilayer);
+
+ free(ivilayer);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetType(struct ivi_layout_layer *ivilayer,
+ int32_t *pLayerType)
+{
+ /* TODO */
+ (void)ivilayer;
+ (void)pLayerType;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetVisibility(struct ivi_layout_layer *ivilayer,
+ int32_t newVisibility)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetVisibility(struct ivi_layout_layer *ivilayer, int32_t *pVisibility)
+{
+ if (ivilayer == NULL || pVisibility == NULL) {
+ weston_log("ivi_layout_layerGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivilayer->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetOpacity(struct ivi_layout_layer *ivilayer,
+ float opacity)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->opacity = opacity;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetOpacity(struct ivi_layout_layer *ivilayer,
+ float *pOpacity)
+{
+ if (ivilayer == NULL || pOpacity == NULL) {
+ weston_log("ivi_layout_layerGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivilayer->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetSourceRectangle(struct ivi_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetDestinationRectangle(struct ivi_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetDimension(struct ivi_layout_layer *ivilayer,
+ int32_t *pDimension)
+{
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("ivi_layout_layerGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivilayer->prop.destX;
+ pDimension[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetDimension(struct ivi_layout_layer *ivilayer,
+ int32_t *pDimension)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("ivi_layout_layerSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetPosition(struct ivi_layout_layer *ivilayer, int32_t *pPosition)
+{
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("ivi_layout_layerGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivilayer->prop.destX;
+ pPosition[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetPosition(struct ivi_layout_layer *ivilayer, int32_t *pPosition)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("ivi_layout_layerSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetOrientation(struct ivi_layout_layer *ivilayer,
+ int32_t orientation)
+{
+ struct ivi_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->orientation = orientation;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetOrientation(struct ivi_layout_layer *ivilayer,
+ int32_t *pOrientation)
+{
+ if (ivilayer == NULL || pOrientation == NULL) {
+ weston_log("ivi_layout_layerGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivilayer->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetChromaKey(struct ivi_layout_layer *ivilayer, int32_t* pColor)
+{
+ /* TODO */
+ (void)ivilayer;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerSetRenderOrder(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface **pSurface,
+ int32_t number)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_surface *next = NULL;
+ uint32_t *id_surface = NULL;
+ int32_t i = 0;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ if (pSurface == NULL) {
+ wl_list_for_each_safe(ivisurf, next, &ivilayer->pending.list_surface, pending.link) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+
+ wl_list_init(&ivisurf->pending.link);
+ }
+ ivilayer->event_mask |= IVI_NOTIFICATION_REMOVE;
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_surface = &pSurface[i]->id_surface;
+
+ wl_list_for_each_safe(ivisurf, next, &layout->list_surface, pending.link) {
+ if (*id_surface != ivisurf->id_surface) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerGetCapabilities(struct ivi_layout_layer *ivilayer,
+ int32_t *pCapabilities)
+{
+ /* TODO */
+ (void)ivilayer;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerTypeGetCapabilities(int32_t layerType,
+ int32_t *pCapabilities)
+{
+ /* TODO */
+ (void)layerType;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetVisibility(struct ivi_layout_surface *ivisurf,
+ int32_t newVisibility)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetVisibility(struct ivi_layout_surface *ivisurf,
+ int32_t *pVisibility)
+{
+ if (ivisurf == NULL || pVisibility == NULL) {
+ weston_log("ivi_layout_surfaceGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivisurf->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetOpacity(struct ivi_layout_surface *ivisurf,
+ float opacity)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->opacity = opacity;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetOpacity(struct ivi_layout_surface *ivisurf,
+ float *pOpacity)
+{
+ if (ivisurf == NULL || pOpacity == NULL) {
+ weston_log("ivi_layout_surfaceGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivisurf->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_SetKeyboardFocusOn(struct ivi_layout_surface *ivisurf)
+{
+ /* TODO */
+ (void)ivisurf;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_GetKeyboardFocusSurfaceId(struct ivi_layout_surface **pSurfaceId)
+{
+ /* TODO */
+ (void)pSurfaceId;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetDestinationRectangle(struct ivi_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetDimension(struct ivi_layout_surface *ivisurf, int32_t *pDimension)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("ivi_layout_surfaceSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetDimension(struct ivi_layout_surface *ivisurf,
+ int32_t *pDimension)
+{
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("ivi_layout_surfaceGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivisurf->prop.destWidth;
+ pDimension[1] = ivisurf->prop.destHeight;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetPosition(struct ivi_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("ivi_layout_surfaceSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetPosition(struct ivi_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("ivi_layout_surfaceGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivisurf->prop.destX;
+ pPosition[1] = ivisurf->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetOrientation(struct ivi_layout_surface *ivisurf,
+ int32_t orientation)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->orientation = orientation;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetOrientation(struct ivi_layout_surface *ivisurf,
+ int32_t *pOrientation)
+{
+ if (ivisurf == NULL || pOrientation == NULL) {
+ weston_log("ivi_layout_surfaceGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivisurf->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceGetPixelformat(struct ivi_layout_layer *ivisurf, int32_t *pPixelformat)
+{
+ /* TODO */
+ (void)ivisurf;
+ (void)pPixelformat;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetChromaKey(struct ivi_layout_surface *ivisurf, int32_t* pColor)
+{
+ /* TODO */
+ (void)ivisurf;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_screenAddLayer(struct ivi_layout_screen *iviscrn,
+ struct ivi_layout_layer *addlayer)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_layer *next = NULL;
+ int is_layer_in_scrn = 0;
+
+ if (iviscrn == NULL || addlayer == NULL) {
+ weston_log("ivi_layout_screenAddLayer: invalid argument\n");
+ return -1;
+ }
+
+ is_layer_in_scrn = is_layer_in_screen(addlayer, iviscrn);
+ if (is_layer_in_scrn == 1) {
+ weston_log("ivi_layout_screenAddLayer: addlayer is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivilayer, next, &layout->list_layer, link) {
+ if (ivilayer->id_layer == addlayer->id_layer) {
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_screenSetRenderOrder(struct ivi_layout_screen *iviscrn,
+ struct ivi_layout_layer **pLayer,
+ const int32_t number)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_layer *ivilayer = NULL;
+ struct ivi_layout_layer *next = NULL;
+ uint32_t *id_layer = NULL;
+ int32_t i = 0;
+
+ if (iviscrn == NULL) {
+ weston_log("ivi_layout_screenSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(ivilayer, next,
+ &iviscrn->pending.list_layer, pending.link) {
+ wl_list_init(&ivilayer->pending.link);
+ }
+
+ wl_list_init(&iviscrn->pending.list_layer);
+
+ if (pLayer == NULL) {
+ wl_list_for_each_safe(ivilayer, next, &iviscrn->pending.list_layer, pending.link) {
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+
+ wl_list_init(&ivilayer->pending.link);
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_REMOVE;
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_layer = &pLayer[i]->id_layer;
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (*id_layer != ivilayer->id_layer) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT struct weston_output *
+ivi_layout_screenGetOutput(struct ivi_layout_screen *iviscrn)
+{
+ return iviscrn->output;
+}
+
+WL_EXPORT int32_t
+ivi_layout_SetOptimizationMode(uint32_t id, int32_t mode)
+{
+ /* TODO */
+ (void)id;
+ (void)mode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_GetOptimizationMode(uint32_t id, int32_t *pMode)
+{
+ /* TODO */
+ (void)id;
+ (void)pMode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerAddNotification(struct ivi_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ if (ivilayer == NULL || callback == NULL) {
+ weston_log("ivi_layout_layerAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivilayer->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerRemoveNotification(struct ivi_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+ struct link_layerPropertyNotification *next = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("ivi_layout_layerRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivilayer->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ }
+ wl_list_init(&ivilayer->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_getPropertiesOfSurface(struct ivi_layout_surface *ivisurf,
+ struct ivi_layout_SurfaceProperties *pSurfaceProperties)
+{
+ if (ivisurf == NULL || pSurfaceProperties == NULL) {
+ weston_log("ivi_layout_getPropertiesOfSurface: invalid argument\n");
+ return -1;
+ }
+
+ *pSurfaceProperties = ivisurf->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerAddSurface(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *addsurf)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_surface *next = NULL;
+ int is_surf_in_layer = 0;
+
+ if (ivilayer == NULL || addsurf == NULL) {
+ weston_log("ivi_layout_layerAddSurface: invalid argument\n");
+ return -1;
+ }
+
+ is_surf_in_layer = is_surface_in_layer(addsurf, ivilayer);
+ if (is_surf_in_layer == 1) {
+ weston_log("ivi_layout_layerAddSurface: addsurf is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivisurf, next, &layout->list_surface, link) {
+ if (ivisurf->id_surface == addsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_layerRemoveSurface(struct ivi_layout_layer *ivilayer,
+ struct ivi_layout_surface *remsurf)
+{
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_surface *next = NULL;
+
+ if (ivilayer == NULL || remsurf == NULL) {
+ weston_log("ivi_layout_layerRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->pending.list_surface, pending.link) {
+ if (ivisurf->id_surface == remsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ break;
+ }
+ }
+
+ remsurf->event_mask |= IVI_NOTIFICATION_REMOVE;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetSourceRectangle(struct ivi_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ struct ivi_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("ivi_layout_surfaceSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_commitChanges(void)
+{
+ struct ivi_layout *layout = get_instance();
+
+ commit_list_surface(layout);
+ commit_list_layer(layout);
+ commit_list_screen(layout);
+
+ commit_changes(layout);
+ send_prop(layout);
+ weston_compositor_schedule_repaint(layout->compositor);
+
+ return 0;
+}
+
+/***called from ivi-shell**/
+static struct weston_view *
+ivi_layout_get_weston_view(struct ivi_layout_surface *surface)
+{
+ if(surface == NULL) return NULL;
+ struct weston_view *tmpview = NULL;
+ wl_list_for_each(tmpview, &surface->surface->views, surface_link)
+ {
+ if (tmpview != NULL) {
+ break;
+ }
+ }
+ return tmpview;
+}
+
+static void
+ivi_layout_surfaceConfigure(struct ivi_layout_surface *ivisurf,
+ int32_t width, int32_t height)
+{
+ struct ivi_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf->surface->width_from_buffer = width;
+ ivisurf->surface->height_from_buffer = height;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_configure, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+}
+
+static int32_t
+ivi_layout_surfaceSetNativeContent(struct weston_surface *surface,
+ int32_t width,
+ int32_t height,
+ uint32_t id_surface)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf == NULL) {
+ weston_log("layout surface is not found\n");
+ return -1;
+ }
+
+ if (ivisurf->surface != NULL) {
+ if (surface != NULL) {
+ weston_log("id_surface(%d) is already set the native content\n",
+ id_surface);
+ return -1;
+ }
+
+ wl_list_remove(&ivisurf->surface_destroy_listener.link);
+
+ ivisurf->surface = NULL;
+
+ wl_list_remove(&ivisurf->surface_rotation.link);
+ wl_list_remove(&ivisurf->layer_rotation.link);
+ wl_list_remove(&ivisurf->surface_pos.link);
+ wl_list_remove(&ivisurf->layer_pos.link);
+ wl_list_remove(&ivisurf->scaling.link);
+ wl_list_init(&ivisurf->surface_rotation.link);
+ wl_list_init(&ivisurf->layer_rotation.link);
+ wl_list_init(&ivisurf->surface_pos.link);
+ wl_list_init(&ivisurf->layer_pos.link);
+ wl_list_init(&ivisurf->scaling.link);
+
+ }
+
+ if (surface == NULL) {
+ if (ivisurf->content_observer.callback) {
+ (*(ivisurf->content_observer.callback))(ivisurf,
+ 0, ivisurf->content_observer.userdata);
+ }
+
+ ivi_layout_surfaceRemoveNotification(ivisurf);
+ return 0;
+ }
+
+ ivisurf->surface = surface;
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(surface->resource,
+ &ivisurf->surface_destroy_listener);
+
+ struct weston_view *tmpview = weston_view_create(surface);
+ if (tmpview == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ ivisurf->surface->width_from_buffer = width;
+ ivisurf->surface->height_from_buffer = height;
+ ivisurf->pixelformat = IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ if (ivisurf->content_observer.callback) {
+ (*(ivisurf->content_observer.callback))(ivisurf,
+ 1, ivisurf->content_observer.userdata);
+ }
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+ivi_layout_surfaceSetContentObserver(struct ivi_layout_surface *ivisurf,
+ ivi_controller_surface_content_callback callback,
+ void* userdata)
+{
+ int32_t ret = -1;
+ if (ivisurf != NULL) {
+ ivisurf->content_observer.callback = callback;
+ ivisurf->content_observer.userdata = userdata;
+ ret = 0;
+ }
+ return ret;
+}
+
+static struct ivi_layout_surface*
+ivi_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface)
+{
+ struct ivi_layout *layout = get_instance();
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (wl_surface == NULL) {
+ weston_log("ivi_layout_surfaceCreate: invalid argument\n");
+ return NULL;
+ }
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf != NULL) {
+ if (ivisurf->surface != NULL) {
+ weston_log("id_surface(%d) is already created\n", id_surface);
+ return NULL;
+ } else {
+ /* if ivisurf->surface exist, wl_surface is tied to id_surface again */
+ /* This means client destroys ivi_surface once, and then tries to tie
+ the id_surface to new wl_surface again. The property of id_surface can
+ be inherited.
+ */
+ ivi_layout_surfaceSetNativeContent(
+ wl_surface, wl_surface->width, wl_surface->height, id_surface);
+ return ivisurf;
+ }
+ }
+
+ ivisurf = calloc(1, sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivisurf->link);
+ wl_list_init(&ivisurf->list_notification);
+ wl_list_init(&ivisurf->list_layer);
+ ivisurf->id_surface = id_surface;
+ ivisurf->layout = layout;
+
+ ivisurf->surface = wl_surface;
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(wl_surface->resource,
+ &ivisurf->surface_destroy_listener);
+
+ struct weston_view *tmpview = weston_view_create(wl_surface);
+ if (tmpview == NULL) {
+ weston_log("fails to allocate memory\n");
+ }
+
+ ivisurf->surface->width_from_buffer = 0;
+ ivisurf->surface->height_from_buffer = 0;
+
+ weston_matrix_init(&ivisurf->surface_rotation.matrix);
+ weston_matrix_init(&ivisurf->layer_rotation.matrix);
+ weston_matrix_init(&ivisurf->surface_pos.matrix);
+ weston_matrix_init(&ivisurf->layer_pos.matrix);
+ weston_matrix_init(&ivisurf->scaling.matrix);
+
+ wl_list_init(&ivisurf->surface_rotation.link);
+ wl_list_init(&ivisurf->layer_rotation.link);
+ wl_list_init(&ivisurf->surface_pos.link);
+ wl_list_init(&ivisurf->layer_pos.link);
+ wl_list_init(&ivisurf->scaling.link);
+
+ init_surfaceProperties(&ivisurf->prop);
+ ivisurf->pixelformat = IVI_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+ ivisurf->event_mask = 0;
+
+ ivisurf->pending.prop = ivisurf->prop;
+ wl_list_init(&ivisurf->pending.link);
+
+ wl_list_init(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.list_layer);
+
+ wl_list_insert(&layout->list_surface, &ivisurf->link);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return ivisurf;
+}
+
+static void
+ivi_layout_initWithCompositor(struct weston_compositor *ec)
+{
+ struct ivi_layout *layout = get_instance();
+
+ layout->compositor = ec;
+
+ wl_list_init(&layout->list_surface);
+ wl_list_init(&layout->list_layer);
+ wl_list_init(&layout->list_screen);
+
+ wl_list_init(&layout->layer_notification.list_create);
+ wl_list_init(&layout->layer_notification.list_remove);
+
+ wl_list_init(&layout->surface_notification.list_create);
+ wl_list_init(&layout->surface_notification.list_remove);
+ wl_list_init(&layout->surface_notification.list_configure);
+
+ /* Add layout_layer at the last of weston_compositor.layer_list */
+ weston_layer_init(&layout->layout_layer, ec->layer_list.prev);
+
+ create_screen(ec);
+
+ struct weston_config *config = weston_config_parse("weston.ini");
+ struct weston_config_section *s =
+ weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ /*A cursor is configured if weston.ini has keys.*/
+ char* cursor_theme = NULL;
+ weston_config_section_get_string(s, "cursor-theme", &cursor_theme, NULL);
+ if (cursor_theme)
+ free(cursor_theme);
+ else
+ wl_list_remove(&ec->cursor_layer.link);
+ weston_config_destroy(config);
+}
+
+
+WL_EXPORT struct ivi_layout_interface ivi_layout_interface = {
+ .get_weston_view = ivi_layout_get_weston_view,
+ .surfaceConfigure = ivi_layout_surfaceConfigure,
+ .surfaceSetNativeContent = ivi_layout_surfaceSetNativeContent,
+ .surfaceCreate = ivi_layout_surfaceCreate,
+ .initWithCompositor = ivi_layout_initWithCompositor
+};
--
1.8.3.1
Nobuhiko Tanibata
2014-06-25 12:07:08 UTC
Permalink
This protocol realizes following features,
- UI ready
- changing modes; tiling, side by side, full_screen, and random
- Give control a surface; workspace to be controlled by using ivi layout APIs
- Display/undisplay a surface; home contains sevaral workspaces to launch
application

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- apply review comments from mailing list

Changes for v6:
- the same as v5

protocol/Makefile.am | 3 +-
protocol/ivi-hmi-controller.xml | 96 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 98 insertions(+), 1 deletion(-)
create mode 100644 protocol/ivi-hmi-controller.xml

diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 9913f16..140aef5 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -9,7 +9,8 @@ protocol_sources = \
wayland-test.xml \
xdg-shell.xml \
scaler.xml \
- ivi-application.xml
+ ivi-application.xml \
+ ivi-hmi-controller.xml

if HAVE_XMLLINT
.PHONY: validate
diff --git a/protocol/ivi-hmi-controller.xml b/protocol/ivi-hmi-controller.xml
new file mode 100644
index 0000000..fd5ce2b
--- /dev/null
+++ b/protocol/ivi-hmi-controller.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ivi_hmi_controller">
+
+ <copyright>
+ Copyright (C) 2013 DENSO CORPORATION
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ </copyright>
+
+ <interface name="ivi_hmi_controller" version="1">
+ <description summary="set up and control IVI style UI"/>
+
+ <request name="UI_ready">
+ <description summary="inform the ready for drawing desktop." />
+ </request>
+
+ <request name="workspace_control">
+ <description summary="start controlling a surface by server">
+ Reference protocol to control a surface by server.
+ To control a surface by server, it gives seat to the server
+ to e.g. control Home screen. Home screen has several workspaces
+ to group launchers of wayland application. These workspaces
+ are drawn on a horizontally long surface to be controlled
+ by motion of input device. E.g. A motion from right to left
+ happens, the viewport of surface is controlled in the ivi-shell
+ by using ivi-layout. client can recognizes the end of controlling
+ by event "workspace_end_control".
+ </description>
+ <arg name="seat" type="object" interface="wl_seat"/>
+ <arg name="serial" type="uint"/>
+ </request>
+
+ <enum name="layout_mode">
+ <entry name="tiling" value="0"/>
+ <entry name="side_by_side" value="1"/>
+ <entry name="full_screen" value="2"/>
+ <entry name="random" value="3" />
+ </enum>
+
+ <request name="switch_mode">
+ <description summary="request mode switch of application layout">
+ hmi-controller loaded to ivi-shall implements 4 types of layout
+ as a reference; tiling, side by side, full_screen, and random.
+ </description>
+ <arg name="layout_mode" type="uint"/>
+ </request>
+
+ <enum name="home">
+ <entry name="off" value="0"/>
+ <entry name="on" value="1"/>
+ </enum>
+
+ <request name="home">
+ <description summary="request displaying/undisplaying home screen">
+ home screen is a reference implementation of launcher to launch
+ wayland applications. The home screen has several workspaces to
+ group wayland applications. By defining the following keys in
+ weston.ini, user can add launcher icon to launch a wayland application
+ to a workspace.
+ [ivi-launcher]
+ workspace-id=0
+ : id of workspace to add a launcher
+ icon-id=4001
+ : ivi id of ivi_surface to draw a icon
+ icon=/home/user/review/build-ivi-shell/data/icon_ivi_flower.png
+ : path to icon image
+ path=/home/user/review/build-ivi-shell/weston-dnd
+ : path to wayland application
+ </description>
+ <arg name="home" type="uint"/>
+ </request>
+
+ <event name="workspace_end_control">
+ <description summary="notify controlling workspace end"/>
+ <arg name="is_controlled" type="int"/>
+ </event>
+
+ </interface>
+
+</protocol>
--
1.8.3.1
Nobuhiko Tanibata
2014-06-25 12:07:35 UTC
Permalink
The library is used to manage layout of surfaces/layers. Layout change
is triggered by ivi-hmi-controller protocol, ivi-hmi-controller.xml. A
reference how to use the protocol, see hmi-controller-homescreen.

In-Vehicle Infotainment system usually manage properties of
surfaces/layers by only a central component which decide where
surfaces/layers shall be. This reference show examples to implement the
central component as a module of weston.

Default Scene graph of UI is defined in hmi_controller_create. It
consists of
- In the bottom, a base layer to group surfaces of background, panel,
and buttons
- Next, a application layer to show application surfaces.
- Workspace background layer to show a surface of background image.
- Workspace layer to show launcher to launch application with icons.
Paths to binary and icon are defined in weston.ini. The width of
this layer is longer than the size of screen because a workspace
has several pages and is controlled by motion of input.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- apply review comments from mailing list

Changes for v6:
- apply review comments from mailing list
- use signed integers except flags, bitfields, object ids.

Makefile.am | 20 +-
ivi-shell/.gitignore | 7 +
ivi-shell/hmi-controller.c | 1925 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1951 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/.gitignore
create mode 100644 ivi-shell/hmi-controller.c

diff --git a/Makefile.am b/Makefile.am
index e8bcb1b..1f75cc3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -704,7 +704,8 @@ if ENABLE_IVI_SHELL

module_LTLIBRARIES += \
$(ivi_shell) \
- $(ivi_layout)
+ $(ivi_layout) \
+ $(hmi_controller)

ivi_shell = ivi-shell.la
ivi_shell_la_LDFLAGS = -module -avoid-version
@@ -720,6 +721,7 @@ nodist_ivi_shell_la_SOURCES = \

BUILT_SOURCES += $(nodist_ivi_shell_la_SOURCES)

+
ivi_layout = ivi-layout.la
ivi_layout_la_LDFLAGS = -module -avoid-version
ivi_layout_la_LIBADD = $(COMPOSITOR_LIBS) $(IVI_SHELL_LIBS) libshared.la
@@ -734,6 +736,22 @@ nodist_ivi_layout_la_SOURCES = \

BUILT_SOURCES += $(nodist_ivi_layout_la_SOURCES)

+hmi_controller = hmi-controller.la
+hmi_controller_la_LDFLAGS = -module -avoid-version
+hmi_controller_la_LIBADD = $(CLIENT_LIBS) $(IVI_SHELL_LIBS) libshared-cairo.la
+hmi_controller_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
+hmi_controller_la_SOURCES = \
+ ivi-shell/ivi-layout-export.h \
+ ivi-shell/hmi-controller.c
+nodist_hmi_controller_la_SOURCES = \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-client-protocol.h \
+ protocol/ivi-hmi-controller-protocol.c \
+ protocol/ivi-hmi-controller-client-protocol.h \
+ protocol/ivi-hmi-controller-server-protocol.h
+
+BUILT_SOURCES += $(nodist_hmi_controller_la_SOURCES)
+
endif


diff --git a/ivi-shell/.gitignore b/ivi-shell/.gitignore
new file mode 100644
index 0000000..9f31bfd
--- /dev/null
+++ b/ivi-shell/.gitignore
@@ -0,0 +1,7 @@
+ivi-application-client-protocol.h
+ivi-application-protocol.c
+ivi-application-server-protocol.h
+ivi-hmi-controller-client-protocol.h
+ivi-hmi-controller-protocol.c
+ivi-hmi-controller-server-protocol.h
+weston.ini
diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
new file mode 100644
index 0000000..e04fe61
--- /dev/null
+++ b/ivi-shell/hmi-controller.c
@@ -0,0 +1,1925 @@
+/*
+ * Copyright (C) 2014 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * A reference implementation how to use ivi-layout APIs in order to manage
+ * layout of surfaces/layers. Layout change is triggered by ivi-hmi-controller
+ * protocol, ivi-hmi-controller.xml. A reference how to use the protocol, see
+ * hmi-controller-homescreen.
+ *
+ * In-Vehicle Infotainment system usually manage properties of surfaces/layers
+ * by only a central component which decide where surfaces/layers shall be. This
+ * reference show examples to implement the central component as a module of weston.
+ *
+ * Default Scene graph of UI is defined in hmi_controller_create. It consists of
+ * - In the bottom, a base layer to group surfaces of background, panel,
+ * and buttons
+ * - Next, a application layer to show application surfaces.
+ * - Workspace background layer to show a surface of background image.
+ * - Workspace layer to show launcher to launch application with icons. Paths to
+ * binary and icon are defined in weston.ini. The width of this layer is longer
+ * than the size of screen because a workspace has several pages and is controlled
+ * by motion of input.
+ *
+ * TODO: animation method shall be refined
+ * TODO: support fade-in when UI is ready
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <assert.h>
+#include <time.h>
+
+#include "ivi-layout-export.h"
+#include "ivi-hmi-controller-server-protocol.h"
+
+/*****************************************************************************
+ * structure, globals
+ ****************************************************************************/
+struct hmi_controller_layer {
+ struct ivi_layout_layer *ivilayer;
+ uint32_t id_layer;
+ int32_t x;
+ int32_t y;
+ int32_t width;
+ int32_t height;
+};
+
+struct link_layer {
+ struct ivi_layout_layer *layout_layer;
+ struct wl_list link;
+};
+
+struct link_animation {
+ struct hmi_controller_animation *animation;
+ struct wl_list link;
+};
+
+struct hmi_controller_animation;
+typedef void (*hmi_controller_animation_frame_func)(void *animation, int32_t timestamp);
+typedef void (*hmi_controller_animation_frame_user_func)(void *animation);
+typedef void (*hmi_controller_animation_destroy_func)(struct hmi_controller_animation *animation);
+
+struct move_animation_user_data {
+ struct ivi_layout_layer* layer;
+ struct animation_set *anima_set;
+ struct hmi_controller *hmi_ctrl;
+};
+
+struct hmi_controller_animation {
+ void *user_data;
+ uint32_t time_start;
+ int32_t is_done;
+ hmi_controller_animation_frame_func frame_func;
+ hmi_controller_animation_frame_user_func frame_user_func;
+ hmi_controller_animation_destroy_func destroy_func;
+};
+
+struct hmi_controller_animation_fade {
+ struct hmi_controller_animation base;
+ double start;
+ double end;
+ struct weston_spring spring;
+};
+
+struct hmi_controller_animation_move {
+ struct hmi_controller_animation base;
+ double pos;
+ double pos_start;
+ double pos_end;
+ double v0;
+ double a;
+ double time_end;
+};
+
+struct hmi_controller_fade {
+ int32_t isFadeIn;
+ struct hmi_controller_animation_fade *animation;
+ struct animation_set *anima_set;
+ struct wl_list layer_list;
+};
+
+struct animation_set {
+ struct wl_event_source *event_source;
+ struct wl_list animation_list;
+};
+
+struct
+hmi_server_setting {
+ uint32_t base_layer_id;
+ uint32_t application_layer_id;
+ uint32_t workspace_background_layer_id;
+ uint32_t workspace_layer_id;
+ int32_t panel_height;
+ char *ivi_homescreen;
+};
+
+struct hmi_controller
+{
+ struct hmi_server_setting *hmi_setting;
+ struct hmi_controller_layer base_layer;
+ struct hmi_controller_layer application_layer;
+ struct hmi_controller_layer workspace_background_layer;
+ struct hmi_controller_layer workspace_layer;
+ enum ivi_hmi_controller_layout_mode layout_mode;
+
+ struct animation_set *anima_set;
+ struct hmi_controller_fade workspace_fade;
+ struct hmi_controller_animation_move *workspace_swipe_animation;
+ int32_t workspace_count;
+ struct wl_array ui_widgets;
+ int32_t is_initialized;
+};
+
+struct launcher_info
+{
+ uint32_t surface_id;
+ uint32_t workspace_id;
+ int32_t index;
+};
+
+/*****************************************************************************
+ * local functions
+ ****************************************************************************/
+static void *
+fail_on_null(void *p, size_t size, char* file, int32_t line)
+{
+ if (size && !p) {
+ fprintf(stderr, "%s(%d) %zd: out of memory\n", file, line, size);
+ exit(EXIT_FAILURE);
+ }
+
+ return p;
+}
+
+static void *
+mem_alloc(size_t size, char* file, int32_t line)
+{
+ return fail_on_null(calloc(1, size), size, file, line);
+}
+
+#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
+
+static int32_t
+is_surf_in_uiWidget(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface *ivisurf)
+{
+ uint32_t id = ivi_layout_getIdOfSurface(ivisurf);
+
+ uint32_t *ui_widget_id = NULL;
+ wl_array_for_each (ui_widget_id, &hmi_ctrl->ui_widgets) {
+ if (*ui_widget_id == id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+compare_launcher_info(const void *lhs, const void *rhs)
+{
+ const struct launcher_info *left = (const struct launcher_info *)lhs;
+ const struct launcher_info *right = (const struct launcher_info *)rhs;
+
+ if (left->workspace_id < right->workspace_id) {
+ return -1;
+ }
+
+ if (left->workspace_id > right->workspace_id) {
+ return 1;
+ }
+
+ if (left->index < right->index) {
+ return -1;
+ }
+
+ if (left->index > right->index) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Internal methods called by mainly ivi_hmi_controller_switch_mode
+ * This reference shows 4 examples how to use ivi_layout APIs.
+ */
+static void
+mode_divided_into_tiling(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface **ppSurface,
+ int32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const float surface_width = (float)layer->width * 0.25;
+ const float surface_height = (float)layer->height * 0.5;
+ int32_t surface_x = 0;
+ int32_t surface_y = 0;
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ int32_t i = 0;
+ int32_t num = 1;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ if (num <= 8) {
+ if (num < 5) {
+ surface_x = (int32_t)((num - 1) * (surface_width));
+ surface_y = 0;
+ }
+ else {
+ surface_x = (int32_t)((num - 5) * (surface_width));
+ surface_y = (int32_t)surface_height;
+ }
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf, surface_x, surface_y,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 0);
+ assert(!ret);
+ }
+}
+
+static void
+mode_divided_into_sidebyside(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface **ppSurface,
+ int32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ int32_t surface_width = layer->width / 2;
+ int32_t surface_height = layer->height;
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ int32_t i = 0;
+ int32_t num = 1;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ if (num == 1) {
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf, 0, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+ else if (num == 2) {
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf, surface_width, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+
+ ivi_layout_surfaceSetVisibility(ivisurf, 0);
+ assert(!ret);
+ }
+}
+
+static void
+mode_fullscreen_someone(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface **ppSurface,
+ int32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const int32_t surface_width = layer->width;
+ const int32_t surface_height = layer->height;
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ int32_t i = 0;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf, 0, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+ }
+}
+
+static void
+mode_random_replace(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface **ppSurface,
+ int32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const int32_t surface_width = (int32_t)(layer->width * 0.25f);
+ const int32_t surface_height = (int32_t)(layer->height * 0.25f);
+ int32_t surface_x = 0;
+ int32_t surface_y = 0;
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ int32_t i = 0;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ surface_x = rand() % (layer->width - surface_width);
+ surface_y = rand() % (layer->height - surface_height);
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf, surface_x, surface_y,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+ }
+}
+
+static int32_t
+has_applicatipn_surface(struct hmi_controller *hmi_ctrl,
+ struct ivi_layout_surface **ppSurface,
+ int32_t surface_length)
+{
+ struct ivi_layout_surface *ivisurf = NULL;
+ int32_t i = 0;
+
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Supports 4 example to layout of application surfaces;
+ * tiling, side by side, fullscreen, and random.
+ */
+static void
+switch_mode(struct hmi_controller *hmi_ctrl,
+ enum ivi_hmi_controller_layout_mode layout_mode)
+{
+ if (!hmi_ctrl->is_initialized) {
+ return;
+ }
+
+ struct hmi_controller_layer *layer = &hmi_ctrl->application_layer;
+ struct ivi_layout_surface **ppSurface = NULL;
+ int32_t surface_length = 0;
+ int32_t ret = 0;
+
+ hmi_ctrl->layout_mode = layout_mode;
+
+ ret = ivi_layout_getSurfaces(&surface_length, &ppSurface);
+ assert(!ret);
+
+ if (!has_applicatipn_surface(hmi_ctrl, ppSurface, surface_length)) {
+ free(ppSurface);
+ ppSurface = NULL;
+ return;
+ }
+
+ switch (layout_mode) {
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING:
+ mode_divided_into_tiling(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE:
+ mode_divided_into_sidebyside(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN:
+ mode_fullscreen_someone(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM:
+ mode_random_replace(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ }
+
+ ivi_layout_commitChanges();
+
+ free(ppSurface);
+ ppSurface = NULL;
+
+ return;
+}
+
+/**
+ * Internal method for animation
+ */
+static void
+hmi_controller_animation_frame(
+ struct hmi_controller_animation *animation, int32_t timestamp)
+{
+ if (0 == animation->time_start) {
+ animation->time_start = timestamp;
+ }
+
+ animation->frame_func(animation, timestamp);
+ animation->frame_user_func(animation);
+}
+
+static int
+animation_set_do_anima(void* data)
+{
+ struct animation_set *anima_set = data;
+ int32_t fps = 30;
+
+ if (wl_list_empty(&anima_set->animation_list)) {
+ wl_event_source_timer_update(anima_set->event_source, 0);
+ return 1;
+ }
+
+ wl_event_source_timer_update(anima_set->event_source, 1000 / fps);
+
+ struct timespec timestamp = {0};
+ clock_gettime(CLOCK_MONOTONIC, &timestamp);
+ int32_t msec = (1e+3 * timestamp.tv_sec + 1e-6 * timestamp.tv_nsec);
+
+ struct link_animation *link_animation = NULL;
+ struct link_animation *next = NULL;
+
+ wl_list_for_each_safe(link_animation, next, &anima_set->animation_list, link) {
+ hmi_controller_animation_frame(link_animation->animation, msec);
+ }
+
+ ivi_layout_commitChanges();
+ return 1;
+}
+
+static struct animation_set *
+animation_set_create(struct weston_compositor* ec)
+{
+ struct animation_set *anima_set = MEM_ALLOC(sizeof(*anima_set));
+
+ wl_list_init(&anima_set->animation_list);
+
+ struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
+ anima_set->event_source = wl_event_loop_add_timer(loop, animation_set_do_anima, anima_set);
+ wl_event_source_timer_update(anima_set->event_source, 0);
+
+ return anima_set;
+}
+
+static void
+animation_set_add_animation(struct animation_set *anima_set,
+ struct hmi_controller_animation *anima)
+{
+ struct link_animation *link_anima = NULL;
+
+ link_anima = MEM_ALLOC(sizeof(*link_anima));
+ if (NULL == link_anima) {
+ return;
+ }
+
+ link_anima->animation = anima;
+ wl_list_insert(&anima_set->animation_list, &link_anima->link);
+ wl_event_source_timer_update(anima_set->event_source, 1);
+}
+
+static void
+animation_set_remove_animation(struct animation_set *anima_set,
+ struct hmi_controller_animation *anima)
+{
+ struct link_animation *link_animation = NULL;
+ struct link_animation *next = NULL;
+
+ wl_list_for_each_safe(link_animation, next, &anima_set->animation_list, link) {
+ if (link_animation->animation == anima) {
+ wl_list_remove(&link_animation->link);
+ free(link_animation);
+ break;
+ }
+ }
+}
+
+static void
+hmi_controller_animation_spring_frame(
+ struct hmi_controller_animation_fade *animation, int32_t timestamp)
+{
+ if (0 == animation->spring.timestamp) {
+ animation->spring.timestamp = timestamp;
+ }
+
+ weston_spring_update(&animation->spring, timestamp);
+ animation->base.is_done = weston_spring_done(&animation->spring);
+}
+
+static void
+hmi_controller_animation_move_frame(
+ struct hmi_controller_animation_move *animation, int32_t timestamp)
+{
+ double s = animation->pos_start;
+ double t = timestamp - animation->base.time_start;
+ double v0 = animation->v0;
+ double a = animation->a;
+ double time_end = animation->time_end;
+
+ if (time_end <= t) {
+ animation->pos = animation->pos_end;
+ animation->base.is_done = 1;
+ } else {
+ animation->pos = v0 * t + 0.5 * a * t * t + s;
+ }
+}
+
+static void
+hmi_controller_animation_destroy(struct hmi_controller_animation *animation)
+{
+ if (animation->destroy_func) {
+ animation->destroy_func(animation);
+ }
+
+ free(animation);
+}
+
+static void
+hmi_controller_fade_animation_destroy(struct hmi_controller_animation *animation)
+{
+ struct hmi_controller_fade *fade = animation->user_data;
+ animation_set_remove_animation(fade->anima_set, animation);
+ fade->animation = NULL;
+ animation->user_data = NULL;
+}
+
+static struct hmi_controller_animation_fade *
+hmi_controller_animation_fade_create(double start, double end, double k,
+ hmi_controller_animation_frame_user_func frame_user_func, void* user_data,
+ hmi_controller_animation_destroy_func destroy_func)
+{
+ struct hmi_controller_animation_fade* animation = MEM_ALLOC(sizeof(*animation));
+
+ animation->base.frame_user_func = frame_user_func;
+ animation->base.user_data = user_data;
+ animation->base.frame_func =
+ (hmi_controller_animation_frame_func)hmi_controller_animation_spring_frame;
+ animation->base.destroy_func = destroy_func;
+
+ animation->start = start;
+ animation->end = end;
+ weston_spring_init(&animation->spring, k, start, end);
+ animation->spring.friction = 1400;
+ animation->spring.previous = -(end - start) * 0.03;
+
+ return animation;
+}
+
+static struct hmi_controller_animation_move *
+hmi_controller_animation_move_create(
+ double pos_start, double pos_end, double v_start, double v_end,
+ hmi_controller_animation_frame_user_func frame_user_func, void* user_data,
+ hmi_controller_animation_destroy_func destroy_func)
+{
+ struct hmi_controller_animation_move* animation = MEM_ALLOC(sizeof(*animation));
+
+ animation->base.frame_user_func = frame_user_func;
+ animation->base.user_data = user_data;
+ animation->base.frame_func =
+ (hmi_controller_animation_frame_func)hmi_controller_animation_move_frame;
+ animation->base.destroy_func = destroy_func;
+
+ animation->pos_start = pos_start;
+ animation->pos_end = pos_end;
+ animation->v0 = v_start;
+ animation->pos = pos_start;
+
+ double dx = (pos_end - pos_start);
+
+ if (1e-3 < fabs(dx)) {
+ animation->a = 0.5 * (v_end * v_end - v_start * v_start) / dx;
+ if (1e-6 < fabs(animation->a)) {
+ animation->time_end = (v_end - v_start) / animation->a;
+
+ } else {
+ animation->a = 0;
+ animation->time_end = fabs(dx / animation->v0);
+ }
+
+ } else {
+ animation->time_end = 0;
+ }
+
+ return animation;
+}
+
+static double
+hmi_controller_animation_fade_alpha_get(struct hmi_controller_animation_fade* animation)
+{
+ if (animation->spring.current > 0.999) {
+ return 1.0;
+ } else if (animation->spring.current < 0.001 ) {
+ return 0.0;
+ } else {
+ return animation->spring.current;
+ }
+}
+
+static int32_t
+hmi_controller_animation_is_done(struct hmi_controller_animation *animation)
+{
+ return animation->is_done;
+}
+
+static void
+hmi_controller_fade_update(struct hmi_controller_animation_fade *animation, double end)
+{
+ animation->spring.target = end;
+}
+
+static void
+hmi_controller_anima_fade_user_frame(struct hmi_controller_animation_fade *animation)
+{
+ double alpha = hmi_controller_animation_fade_alpha_get(animation);
+ alpha = wl_fixed_from_double(alpha);
+ struct hmi_controller_fade *fade = animation->base.user_data;
+ struct link_layer *linklayer = NULL;
+ int32_t is_done = hmi_controller_animation_is_done(&animation->base);
+ int32_t is_visible = !is_done || fade->isFadeIn;
+
+ wl_list_for_each(linklayer, &fade->layer_list, link) {
+ ivi_layout_layerSetOpacity(linklayer->layout_layer, alpha);
+ ivi_layout_layerSetVisibility(linklayer->layout_layer, is_visible);
+ }
+
+ if (is_done) {
+ hmi_controller_animation_destroy(&animation->base);
+ }
+}
+
+static void
+hmi_controller_anima_move_user_frame(struct hmi_controller_animation_move *animation)
+{
+ struct move_animation_user_data* user_data = animation->base.user_data;
+ struct ivi_layout_layer *layer = user_data->layer;
+ int32_t is_done = hmi_controller_animation_is_done(&animation->base);
+
+ int32_t pos[2] = {0};
+ ivi_layout_layerGetPosition(layer, pos);
+
+ pos[0] = (int32_t)animation->pos;
+ ivi_layout_layerSetPosition(layer, pos);
+
+ if (is_done) {
+ hmi_controller_animation_destroy(&animation->base);
+ }
+}
+
+static void
+hmi_controller_fade_run(int32_t isFadeIn, struct hmi_controller_fade *fade)
+{
+ double tint = isFadeIn ? 1.0 : 0.0;
+ fade->isFadeIn = isFadeIn;
+
+ if (fade->animation) {
+ hmi_controller_fade_update(fade->animation, tint);
+ } else {
+ fade->animation = hmi_controller_animation_fade_create(
+ 1.0 - tint, tint, 300.0,
+ (hmi_controller_animation_frame_user_func)hmi_controller_anima_fade_user_frame,
+ fade, hmi_controller_fade_animation_destroy);
+
+ animation_set_add_animation(fade->anima_set, &fade->animation->base);
+ }
+}
+
+/**
+ * Internal method to create layer with hmi_controller_layer and add to a screen
+ */
+static void
+create_layer(struct ivi_layout_screen *iviscrn,
+ struct hmi_controller_layer *layer)
+{
+ int32_t ret = 0;
+
+ layer->ivilayer = ivi_layout_layerCreateWithDimension(layer->id_layer,
+ layer->width, layer->height);
+ assert(layer->ivilayer != NULL);
+
+ ret = ivi_layout_screenAddLayer(iviscrn, layer->ivilayer);
+ assert(!ret);
+
+ ret = ivi_layout_layerSetDestinationRectangle(layer->ivilayer, layer->x, layer->y,
+ layer->width, layer->height);
+ assert(!ret);
+
+ ret = ivi_layout_layerSetVisibility(layer->ivilayer, 1);
+ assert(!ret);
+}
+
+/**
+ * Internal set notification
+ */
+static void
+set_notification_create_surface(struct ivi_layout_surface *ivisurf,
+ void *userdata)
+{
+ struct hmi_controller* hmi_ctrl = userdata;
+ struct ivi_layout_layer *application_layer = hmi_ctrl->application_layer.ivilayer;
+ int32_t ret = 0;
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ return;
+ }
+
+ ret = ivi_layout_layerAddSurface(application_layer, ivisurf);
+ assert(!ret);
+}
+
+static void
+set_notification_remove_surface(struct ivi_layout_surface *ivisurf,
+ void *userdata)
+{
+ (void)ivisurf;
+ struct hmi_controller* hmi_ctrl = userdata;
+ switch_mode(hmi_ctrl, hmi_ctrl->layout_mode);
+}
+
+static void
+set_notification_configure_surface(struct ivi_layout_surface *ivisurf,
+ void *userdata)
+{
+ (void)ivisurf;
+ struct hmi_controller* hmi_ctrl = userdata;
+ switch_mode(hmi_ctrl, hmi_ctrl->layout_mode);
+}
+
+/**
+ * A hmi_controller used 4 layers to manage surfaces. The IDs of corresponding layer
+ * are defined in weston.ini. Default scene graph of layers are initialized in
+ * hmi_controller_create
+ */
+static struct hmi_server_setting *
+hmi_server_setting_create(void)
+{
+ struct hmi_server_setting* setting = MEM_ALLOC(sizeof(*setting));
+
+ struct weston_config *config = NULL;
+ config = weston_config_parse("weston.ini");
+
+ struct weston_config_section *shellSection = NULL;
+ shellSection = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ weston_config_section_get_uint(
+ shellSection, "base-layer-id", &setting->base_layer_id, 1000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-layer-id", &setting->workspace_background_layer_id, 2000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-layer-id", &setting->workspace_layer_id, 3000);
+
+ weston_config_section_get_uint(
+ shellSection, "application-layer-id", &setting->application_layer_id, 4000);
+
+ setting->panel_height = 70;
+
+ weston_config_destroy(config);
+
+ return setting;
+}
+
+/**
+ * This is a starting method called from module_init.
+ * This sets up scene graph of layers; base, application, workspace background,
+ * and workspace. These layers are created/added to screen in create_layer
+ *
+ * base: to group surfaces of panel and background
+ * application: to group surfaces of ivi_applications
+ * workspace background: to group a surface of background in workspace
+ * workspace: to group surfaces for launching ivi_applications
+ *
+ * Layers of workspace background and workspace is set to invisible at first.
+ * The properties of it is updated with animation when ivi_hmi_controller_home is
+ * requested.
+ */
+static struct hmi_controller *
+hmi_controller_create(struct weston_compositor *ec)
+{
+ struct ivi_layout_screen **ppScreen = NULL;
+ struct ivi_layout_screen *iviscrn = NULL;
+ int32_t screen_length = 0;
+ int32_t screen_width = 0;
+ int32_t screen_height = 0;
+ int32_t ret = 0;
+ struct link_layer *tmp_link_layer = NULL;
+
+ struct hmi_controller *hmi_ctrl = MEM_ALLOC(sizeof(*hmi_ctrl));
+ wl_array_init(&hmi_ctrl->ui_widgets);
+ hmi_ctrl->layout_mode = IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING;
+ hmi_ctrl->hmi_setting = hmi_server_setting_create();
+
+ ivi_layout_getScreens(&screen_length, &ppScreen);
+
+ iviscrn = ppScreen[0];
+
+ ivi_layout_getScreenResolution(iviscrn, &screen_width, &screen_height);
+ assert(!ret);
+
+ /* init base layer*/
+ hmi_ctrl->base_layer.x = 0;
+ hmi_ctrl->base_layer.y = 0;
+ hmi_ctrl->base_layer.width = screen_width;
+ hmi_ctrl->base_layer.height = screen_height;
+ hmi_ctrl->base_layer.id_layer = hmi_ctrl->hmi_setting->base_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->base_layer);
+
+ int32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+
+
+ /* init application layer */
+ hmi_ctrl->application_layer.x = 0;
+ hmi_ctrl->application_layer.y = 0;
+ hmi_ctrl->application_layer.width = screen_width;
+ hmi_ctrl->application_layer.height = screen_height - panel_height;
+ hmi_ctrl->application_layer.id_layer = hmi_ctrl->hmi_setting->application_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->application_layer);
+
+ /* init workspace background layer */
+ hmi_ctrl->workspace_background_layer.x = 0;
+ hmi_ctrl->workspace_background_layer.y = 0;
+ hmi_ctrl->workspace_background_layer.width = screen_width;
+ hmi_ctrl->workspace_background_layer.height = screen_height - panel_height;
+
+ hmi_ctrl->workspace_background_layer.id_layer =
+ hmi_ctrl->hmi_setting->workspace_background_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->workspace_background_layer);
+ ivi_layout_layerSetOpacity(hmi_ctrl->workspace_background_layer.ivilayer, 0);
+ ivi_layout_layerSetVisibility(hmi_ctrl->workspace_background_layer.ivilayer, 0);
+
+ /* init workspace layer */
+ hmi_ctrl->workspace_layer.x = hmi_ctrl->workspace_background_layer.x;
+ hmi_ctrl->workspace_layer.y = hmi_ctrl->workspace_background_layer.y;
+ hmi_ctrl->workspace_layer.width = hmi_ctrl->workspace_background_layer.width;
+ hmi_ctrl->workspace_layer.height = hmi_ctrl->workspace_background_layer.height;
+ hmi_ctrl->workspace_layer.id_layer = hmi_ctrl->hmi_setting->workspace_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->workspace_layer);
+ ivi_layout_layerSetOpacity(hmi_ctrl->workspace_layer.ivilayer, 0);
+ ivi_layout_layerSetVisibility(hmi_ctrl->workspace_layer.ivilayer, 0);
+
+ /* set up animation to workspace background and workspace */
+ hmi_ctrl->anima_set = animation_set_create(ec);
+
+ wl_list_init(&hmi_ctrl->workspace_fade.layer_list);
+ tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer));
+ tmp_link_layer->layout_layer = hmi_ctrl->workspace_layer.ivilayer;
+ wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, &tmp_link_layer->link);
+ tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer));
+ tmp_link_layer->layout_layer = hmi_ctrl->workspace_background_layer.ivilayer;
+ wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, &tmp_link_layer->link);
+ hmi_ctrl->workspace_fade.anima_set = hmi_ctrl->anima_set;
+
+ ivi_layout_addNotificationCreateSurface(set_notification_create_surface, hmi_ctrl);
+ ivi_layout_addNotificationRemoveSurface(set_notification_remove_surface, hmi_ctrl);
+ ivi_layout_addNotificationConfigureSurface(set_notification_configure_surface, hmi_ctrl);
+
+ free(ppScreen);
+ ppScreen = NULL;
+
+ return hmi_ctrl;
+}
+
+/**
+ * Implementations of ivi-hmi-controller.xml
+ */
+
+/**
+ * A surface drawing background is identified by id_surface.
+ * Properties of the surface is set by using ivi_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_background(struct wl_resource *resource,
+ uint32_t id_surface)
+
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const int32_t dstx = hmi_ctrl->application_layer.x;
+ const int32_t dsty = hmi_ctrl->application_layer.y;
+ const int32_t width = hmi_ctrl->application_layer.width;
+ const int32_t height = hmi_ctrl->application_layer.height;
+ int32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = ivi_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = ivi_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf,
+ dstx, dsty, width, height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ ivi_layout_commitChanges();
+}
+
+/**
+ * A surface drawing panel is identified by id_surface.
+ * Properties of the surface is set by using ivi_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_panel(struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const int32_t width = hmi_ctrl->base_layer.width;
+ int32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = ivi_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = ivi_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+ int32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+ const int32_t dstx = 0;
+ const int32_t dsty = hmi_ctrl->base_layer.height - panel_height;
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(
+ ivisurf, dstx, dsty, width, panel_height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ ivi_layout_commitChanges();
+}
+
+/**
+ * A surface drawing buttons in panel is identified by id_surface. It can set
+ * several buttons. Properties of the surface is set by using ivi_layout
+ * APIs according to the scene graph of UI defined in hmi_controller_create.
+ * Additionally, the position of it is shifted to right when new one is requested.
+ *
+ * UI layer is used to add these surfaces.
+ */
+static void
+ivi_hmi_controller_set_button(struct wl_resource *resource,
+ uint32_t id_surface, int32_t number)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const int32_t width = 48;
+ const int32_t height = 48;
+ int32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = ivi_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = ivi_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ int32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+
+ const int32_t dstx = (60 * number) + 15;
+ const int32_t dsty = (hmi_ctrl->base_layer.height - panel_height) + 5;
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(
+ ivisurf,dstx, dsty, width, height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ ivi_layout_commitChanges();
+}
+
+/**
+ * A surface drawing home button in panel is identified by id_surface.
+ * Properties of the surface is set by using ivi_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add these surfaces.
+ */
+static void
+ivi_hmi_controller_set_home_button(struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ int32_t ret = 0;
+ int32_t size = 48;
+ int32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+ const int32_t dstx = (hmi_ctrl->base_layer.width - size) / 2;
+ const int32_t dsty = (hmi_ctrl->base_layer.height - panel_height) + 5;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = ivi_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = ivi_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(
+ ivisurf, dstx, dsty, size, size);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ ivi_layout_commitChanges();
+ hmi_ctrl->is_initialized = 1;
+}
+
+/**
+ * A surface drawing background of workspace is identified by id_surface.
+ * Properties of the surface is set by using ivi_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * A layer of workspace_background is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_workspacebackground(struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *ivisurf = NULL;
+ struct ivi_layout_layer *ivilayer = NULL;
+ ivilayer = hmi_ctrl->workspace_background_layer.ivilayer;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ const int32_t width = hmi_ctrl->workspace_background_layer.width;
+ const int32_t height = hmi_ctrl->workspace_background_layer.height;
+ int32_t ret = 0;
+
+ ivisurf = ivi_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = ivi_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(ivisurf,
+ 0, 0, width, height);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ ivi_layout_commitChanges();
+}
+
+/**
+ * A list of surfaces drawing launchers in workspace is identified by id_surfaces.
+ * Properties of the surface is set by using ivi_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * The workspace can have several pages to group surfaces of launcher. Each call
+ * of this interface increments a number of page to add a group of surfaces
+ */
+static void
+ivi_hmi_controller_add_launchers(struct wl_resource *resource,
+ int32_t icon_size)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ int32_t minspace_x = 10;
+ int32_t minspace_y = minspace_x;
+
+ int32_t width = hmi_ctrl->workspace_layer.width;
+ int32_t height = hmi_ctrl->workspace_layer.height;
+
+ int32_t x_count = (width - minspace_x) / (minspace_x + icon_size);
+ int32_t space_x = (int32_t)((width - x_count * icon_size) / (1.0 + x_count));
+ float fcell_size_x = icon_size + space_x;
+
+ int32_t y_count = (height - minspace_y) / (minspace_y + icon_size);
+ int32_t space_y = (int32_t)((height - y_count * icon_size) / (1.0 + y_count));
+ float fcell_size_y = icon_size + space_y;
+
+ if (0 == x_count) {
+ x_count = 1;
+ }
+
+ if (0 == y_count) {
+ y_count = 1;
+ }
+
+ struct weston_config *config = weston_config_parse("weston.ini");
+ if (!config) {
+ return;
+ }
+
+ struct weston_config_section *section = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+ if (!section) {
+ return;
+ }
+
+ const char *name = NULL;
+ int launcher_count = 0;
+ struct wl_array launchers;
+ wl_array_init(&launchers);
+
+ while (weston_config_next_section(config, &section, &name)) {
+ uint32_t surfaceid = 0;
+ uint32_t workspaceid = 0;
+ if (0 != strcmp(name, "ivi-launcher")) {
+ continue;
+ }
+
+ if (0 != weston_config_section_get_uint(section, "icon-id", &surfaceid, 0)) {
+ continue;
+ }
+
+ if (0 != weston_config_section_get_uint(section, "workspace-id", &workspaceid, 0)) {
+ continue;
+ }
+
+ struct launcher_info *info = wl_array_add(&launchers, sizeof(*info));
+
+ if (info) {
+ info->surface_id = surfaceid;
+ info->workspace_id = workspaceid;
+ info->index = launcher_count;
+ ++launcher_count;
+ }
+ }
+
+ qsort(launchers.data, launcher_count, sizeof(struct launcher_info), compare_launcher_info);
+
+ int32_t nx = 0;
+ int32_t ny = 0;
+ int32_t prev = -1;
+ struct launcher_info *data = NULL;
+ wl_array_for_each(data, &launchers)
+ {
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = data->surface_id;
+
+ if (0 > prev || (uint32_t)prev != data->workspace_id) {
+ nx = 0;
+ ny = 0;
+ prev = data->workspace_id;
+
+ if (0 <= prev) {
+ hmi_ctrl->workspace_count++;
+ }
+ }
+
+ if (y_count == ny) {
+ ny = 0;
+ hmi_ctrl->workspace_count++;
+ }
+
+ int32_t x = nx * fcell_size_x + (hmi_ctrl->workspace_count - 1) * width + space_x;
+ int32_t y = ny * fcell_size_y + space_y;
+
+ struct ivi_layout_surface* layout_surface = NULL;
+ layout_surface = ivi_layout_getSurfaceFromId(data->surface_id);
+ assert(layout_surface);
+
+ int32_t ret = 0;
+ ret = ivi_layout_layerAddSurface(layer, layout_surface);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetDestinationRectangle(
+ layout_surface, x, y, icon_size, icon_size);
+ assert(!ret);
+
+ ret = ivi_layout_surfaceSetVisibility(layout_surface, 1);
+ assert(!ret);
+
+ nx++;
+
+ if (x_count == nx) {
+ ny++;
+ nx = 0;
+ }
+ }
+
+ wl_array_release(&launchers);
+ weston_config_destroy(config);
+ ivi_layout_commitChanges();
+}
+
+static void
+ivi_hmi_controller_UI_ready(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct setting {
+ uint32_t background_id;
+ uint32_t panel_id;
+ uint32_t tiling_id;
+ uint32_t sidebyside_id;
+ uint32_t fullscreen_id;
+ uint32_t random_id;
+ uint32_t home_id;
+ uint32_t workspace_background_id;
+ };
+
+ struct config_command {
+ char *key;
+ void *dest;
+ };
+
+ struct weston_config *config = NULL;
+ struct weston_config_section *section = NULL;
+ struct setting dest;
+ int result = 0;
+ int i = 0;
+
+ const struct config_command uint_commands[] = {
+ { "background-id", &dest.background_id },
+ { "panel-id", &dest.panel_id },
+ { "tiling-id", &dest.tiling_id },
+ { "sidebyside-id", &dest.sidebyside_id },
+ { "fullscreen-id", &dest.fullscreen_id },
+ { "random-id", &dest.random_id },
+ { "home-id", &dest.home_id },
+ { "workspace-background-id", &dest.workspace_background_id },
+ { NULL, NULL }
+ };
+
+ config = weston_config_parse("weston.ini");
+ section = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ for (i = 0; -1 != result; ++i)
+ {
+ const struct config_command *command = &uint_commands[i];
+
+ if (!command->key)
+ {
+ break;
+ }
+
+ if (weston_config_section_get_uint(
+ section, command->key, (uint32_t *)command->dest, 0) != 0)
+ {
+ result = -1;
+ }
+ }
+
+ if (-1 != result)
+ {
+ ivi_hmi_controller_set_background(resource, dest.background_id);
+ ivi_hmi_controller_set_panel(resource, dest.panel_id);
+ ivi_hmi_controller_set_button(resource, dest.tiling_id, 0);
+ ivi_hmi_controller_set_button(resource, dest.sidebyside_id, 1);
+ ivi_hmi_controller_set_button(resource, dest.fullscreen_id, 2);
+ ivi_hmi_controller_set_button(resource, dest.random_id, 3);
+ ivi_hmi_controller_set_home_button(resource, dest.home_id);
+ ivi_hmi_controller_set_workspacebackground(resource, dest.workspace_background_id);
+ }
+
+ weston_config_destroy(config);
+
+ ivi_hmi_controller_add_launchers(resource, 256);
+}
+
+/**
+ * Implementation of request and event of ivi_hmi_controller_workspace_control
+ * and controlling workspace.
+ *
+ * When motion of input is detected in a surface of workspace background,
+ * ivi_hmi_controller_workspace_control shall be invoked and to start controlling of
+ * workspace. The workspace has several pages to show several groups of applications.
+ * The workspace is slid by using ivi-layout to select a a page in layer_set_pos
+ * according to motion. When motion finished, e.g. touch up detected, control is
+ * terminated and event:ivi_hmi_controller_workspace_control is notified.
+ */
+struct pointer_grab {
+ struct weston_pointer_grab grab;
+ struct ivi_layout_layer *layer;
+ struct wl_resource *resource;
+};
+
+struct touch_grab {
+ struct weston_touch_grab grab;
+ struct ivi_layout_layer *layer;
+ struct wl_resource *resource;
+};
+
+struct move_grab {
+ wl_fixed_t dst[2];
+ wl_fixed_t rgn[2][2];
+ double v[2];
+ struct timespec start_time;
+ struct timespec pre_time;
+ wl_fixed_t start_pos[2];
+ wl_fixed_t pos[2];
+ int32_t is_moved;
+};
+
+struct pointer_move_grab {
+ struct pointer_grab base;
+ struct move_grab move;
+};
+
+struct touch_move_grab {
+ struct touch_grab base;
+ struct move_grab move;
+ int32_t is_active;
+};
+
+static void
+pointer_grab_start(struct pointer_grab *grab,
+ struct ivi_layout_layer *layer,
+ const struct weston_pointer_grab_interface *interface,
+ struct weston_pointer *pointer)
+{
+ grab->grab.interface = interface;
+ grab->layer = layer;
+ weston_pointer_start_grab(pointer, &grab->grab);
+}
+
+static void
+touch_grab_start(struct touch_grab *grab,
+ struct ivi_layout_layer *layer,
+ const struct weston_touch_grab_interface *interface,
+ struct weston_touch* touch)
+{
+ grab->grab.interface = interface;
+ grab->layer = layer;
+ weston_touch_start_grab(touch, &grab->grab);
+}
+
+static int32_t
+range_val(int32_t val, int32_t min, int32_t max)
+{
+ if (val < min) {
+ return min;
+ }
+
+ if (max < val) {
+ return max;
+ }
+
+ return val;
+}
+
+static void
+hmi_controller_move_animation_destroy(struct hmi_controller_animation *animation)
+{
+ struct move_animation_user_data *user_data = animation->user_data;
+ if (animation == &user_data->hmi_ctrl->workspace_swipe_animation->base) {
+ user_data->hmi_ctrl->workspace_swipe_animation = NULL;
+ }
+
+ animation_set_remove_animation(user_data->anima_set, animation);
+ free(animation->user_data);
+ animation->user_data = NULL;
+}
+
+static void
+move_workspace_grab_end(struct move_grab *move, struct wl_resource* resource,
+ wl_fixed_t grab_x, struct ivi_layout_layer *layer)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ int32_t width = hmi_ctrl->workspace_background_layer.width;
+
+ struct timespec time = {0};
+ clock_gettime(CLOCK_MONOTONIC, &time);
+
+ double grab_time = 1e+3 * (time.tv_sec - move->start_time.tv_sec) +
+ 1e-6 * (time.tv_nsec - move->start_time.tv_nsec);
+
+ double from_motion_time = 1e+3 * (time.tv_sec - move->pre_time.tv_sec) +
+ 1e-6 * (time.tv_nsec - move->pre_time.tv_nsec);
+
+ double pointer_v = move->v[0];
+
+ if (200 < from_motion_time) {
+ pointer_v = 0.0;
+ }
+
+ int32_t is_flick = grab_time < 400 &&
+ 0.4 < fabs(pointer_v);
+
+ int32_t pos[2] = {0};
+ ivi_layout_layerGetPosition(layer, pos);
+
+ int page_no = 0;
+
+ if (is_flick) {
+ int orgx = wl_fixed_to_int(move->dst[0] + grab_x);
+ page_no = (-orgx + width / 2) / width;
+
+ if (pointer_v < 0.0) {
+ page_no++;
+ }else {
+ page_no--;
+ }
+ }else {
+ page_no = (-pos[0] + width / 2) / width;
+ }
+
+ page_no = range_val(page_no, 0, hmi_ctrl->workspace_count - 1);
+ double end_pos = -page_no * width;
+
+ double dst = fabs(end_pos - pos[0]);
+ double max_time = 0.5 * 1e+3;
+ double v = dst / max_time;
+
+ double vmin = 1000 * 1e-3;
+ if (v < vmin ) {
+ v = vmin;
+ }
+
+ double v0 = 0.0;
+ if (pos[0] < end_pos) {
+ v0 = v;
+ } else {
+ v0 = -v;
+ }
+
+ struct move_animation_user_data *animation_user_data = NULL;
+ animation_user_data = MEM_ALLOC(sizeof(*animation_user_data));
+ animation_user_data->layer = layer;
+ animation_user_data->anima_set = hmi_ctrl->anima_set;
+ animation_user_data->hmi_ctrl = hmi_ctrl;
+
+ struct hmi_controller_animation_move* animation = NULL;
+ animation = hmi_controller_animation_move_create(
+ pos[0], end_pos, v0, v0,
+ (hmi_controller_animation_frame_user_func)hmi_controller_anima_move_user_frame,
+ animation_user_data, hmi_controller_move_animation_destroy);
+
+ hmi_ctrl->workspace_swipe_animation = animation;
+ animation_set_add_animation(hmi_ctrl->anima_set, &animation->base);
+
+ ivi_hmi_controller_send_workspace_end_control(resource, move->is_moved);
+}
+
+static void
+pointer_move_workspace_grab_end(struct pointer_grab *grab)
+{
+ struct pointer_move_grab *pnt_move_grab = (struct pointer_move_grab *) grab;
+ struct ivi_layout_layer *layer = pnt_move_grab->base.layer;
+
+ move_workspace_grab_end(&pnt_move_grab->move, grab->resource,
+ grab->grab.pointer->grab_x, layer);
+
+ weston_pointer_end_grab(grab->grab.pointer);
+}
+
+static void
+touch_move_workspace_grab_end(struct touch_grab *grab)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *) grab;
+ struct ivi_layout_layer *layer = tch_move_grab->base.layer;
+
+ move_workspace_grab_end(&tch_move_grab->move, grab->resource,
+ grab->grab.touch->grab_x, layer);
+
+ weston_touch_end_grab(grab->grab.touch);
+}
+
+static void
+pointer_noop_grab_focus(struct weston_pointer_grab *grab)
+{
+}
+
+static void
+move_grab_update(struct move_grab *move, wl_fixed_t pointer[2])
+{
+ struct timespec timestamp = {0};
+ clock_gettime(CLOCK_MONOTONIC, &timestamp);
+
+ double dt = (1e+3 * (timestamp.tv_sec - move->pre_time.tv_sec) +
+ 1e-6 * (timestamp.tv_nsec - move->pre_time.tv_nsec));
+
+ if (dt < 1e-6) {
+ dt = 1e-6;
+ }
+
+ move->pre_time = timestamp;
+
+ int32_t ii = 0;
+ for (ii = 0; ii < 2; ii++) {
+ wl_fixed_t prepos = move->pos[ii];
+ move->pos[ii] = pointer[ii] + move->dst[ii];
+
+ if (move->pos[ii] < move->rgn[0][ii]) {
+ move->pos[ii] = move->rgn[0][ii];
+ move->dst[ii] = move->pos[ii] - pointer[ii];
+ } else if (move->rgn[1][ii] < move->pos[ii]) {
+ move->pos[ii] = move->rgn[1][ii];
+ move->dst[ii] = move->pos[ii] - pointer[ii];
+ }
+
+ move->v[ii] = wl_fixed_to_double(move->pos[ii] - prepos) / dt;
+
+ if (!move->is_moved &&
+ 0 < wl_fixed_to_int(move->pos[ii] - move->start_pos[ii])) {
+ move->is_moved = 1;
+ }
+ }
+}
+
+static void
+layer_set_pos(struct ivi_layout_layer *layer, wl_fixed_t pos[2])
+{
+ int32_t layout_pos[2] = {0};
+ layout_pos[0] = wl_fixed_to_int(pos[0]);
+ layout_pos[1] = wl_fixed_to_int(pos[1]);
+ ivi_layout_layerSetPosition(layer, layout_pos);
+ ivi_layout_commitChanges();
+}
+
+static void
+pointer_move_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ struct pointer_move_grab *pnt_move_grab = (struct pointer_move_grab *) grab;
+ wl_fixed_t pointer_pos[2] = {x, y};
+ move_grab_update(&pnt_move_grab->move, pointer_pos);
+ layer_set_pos(pnt_move_grab->base.layer, pnt_move_grab->move.pos);
+ weston_pointer_move(pnt_move_grab->base.grab.pointer, x, y);
+}
+
+static void
+touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
+ int touch_id, wl_fixed_t x, wl_fixed_t y)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *) grab;
+
+ if (!tch_move_grab->is_active) {
+ return;
+ }
+
+ wl_fixed_t pointer_pos[2] = {grab->touch->grab_x, grab->touch->grab_y};
+ move_grab_update(&tch_move_grab->move, pointer_pos);
+ layer_set_pos(tch_move_grab->base.layer, tch_move_grab->move.pos);
+}
+
+static void
+pointer_move_workspace_grab_button(struct weston_pointer_grab *grab,
+ uint32_t time, uint32_t button,
+ uint32_t state_w)
+{
+ if (BTN_LEFT == button &&
+ WL_POINTER_BUTTON_STATE_RELEASED == state_w) {
+ struct pointer_grab *pg = (struct pointer_grab *)grab;
+ pointer_move_workspace_grab_end(pg);
+ free(grab);
+ }
+}
+
+static void
+touch_nope_grab_down(struct weston_touch_grab *grab, uint32_t time,
+ int touch_id, wl_fixed_t sx, wl_fixed_t sy)
+{
+}
+
+static void
+touch_move_workspace_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *)grab;
+
+ if (0 == touch_id) {
+ tch_move_grab->is_active = 0;
+ }
+
+ if (0 == grab->touch->num_tp) {
+ touch_move_workspace_grab_end(&tch_move_grab->base);
+ free(grab);
+ }
+}
+
+static void
+pointer_move_workspace_grab_cancel(struct weston_pointer_grab *grab)
+{
+ struct pointer_grab *pg = (struct pointer_grab *)grab;
+ pointer_move_workspace_grab_end(pg);
+ free(grab);
+}
+
+static void
+touch_move_workspace_grab_cancel(struct weston_touch_grab *grab)
+{
+ struct touch_grab *tg = (struct touch_grab *)grab;
+ touch_move_workspace_grab_end(tg);
+ free(grab);
+}
+
+static const struct weston_pointer_grab_interface pointer_move_grab_workspace_interface = {
+ pointer_noop_grab_focus,
+ pointer_move_grab_motion,
+ pointer_move_workspace_grab_button,
+ pointer_move_workspace_grab_cancel
+};
+
+static const struct weston_touch_grab_interface touch_move_grab_workspace_interface = {
+ touch_nope_grab_down,
+ touch_move_workspace_grab_up,
+ touch_move_grab_motion,
+ touch_move_workspace_grab_cancel
+};
+
+enum HMI_GRAB_DEVICE
+{
+ HMI_GRAB_DEVICE_NONE,
+ HMI_GRAB_DEVICE_POINTER,
+ HMI_GRAB_DEVICE_TOUCH
+};
+
+static enum HMI_GRAB_DEVICE
+get_hmi_grab_device(struct weston_seat *seat, int32_t serial)
+{
+ if (seat->pointer &&
+ seat->pointer->focus &&
+ seat->pointer->button_count &&
+ (int32_t)seat->pointer->grab_serial == serial) {
+ return HMI_GRAB_DEVICE_POINTER;
+ }
+
+ if (seat->touch &&
+ seat->touch->focus &&
+ seat->touch->grab_serial) {
+ return HMI_GRAB_DEVICE_TOUCH;
+ }
+
+ return HMI_GRAB_DEVICE_NONE;
+}
+
+static void
+move_grab_init(struct move_grab* move, wl_fixed_t start_pos[2],
+ wl_fixed_t grab_pos[2], wl_fixed_t rgn[2][2],
+ struct wl_resource* resource)
+{
+ clock_gettime(CLOCK_MONOTONIC, &move->start_time);
+ move->pre_time = move->start_time;
+ move->pos[0] = start_pos[0];
+ move->pos[1] = start_pos[1];
+ move->start_pos[0] = start_pos[0];
+ move->start_pos[1] = start_pos[1];
+ move->dst[0] = start_pos[0] - grab_pos[0];
+ move->dst[1] = start_pos[1] - grab_pos[1];
+ memcpy(move->rgn, rgn, sizeof(move->rgn));
+}
+
+static void
+move_grab_init_workspace(struct move_grab* move,
+ wl_fixed_t grab_x, wl_fixed_t grab_y,
+ struct wl_resource *resource)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct ivi_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ int32_t workspace_count = hmi_ctrl->workspace_count;
+ int32_t workspace_width = hmi_ctrl->workspace_background_layer.width;
+ int32_t layer_pos[2] = {0};
+ ivi_layout_layerGetPosition(layer, layer_pos);
+
+ wl_fixed_t start_pos[2] = {0};
+ start_pos[0] = wl_fixed_from_int(layer_pos[0]);
+ start_pos[1] = wl_fixed_from_int(layer_pos[1]);
+
+ wl_fixed_t rgn[2][2] = {{0}};
+ rgn[0][0] = wl_fixed_from_int(-workspace_width * (workspace_count - 1));
+
+ rgn[0][1] = wl_fixed_from_int(0);
+ rgn[1][0] = wl_fixed_from_int(0);
+ rgn[1][1] = wl_fixed_from_int(0);
+
+ wl_fixed_t grab_pos[2] = {grab_x, grab_y};
+
+ move_grab_init(move, start_pos, grab_pos, rgn, resource);
+}
+
+static struct pointer_move_grab *
+create_workspace_pointer_move(struct weston_pointer *pointer, struct wl_resource* resource)
+{
+ struct pointer_move_grab *pnt_move_grab = MEM_ALLOC(sizeof(*pnt_move_grab));
+ pnt_move_grab->base.resource = resource;
+ move_grab_init_workspace(&pnt_move_grab->move, pointer->grab_x, pointer->grab_y, resource);
+ return pnt_move_grab;
+}
+
+static struct touch_move_grab *
+create_workspace_touch_move(struct weston_touch *touch, struct wl_resource* resource)
+{
+ struct touch_move_grab *tch_move_grab = MEM_ALLOC(sizeof(*tch_move_grab));
+ tch_move_grab->base.resource = resource;
+ tch_move_grab->is_active = 1;
+ move_grab_init_workspace(&tch_move_grab->move, touch->grab_x,touch->grab_y, resource);
+ return tch_move_grab;
+}
+
+static void
+ivi_hmi_controller_workspace_control(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *seat_resource,
+ uint32_t serial)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+
+ if (hmi_ctrl->workspace_count < 2) {
+ return;
+ }
+
+ struct weston_seat* seat = wl_resource_get_user_data(seat_resource);
+ enum HMI_GRAB_DEVICE device = get_hmi_grab_device(seat, serial);
+
+ if (HMI_GRAB_DEVICE_POINTER != device &&
+ HMI_GRAB_DEVICE_TOUCH != device) {
+ return;
+ }
+
+ if (hmi_ctrl->workspace_swipe_animation) {
+ hmi_controller_animation_destroy(&hmi_ctrl->workspace_swipe_animation->base);
+ }
+
+ struct ivi_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ struct pointer_move_grab *pnt_move_grab = NULL;
+ struct touch_move_grab *tch_move_grab = NULL;
+
+ switch (device) {
+ case HMI_GRAB_DEVICE_POINTER:
+ pnt_move_grab = create_workspace_pointer_move(seat->pointer, resource);
+
+ pointer_grab_start(
+ &pnt_move_grab->base, layer, &pointer_move_grab_workspace_interface,
+ seat->pointer);
+ break;
+
+ case HMI_GRAB_DEVICE_TOUCH:
+ tch_move_grab = create_workspace_touch_move(seat->touch, resource);
+
+ touch_grab_start(
+ &tch_move_grab->base, layer, &touch_move_grab_workspace_interface,
+ seat->touch);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * Implementation of switch_mode
+ */
+static void
+ivi_hmi_controller_switch_mode(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t layout_mode)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ switch_mode(hmi_ctrl, layout_mode);
+}
+
+/**
+ * Implementation of on/off displaying workspace and workspace background layers.
+ */
+static void
+ivi_hmi_controller_home(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t home)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+
+ if ((IVI_HMI_CONTROLLER_HOME_ON == home && !hmi_ctrl->workspace_fade.isFadeIn) ||
+ (IVI_HMI_CONTROLLER_HOME_OFF == home && hmi_ctrl->workspace_fade.isFadeIn)) {
+
+ int32_t isFadeIn = !hmi_ctrl->workspace_fade.isFadeIn;
+ hmi_controller_fade_run(isFadeIn, &hmi_ctrl->workspace_fade);
+ }
+}
+
+/**
+ * binding ivi-hmi-controller implementation
+ */
+static const struct ivi_hmi_controller_interface ivi_hmi_controller_implementation = {
+ ivi_hmi_controller_UI_ready,
+ ivi_hmi_controller_workspace_control,
+ ivi_hmi_controller_switch_mode,
+ ivi_hmi_controller_home
+};
+
+static void
+unbind_hmi_controller(struct wl_resource *resource)
+{
+}
+
+static void
+bind_hmi_controller(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource = NULL;
+
+ resource = wl_resource_create(
+ client, &ivi_hmi_controller_interface, 1, id);
+
+ wl_resource_set_implementation(
+ resource, &ivi_hmi_controller_implementation,
+ data, unbind_hmi_controller);
+}
+
+static void
+launch_hmi_client(void *data)
+{
+ /*Nothing to do here*/
+}
+
+/*****************************************************************************
+ * exported functions
+ ****************************************************************************/
+
+WL_EXPORT int
+module_init(struct weston_compositor *ec,
+ int *argc, char *argv[])
+{
+ struct hmi_controller *hmi_ctrl = hmi_controller_create(ec);
+
+ if (wl_global_create(ec->wl_display,
+ &ivi_hmi_controller_interface, 1,
+ hmi_ctrl, bind_hmi_controller) == NULL) {
+ return -1;
+ }
+
+ struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
+ wl_event_loop_add_idle(loop, launch_hmi_client, ec);
+
+ return 0;
+}
--
1.8.3.1
Nobuhiko Tanibata
2014-06-25 12:08:08 UTC
Permalink
This is launched from hmi-controller by launch_hmi_client_process and invoke a
client process.

The basic flow is as followed,
1/ process invoked
2/ read configuration from weston.ini.
3/ draw png file to surface according to configuration of weston.ini
4/ all parts of UI are ready. request "UI_ready" to draw UI.
5/ Enter event loop
6/ If a surface receives touch/pointer event, followings are invoked according
to type of event and surface
6-1/ If a surface to launch ivi_application receive touch up, it execs
ivi-application configured in weston.ini.
6-2/ If a surface to switch layout mode receive touch up, it sends a request,
ivi_hmi_controller_switch_mode, to hmi-controller.
6-3/ If a surface to show workspace having launchers, it sends a request,
ivi_hmi_controller_home, to hmi-controller.
6-4/ If touch down events happens in workspace,
ivi_hmi_controller_workspace_control is sent to slide workspace.
When control finished, event: ivi_hmi_controller_workspace_end_control
is received.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>

data: add reference image files for weston-ivi-shell-user-interface

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- apply review comments from mailing list

Changes for v6:
- apply review comments from mailing list
- disable compling ivi-shell-user-interface with --disable-ivi-shell
- add protocol/ivi-application-protocol.c

Makefile.am | 15 +
clients/ivi-shell-user-interface.c | 1332 ++++++++++++++++++++++++++++++++++++
ivi-shell/hmi-controller.c | 41 +-
3 files changed, 1385 insertions(+), 3 deletions(-)
create mode 100644 clients/ivi-shell-user-interface.c

diff --git a/Makefile.am b/Makefile.am
index 1f75cc3..64bdf6d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -361,6 +361,11 @@ libexec_PROGRAMS += \
weston-keyboard \
weston-simple-im

+if ENABLE_IVI_SHELL
+libexec_PROGRAMS += \
+ weston-ivi-shell-user-interface
+endif
+
demo_clients = \
weston-flower \
weston-image \
@@ -570,6 +575,16 @@ nodist_weston_desktop_shell_SOURCES = \
weston_desktop_shell_LDADD = libtoytoolkit.la
weston_desktop_shell_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)

+if ENABLE_IVI_SHELL
+weston_ivi_shell_user_interface_SOURCES = clients/ivi-shell-user-interface.c
+nodist_weston_ivi_shell_user_interface_SOURCES = \
+ protocol/ivi-hmi-controller-client-protocol.h \
+ protocol/ivi-hmi-controller-protocol.c \
+ protocol/ivi-application-protocol.c
+weston_ivi_shell_user_interface_LDADD = libtoytoolkit.la
+weston_ivi_shell_user_interface_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+endif
+
if BUILD_FULL_GL_CLIENTS
demo_clients += weston-gears
weston_gears_SOURCES = clients/gears.c
diff --git a/clients/ivi-shell-user-interface.c b/clients/ivi-shell-user-interface.c
new file mode 100644
index 0000000..70b854b
--- /dev/null
+++ b/clients/ivi-shell-user-interface.c
@@ -0,0 +1,1332 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <wayland-cursor.h>
+#include "../shared/cairo-util.h"
+#include "../shared/config-parser.h"
+#include "ivi-application-client-protocol.h"
+#include "ivi-hmi-controller-client-protocol.h"
+
+/**
+ * A reference implementation how to use ivi-hmi-controller interface to interact
+ * with hmi-controller. This is launched from hmi-controller by using
+ * hmi_client_start and create a pthread.
+ *
+ * The basic flow is as followed,
+ * 1/ create pthread
+ * 2/ read configuration from weston.ini.
+ * 3/ draw png file to surface according to configuration of weston.ini
+ * 4/ set up UI by using ivi-hmi-controller protocol
+ * 5/ Enter event loop
+ * 6/ If a surface receives touch/pointer event, followings are invoked according
+ * to type of event and surface
+ * 6-1/ If a surface to launch ivi_application receive touch up, it execs
+ * ivi-application configured in weston.ini.
+ * 6-2/ If a surface to switch layout mode receive touch up, it sends a request,
+ * ivi_hmi_controller_switch_mode, to hmi-controller.
+ * 6-3/ If a surface to show workspace having launchers, it sends a request,
+ * ivi_hmi_controller_home, to hmi-controller.
+ * 6-4/ If touch down events happens in workspace,
+ * ivi_hmi_controller_workspace_control is sent to slide workspace.
+ * When control finished, event: ivi_hmi_controller_workspace_end_control
+ * is received.
+ */
+
+/*****************************************************************************
+ * structure, globals
+ ****************************************************************************/
+enum cursor_type {
+ CURSOR_BOTTOM_LEFT,
+ CURSOR_BOTTOM_RIGHT,
+ CURSOR_BOTTOM,
+ CURSOR_DRAGGING,
+ CURSOR_LEFT_PTR,
+ CURSOR_LEFT,
+ CURSOR_RIGHT,
+ CURSOR_TOP_LEFT,
+ CURSOR_TOP_RIGHT,
+ CURSOR_TOP,
+ CURSOR_IBEAM,
+ CURSOR_HAND1,
+ CURSOR_WATCH,
+
+ CURSOR_BLANK
+};
+struct wlContextCommon {
+ struct wl_display *wlDisplay;
+ struct wl_registry *wlRegistry;
+ struct wl_compositor *wlCompositor;
+ struct wl_shm *wlShm;
+ struct wl_seat *wlSeat;
+ struct wl_pointer *wlPointer;
+ struct wl_touch *wlTouch;
+ struct ivi_application *iviApplication;
+ struct ivi_hmi_controller *hmiCtrl;
+ struct hmi_homescreen_setting *hmi_setting;
+ struct wl_list *list_wlContextStruct;
+ struct wl_surface *enterSurface;
+ int32_t is_home_on;
+ struct wl_cursor_theme *cursor_theme;
+ struct wl_cursor **cursors;
+ struct wl_surface *pointer_surface;
+ enum cursor_type current_cursor;
+ uint32_t enter_serial;
+};
+
+struct wlContextStruct {
+ struct wlContextCommon cmm;
+ struct wl_surface *wlSurface;
+ struct wl_buffer *wlBuffer;
+ uint32_t formats;
+ cairo_surface_t *ctx_image;
+ void *data;
+ uint32_t id_surface;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_srf {
+ uint32_t id;
+ char *filePath;
+ uint32_t color;
+};
+
+struct
+hmi_homescreen_workspace {
+ struct wl_array launcher_id_array;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_launcher {
+ uint32_t icon_surface_id;
+ uint32_t workspace_id;
+ char* icon;
+ char* path;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_setting {
+ struct hmi_homescreen_srf background;
+ struct hmi_homescreen_srf panel;
+ struct hmi_homescreen_srf tiling;
+ struct hmi_homescreen_srf sidebyside;
+ struct hmi_homescreen_srf fullscreen;
+ struct hmi_homescreen_srf random;
+ struct hmi_homescreen_srf home;
+ struct hmi_homescreen_srf workspace_background;
+
+ struct wl_list workspace_list;
+ struct wl_list launcher_list;
+
+ char *cursor_theme;
+ int32_t cursor_size;
+};
+
+volatile int gRun = 0;
+
+static void *
+fail_on_null(void *p, size_t size, char* file, int32_t line)
+{
+ if (size && !p) {
+ fprintf(stderr, "%s(%d) %zd: out of memory\n", file, line, size);
+ exit(EXIT_FAILURE);
+ }
+
+ return p;
+}
+
+static void *
+mem_alloc(size_t size, char* file, int32_t line)
+{
+ return fail_on_null(calloc(1, size), size, file, line);
+}
+
+#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+/*****************************************************************************
+ * Event Handler
+ ****************************************************************************/
+
+static void
+shm_format(void* data, struct wl_shm* pWlShm, uint32_t format)
+{
+ struct wlContextStruct* pDsp = data;
+ pDsp->formats |= (1 << format);
+}
+
+static struct wl_shm_listener shm_listenter = {
+ shm_format
+};
+
+static int32_t
+getIdOfWlSurface(struct wlContextCommon *pCtx, struct wl_surface *wlSurface)
+{
+ if (NULL == pCtx ||
+ NULL == wlSurface ) {
+ return 0;
+ }
+
+ struct wlContextStruct* pWlCtxSt = NULL;
+ wl_list_for_each(pWlCtxSt, pCtx->list_wlContextStruct, link) {
+ if (pWlCtxSt->wlSurface == wlSurface) {
+ return pWlCtxSt->id_surface;
+ }
+ continue;
+ }
+ return -1;
+}
+
+static void
+set_pointer_image(struct wlContextCommon *pCtx, uint32_t index)
+{
+ if (!pCtx->wlPointer ||
+ !pCtx->cursors) {
+ return;
+ }
+
+ if (CURSOR_BLANK == pCtx->current_cursor) {
+ wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
+ NULL, 0, 0);
+ return;
+ }
+
+ struct wl_cursor *cursor = pCtx->cursors[pCtx->current_cursor];
+ if (!cursor) {
+ return;
+ }
+
+ if (cursor->image_count <= index) {
+ fprintf(stderr, "cursor index out of range\n");
+ return;
+ }
+
+ struct wl_cursor_image *image = cursor->images[index];
+ struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
+
+ if (!buffer) {
+ return;
+ }
+
+ wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
+ pCtx->pointer_surface,
+ image->hotspot_x, image->hotspot_y);
+
+ wl_surface_attach(pCtx->pointer_surface, buffer, 0, 0);
+
+ wl_surface_damage(pCtx->pointer_surface, 0, 0,
+ image->width, image->height);
+
+ wl_surface_commit(pCtx->pointer_surface);
+}
+
+static void
+PointerHandleEnter(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ struct wl_surface* wlSurface, wl_fixed_t sx, wl_fixed_t sy)
+{
+ (void)wlPointer;
+ (void)serial;
+
+ struct wlContextCommon *pCtx = data;
+ pCtx->enter_serial = serial;
+ pCtx->enterSurface = wlSurface;
+ set_pointer_image(pCtx, 0);
+#ifdef _DEBUG
+ printf("ENTER PointerHandleEnter: x(%d), y(%d)\n", sx, sy);
+#endif
+}
+
+static void
+PointerHandleLeave(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ struct wl_surface* wlSurface)
+{
+ (void)wlPointer;
+ (void)wlSurface;
+
+ struct wlContextCommon *pCtx = data;
+ pCtx->enterSurface = NULL;
+
+#ifdef _DEBUG
+ printf("ENTER PointerHandleLeave: serial(%d)\n", serial);
+#endif
+}
+
+static void
+PointerHandleMotion(void* data, struct wl_pointer* wlPointer, uint32_t time,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ (void)data;
+ (void)wlPointer;
+ (void)time;
+
+#ifdef _DEBUG
+ printf("ENTER PointerHandleMotion: x(%d), y(%d)\n", gPointerX, gPointerY);
+#endif
+}
+
+/**
+ * if a surface assigned as launcher receives touch-off event, invoking
+ * ivi-application which configured in weston.ini with path to binary.
+ */
+extern char **environ; /*defied by libc */
+
+static pid_t execute_process(char* path, char *argv[])
+{
+ pid_t pid = fork();
+ if (pid < 0) {
+ fprintf(stderr, "Failed to fork\n");
+ }
+
+ if (pid) {
+ return pid;
+ }
+
+ if (-1 == execve(path, argv, environ)) {
+ fprintf(stderr, "Failed to execve %s\n", path);
+ exit(1);
+ }
+
+ return pid;
+}
+
+static int32_t
+launcher_button(uint32_t surfaceId, struct wl_list *launcher_list)
+{
+ struct hmi_homescreen_launcher *launcher = NULL;
+
+ wl_list_for_each(launcher, launcher_list, link) {
+ if (surfaceId != launcher->icon_surface_id) {
+ continue;
+ }
+
+ char *argv[] = {NULL};
+ execute_process(launcher->path, argv);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * is-method to identify a surface set as launcher in workspace or workspace
+ * itself. This is-method is used to decide whether request;
+ * ivi_hmi_controller_workspace_control is sent or not.
+ */
+static int32_t
+isWorkspaceSurface(uint32_t id, struct hmi_homescreen_setting *hmi_setting)
+{
+ if (id == hmi_setting->workspace_background.id) {
+ return 1;
+ }
+
+ struct hmi_homescreen_launcher *launcher = NULL;
+ wl_list_for_each(launcher, &hmi_setting->launcher_list, link) {
+ if (id == launcher->icon_surface_id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Decide which request is sent to hmi-controller
+ */
+static void
+touch_up(struct ivi_hmi_controller *hmi_ctrl, uint32_t id_surface,
+ int32_t *is_home_on, struct hmi_homescreen_setting* hmi_setting)
+{
+ if (launcher_button(id_surface, &hmi_setting->launcher_list)) {
+ *is_home_on = 0;
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ } else if (id_surface == hmi_setting->tiling.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING);
+ } else if (id_surface == hmi_setting->sidebyside.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE);
+ } else if (id_surface == hmi_setting->fullscreen.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN);
+ } else if (id_surface == hmi_setting->random.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM);
+ } else if (id_surface == hmi_setting->home.id) {
+ *is_home_on = !(*is_home_on);
+ if (*is_home_on) {
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_ON);
+ } else {
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ }
+ }
+}
+
+/**
+ * Even handler of Pointer event. IVI system is usually manipulated by touch
+ * screen. However, some systems also have pointer device.
+ * Release is the same behavior as touch off
+ * Pressed is the same behavior as touch on
+ */
+static void
+PointerHandleButton(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ uint32_t time, uint32_t button, uint32_t state)
+{
+ (void)wlPointer;
+ (void)serial;
+ (void)time;
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ if (BTN_RIGHT == button) {
+ return;
+ }
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ switch (state) {
+ case WL_POINTER_BUTTON_STATE_RELEASED:
+ touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, pCtx->hmi_setting);
+ break;
+
+ case WL_POINTER_BUTTON_STATE_PRESSED:
+
+ if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
+ ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, serial);
+ }
+
+ break;
+ }
+#ifdef _DEBUG
+ printf("ENTER PointerHandleButton: button(%d), state(%d)\n", button, state);
+#endif
+}
+
+static void
+PointerHandleAxis(void* data, struct wl_pointer* wlPointer, uint32_t time,
+ uint32_t axis, wl_fixed_t value)
+{
+ (void)data;
+ (void)wlPointer;
+ (void)time;
+#ifdef _DEBUG
+ printf("ENTER PointerHandleAxis: axis(%d), value(%d)\n", axis, value);
+#endif
+}
+
+static struct wl_pointer_listener pointer_listener = {
+ PointerHandleEnter,
+ PointerHandleLeave,
+ PointerHandleMotion,
+ PointerHandleButton,
+ PointerHandleAxis
+};
+
+/**
+ * Even handler of touch event
+ */
+static void
+TouchHandleDown(void *data, struct wl_touch *wlTouch, uint32_t serial, uint32_t time,
+ struct wl_surface *surface, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ if (0 == id){
+ pCtx->enterSurface = surface;
+ }
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * When touch down happens on surfaces of workspace, ask hmi-controller to start
+ * control workspace to select page of workspace.
+ * After sending seat to hmi-controller by ivi_hmi_controller_workspace_control,
+ * hmi-controller-homescreen doesn't receive any event till hmi-controller sends
+ * back it.
+ */
+ if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
+ ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, serial);
+ }
+}
+
+static void
+TouchHandleUp(void *data, struct wl_touch *wlTouch, uint32_t serial, uint32_t time,
+ int32_t id)
+{
+ (void)serial;
+ (void)time;
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * triggering event according to touch-up happening on which surface.
+ */
+ if (id == 0){
+ touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, pCtx->hmi_setting);
+ }
+}
+
+static void
+TouchHandleMotion(void *data, struct wl_touch *wlTouch, uint32_t time,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+}
+
+static void
+TouchHandleFrame(void *data, struct wl_touch *wlTouch)
+{
+}
+
+static void
+TouchHandleCancel(void *data, struct wl_touch *wlTouch)
+{
+}
+
+static struct wl_touch_listener touch_listener = {
+ TouchHandleDown,
+ TouchHandleUp,
+ TouchHandleMotion,
+ TouchHandleFrame,
+ TouchHandleCancel,
+};
+
+/**
+ * Handler of capabilities
+ */
+static void
+seat_handle_capabilities(void* data, struct wl_seat* seat, uint32_t caps)
+{
+ (void)seat;
+ struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
+ struct wl_seat* wlSeat = p_wlCtx->wlSeat;
+ struct wl_pointer* wlPointer = p_wlCtx->wlPointer;
+ struct wl_touch* wlTouch = p_wlCtx->wlTouch;
+
+ if (p_wlCtx->hmi_setting->cursor_theme) {
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wlPointer){
+ wlPointer = wl_seat_get_pointer(wlSeat);
+ wl_pointer_set_user_data(wlPointer, data);
+ wl_pointer_add_listener(wlPointer, &pointer_listener, data);
+ } else
+ if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wlPointer){
+ wl_pointer_destroy(wlPointer);
+ wlPointer = NULL;
+ }
+ p_wlCtx->wlPointer = wlPointer;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wlTouch){
+ wlTouch = wl_seat_get_touch(wlSeat);
+ wl_touch_set_user_data(wlTouch, data);
+ wl_touch_add_listener(wlTouch, &touch_listener, data);
+ } else
+ if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wlTouch){
+ wl_touch_destroy(wlTouch);
+ wlTouch = NULL;
+ }
+ p_wlCtx->wlTouch = wlTouch;
+}
+
+static struct wl_seat_listener seat_Listener = {
+ seat_handle_capabilities,
+};
+
+/**
+ * Registration of event
+ * This event is received when hmi-controller server finished controlling
+ * workspace.
+ */
+static void
+ivi_hmi_controller_workspace_end_control(void *data,
+ struct ivi_hmi_controller *hmi_ctrl,
+ int32_t is_controlled)
+{
+ if (is_controlled) {
+ return;
+ }
+
+ struct wlContextCommon *pCtx = data;
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * During being controlled by hmi-controller, any input event is not
+ * notified. So when control ends with touch up, it invokes launcher
+ * if up event happens on a launcher surface.
+ *
+ */
+ if (launcher_button(id_surface, &pCtx->hmi_setting->launcher_list)) {
+ pCtx->is_home_on = 0;
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ }
+}
+
+static const struct ivi_hmi_controller_listener hmi_controller_listener = {
+ ivi_hmi_controller_workspace_end_control
+};
+
+/**
+ * Registration of interfaces
+ */
+static void
+registry_handle_global(void* data, struct wl_registry* registry, uint32_t name,
+ const char *interface, uint32_t version)
+{
+ (void)version;
+ struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
+
+ do {
+ if (!strcmp(interface, "wl_compositor")) {
+ p_wlCtx->wlCompositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+ break;
+ }
+ if (!strcmp(interface, "wl_shm")) {
+ p_wlCtx->wlShm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
+ wl_shm_add_listener(p_wlCtx->wlShm, &shm_listenter, p_wlCtx);
+ break;
+ }
+ if (!strcmp(interface, "wl_seat")) {
+ p_wlCtx->wlSeat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
+ wl_seat_add_listener(p_wlCtx->wlSeat, &seat_Listener, data);
+ break;
+ }
+ if (!strcmp(interface, "ivi_application")) {
+ p_wlCtx->iviApplication = wl_registry_bind(registry, name, &ivi_application_interface, 1);
+ break;
+ }
+ if (!strcmp(interface, "ivi_hmi_controller")) {
+ p_wlCtx->hmiCtrl = wl_registry_bind(registry, name, &ivi_hmi_controller_interface, 1);
+
+ if (p_wlCtx->hmiCtrl) {
+ ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl, &hmi_controller_listener, p_wlCtx);
+ }
+ break;
+ }
+
+ } while(0);
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ NULL
+};
+
+static void
+frame_listener_func(void *data, struct wl_callback *callback, uint32_t time)
+{
+ if (callback) {
+ wl_callback_destroy(callback);
+ }
+}
+
+static const struct wl_callback_listener frame_listener = {
+ frame_listener_func
+};
+
+/*
+ * The following correspondences between file names and cursors was copied
+ * from: https://bugs.kde.org/attachment.cgi?id=67313
+ */
+static const char *bottom_left_corners[] = {
+ "bottom_left_corner",
+ "sw-resize",
+ "size_bdiag"
+};
+
+static const char *bottom_right_corners[] = {
+ "bottom_right_corner",
+ "se-resize",
+ "size_fdiag"
+};
+
+static const char *bottom_sides[] = {
+ "bottom_side",
+ "s-resize",
+ "size_ver"
+};
+
+static const char *grabbings[] = {
+ "grabbing",
+ "closedhand",
+ "208530c400c041818281048008011002"
+};
+
+static const char *left_ptrs[] = {
+ "left_ptr",
+ "default",
+ "top_left_arrow",
+ "left-arrow"
+};
+
+static const char *left_sides[] = {
+ "left_side",
+ "w-resize",
+ "size_hor"
+};
+
+static const char *right_sides[] = {
+ "right_side",
+ "e-resize",
+ "size_hor"
+};
+
+static const char *top_left_corners[] = {
+ "top_left_corner",
+ "nw-resize",
+ "size_fdiag"
+};
+
+static const char *top_right_corners[] = {
+ "top_right_corner",
+ "ne-resize",
+ "size_bdiag"
+};
+
+static const char *top_sides[] = {
+ "top_side",
+ "n-resize",
+ "size_ver"
+};
+
+static const char *xterms[] = {
+ "xterm",
+ "ibeam",
+ "text"
+};
+
+static const char *hand1s[] = {
+ "hand1",
+ "pointer",
+ "pointing_hand",
+ "e29285e634086352946a0e7090d73106"
+};
+
+static const char *watches[] = {
+ "watch",
+ "wait",
+ "0426c94ea35c87780ff01dc239897213"
+};
+
+struct cursor_alternatives {
+ const char **names;
+ size_t count;
+};
+
+static const struct cursor_alternatives cursors[] = {
+ {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
+ {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
+ {bottom_sides, ARRAY_LENGTH(bottom_sides)},
+ {grabbings, ARRAY_LENGTH(grabbings)},
+ {left_ptrs, ARRAY_LENGTH(left_ptrs)},
+ {left_sides, ARRAY_LENGTH(left_sides)},
+ {right_sides, ARRAY_LENGTH(right_sides)},
+ {top_left_corners, ARRAY_LENGTH(top_left_corners)},
+ {top_right_corners, ARRAY_LENGTH(top_right_corners)},
+ {top_sides, ARRAY_LENGTH(top_sides)},
+ {xterms, ARRAY_LENGTH(xterms)},
+ {hand1s, ARRAY_LENGTH(hand1s)},
+ {watches, ARRAY_LENGTH(watches)},
+};
+
+static void
+create_cursors(struct wlContextCommon *cmm)
+{
+ uint32_t i = 0;
+ uint32_t j = 0;
+ struct wl_cursor *cursor = NULL;
+ char* cursor_theme = cmm->hmi_setting->cursor_theme;
+ int32_t cursor_size = cmm->hmi_setting->cursor_size;
+
+ cmm->cursor_theme = wl_cursor_theme_load(cursor_theme, cursor_size, cmm->wlShm);
+
+ cmm->cursors = MEM_ALLOC(ARRAY_LENGTH(cursors) * sizeof(cmm->cursors[0]));
+
+ for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
+ cursor = NULL;
+
+ for (j = 0; !cursor && j < cursors[i].count; ++j) {
+ cursor = wl_cursor_theme_get_cursor(
+ cmm->cursor_theme, cursors[i].names[j]);
+ }
+
+ if (!cursor) {
+ fprintf(stderr, "could not load cursor '%s'\n",
+ cursors[i].names[0]);
+ }
+
+ cmm->cursors[i] = cursor;
+ }
+}
+
+static void
+destroy_cursors(struct wlContextCommon *cmm)
+{
+ if (cmm->cursor_theme) {
+ wl_cursor_theme_destroy(cmm->cursor_theme);
+ }
+
+ free(cmm->cursors);
+}
+
+/**
+ * Internal method to prepare parts of UI
+ */
+static void
+createShmBuffer(struct wlContextStruct *p_wlCtx)
+{
+ struct wl_shm_pool *pool;
+
+ char filename[] = "/tmp/wayland-shm-XXXXXX";
+ int fd = -1;
+ int size = 0;
+ int width = 0;
+ int height = 0;
+ int stride = 0;
+
+ fd = mkstemp(filename);
+ if (fd < 0) {
+ fprintf(stderr, "open %s failed: %m\n", filename);
+ return;
+ }
+
+ width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
+ height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
+ stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
+
+ size = stride * height;
+ if (ftruncate(fd, size) < 0) {
+ fprintf(stderr, "ftruncate failed: %m\n");
+ close(fd);
+ return;
+ }
+
+ p_wlCtx->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ if (MAP_FAILED == p_wlCtx->data) {
+ fprintf(stderr, "mmap failed: %m\n");
+ close(fd);
+ return;
+ }
+
+ pool = wl_shm_create_pool(p_wlCtx->cmm.wlShm, fd, size);
+ p_wlCtx->wlBuffer = wl_shm_pool_create_buffer(pool, 0,
+ width,
+ height,
+ stride,
+ WL_SHM_FORMAT_ARGB8888);
+
+ if (NULL == p_wlCtx->wlBuffer) {
+ fprintf(stderr, "wl_shm_create_buffer failed: %m\n");
+ close(fd);
+ return;
+ }
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ return;
+}
+
+static void
+destroyWLContextCommon(struct wlContextCommon *p_wlCtx)
+{
+ destroy_cursors(p_wlCtx);
+
+ if (p_wlCtx->pointer_surface) {
+ wl_surface_destroy(p_wlCtx->pointer_surface);
+ }
+
+ if (p_wlCtx->wlCompositor) {
+ wl_compositor_destroy(p_wlCtx->wlCompositor);
+ }
+}
+
+static void
+destroyWLContextStruct(struct wlContextStruct *p_wlCtx)
+{
+ if (p_wlCtx->wlSurface) {
+ wl_surface_destroy(p_wlCtx->wlSurface);
+ }
+
+ if (p_wlCtx->ctx_image) {
+ cairo_surface_destroy(p_wlCtx->ctx_image);
+ p_wlCtx->ctx_image = NULL;
+ }
+}
+
+static int
+createWLContext(struct wlContextStruct *p_wlCtx)
+{
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+
+ p_wlCtx->wlSurface = wl_compositor_create_surface(p_wlCtx->cmm.wlCompositor);
+ if (NULL == p_wlCtx->wlSurface) {
+ printf("Error: wl_compositor_create_surface failed.\n");
+ destroyWLContextCommon(&p_wlCtx->cmm);
+ abort();
+ }
+
+
+ createShmBuffer(p_wlCtx);
+
+ wl_display_flush(p_wlCtx->cmm.wlDisplay);
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+
+ return 0;
+}
+
+static void
+drawImage(struct wlContextStruct *p_wlCtx)
+{
+ struct wl_callback *callback;
+
+ int width = 0;
+ int height = 0;
+ int stride = 0;
+ void *data = NULL;
+
+ width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
+ height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
+ stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
+ data = cairo_image_surface_get_data(p_wlCtx->ctx_image);
+
+ memcpy(p_wlCtx->data, data, stride * height);
+
+ wl_surface_attach(p_wlCtx->wlSurface, p_wlCtx->wlBuffer, 0, 0);
+ wl_surface_damage(p_wlCtx->wlSurface, 0, 0, width, height);
+
+ callback = wl_surface_frame(p_wlCtx->wlSurface);
+ wl_callback_add_listener(callback, &frame_listener, NULL);
+
+ wl_surface_commit(p_wlCtx->wlSurface);
+
+ wl_display_flush(p_wlCtx->cmm.wlDisplay);
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+}
+
+static void
+create_ivisurface(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ cairo_surface_t* surface)
+{
+ struct ivi_surface *ivisurf = NULL;
+
+ p_wlCtx->ctx_image = surface;
+
+ p_wlCtx->id_surface = id_surface;
+ wl_list_init(&p_wlCtx->link);
+ wl_list_insert(p_wlCtx->cmm.list_wlContextStruct, &p_wlCtx->link);
+
+ createWLContext(p_wlCtx);
+
+ ivisurf = ivi_application_surface_create(p_wlCtx->cmm.iviApplication,
+ id_surface, p_wlCtx->wlSurface);
+ if (ivisurf == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ return;
+ }
+
+ drawImage(p_wlCtx);
+
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+}
+
+static void
+create_ivisurfaceFromFile(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ const char* imageFile)
+{
+ cairo_surface_t* surface = load_cairo_surface(imageFile);
+
+ if (NULL == surface) {
+ fprintf(stderr, "Failed to load_cairo_surface %s\n", imageFile);
+ return;
+ }
+
+ create_ivisurface(p_wlCtx, id_surface, surface);
+}
+
+static void
+set_hex_color(cairo_t *cr, uint32_t color)
+{
+ cairo_set_source_rgba(cr,
+ ((color >> 16) & 0xff) / 255.0,
+ ((color >> 8) & 0xff) / 255.0,
+ ((color >> 0) & 0xff) / 255.0,
+ ((color >> 24) & 0xff) / 255.0);
+}
+
+static void
+create_ivisurfaceFromColor(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ uint32_t width, uint32_t height,
+ uint32_t color)
+{
+ cairo_surface_t *surface = NULL;
+ cairo_t *cr = NULL;
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+
+ cr = cairo_create(surface);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle(cr, 0, 0, width, height);
+ set_hex_color(cr, color);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+
+ create_ivisurface(p_wlCtx, id_surface, surface);
+}
+
+static void
+UI_ready(struct ivi_hmi_controller *controller)
+{
+ ivi_hmi_controller_UI_ready(controller);
+}
+
+/**
+ * Internal method to set up UI by using ivi-hmi-controller
+ */
+static void
+create_background(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+}
+
+static void
+create_panel(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+}
+
+static void
+create_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile, uint32_t number)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+}
+
+static void
+create_home_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+}
+
+static void
+create_workspace_background(
+ struct wlContextStruct *p_wlCtx, struct hmi_homescreen_srf *srf)
+{
+ create_ivisurfaceFromColor(p_wlCtx, srf->id, 1, 1, srf->color);
+}
+
+static void
+create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list)
+{
+ int launcher_count = wl_list_length(launcher_list);
+
+ if (0 == launcher_count) {
+ return;
+ }
+
+ struct hmi_homescreen_launcher** launchers;
+ launchers = MEM_ALLOC(launcher_count * sizeof(*launchers));
+
+ int ii = 0;
+ struct hmi_homescreen_launcher *launcher = NULL;
+
+ wl_list_for_each(launcher, launcher_list, link) {
+ launchers[ii] = launcher;
+ ii++;
+ }
+
+ int start = 0;
+
+ for (ii = 0; ii < launcher_count; ii++) {
+
+ if (ii != launcher_count -1 &&
+ launchers[ii]->workspace_id == launchers[ii + 1]->workspace_id) {
+ continue;
+ }
+
+ int jj = 0;
+ for (jj = start; jj <= ii; jj++) {
+ struct wlContextStruct *p_wlCtx = MEM_ALLOC(sizeof(*p_wlCtx));
+ p_wlCtx->cmm = *cmm;
+ create_ivisurfaceFromFile(p_wlCtx,launchers[jj]->icon_surface_id, launchers[jj]->icon);
+ }
+
+ start = ii + 1;
+ }
+
+ free(launchers);
+}
+
+static void sigFunc(int signum)
+{
+ gRun = 0;
+}
+
+/**
+ * Internal method to read out weston.ini to get configuration
+ */
+static struct hmi_homescreen_setting*
+hmi_homescreen_setting_create(void)
+{
+ struct hmi_homescreen_setting* setting = MEM_ALLOC(sizeof(*setting));
+
+ wl_list_init(&setting->workspace_list);
+ wl_list_init(&setting->launcher_list);
+
+ struct weston_config *config = NULL;
+ config = weston_config_parse("weston.ini");
+
+ struct weston_config_section *shellSection = NULL;
+ shellSection = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ weston_config_section_get_string(
+ shellSection, "cursor-theme", &setting->cursor_theme, NULL);
+
+ weston_config_section_get_int(shellSection, "cursor-size", &setting->cursor_size, 32);
+
+ uint32_t workspace_layer_id;
+ weston_config_section_get_uint(
+ shellSection, "workspace-layer-id", &workspace_layer_id, 3000);
+
+ weston_config_section_get_string(
+ shellSection, "background-image", &setting->background.filePath,
+ DATADIR "/weston/background.png");
+
+ weston_config_section_get_uint(
+ shellSection, "background-id", &setting->background.id, 1001);
+
+ weston_config_section_get_string(
+ shellSection, "panel-image", &setting->panel.filePath,
+ DATADIR "/weston/panel.png");
+
+ weston_config_section_get_uint(
+ shellSection, "panel-id", &setting->panel.id, 1002);
+
+ weston_config_section_get_string(
+ shellSection, "tiling-image", &setting->tiling.filePath,
+ DATADIR "/weston/tiling.png");
+
+ weston_config_section_get_uint(
+ shellSection, "tiling-id", &setting->tiling.id, 1003);
+
+ weston_config_section_get_string(
+ shellSection, "sidebyside-image", &setting->sidebyside.filePath,
+ DATADIR "/weston/sidebyside.png");
+
+ weston_config_section_get_uint(
+ shellSection, "sidebyside-id", &setting->sidebyside.id, 1004);
+
+ weston_config_section_get_string(
+ shellSection, "fullscreen-image", &setting->fullscreen.filePath,
+ DATADIR "/weston/fullscreen.png");
+
+ weston_config_section_get_uint(
+ shellSection, "fullscreen-id", &setting->fullscreen.id, 1005);
+
+ weston_config_section_get_string(
+ shellSection, "random-image", &setting->random.filePath,
+ DATADIR "/weston/random.png");
+
+ weston_config_section_get_uint(
+ shellSection, "random-id", &setting->random.id, 1006);
+
+ weston_config_section_get_string(
+ shellSection, "home-image", &setting->home.filePath,
+ DATADIR "/weston/home.png");
+
+ weston_config_section_get_uint(
+ shellSection, "home-id", &setting->home.id, 1007);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-color",
+ &setting->workspace_background.color, 0x99000000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-id",
+ &setting->workspace_background.id, 2001);
+
+ struct weston_config_section *section = NULL;
+ const char *name = NULL;
+
+ uint32_t icon_surface_id = workspace_layer_id + 1;
+
+ while (weston_config_next_section(config, &section, &name)) {
+
+ if (0 == strcmp(name, "ivi-launcher")) {
+
+ struct hmi_homescreen_launcher *launcher = NULL;
+ launcher = MEM_ALLOC(sizeof(*launcher));
+ wl_list_init(&launcher->link);
+
+ weston_config_section_get_string(section, "icon", &launcher->icon, NULL);
+ weston_config_section_get_string(section, "path", &launcher->path, NULL);
+ weston_config_section_get_uint(section, "workspace-id", &launcher->workspace_id, 0);
+ weston_config_section_get_uint(section, "icon-id", &launcher->icon_surface_id, icon_surface_id);
+ icon_surface_id++;
+
+ wl_list_insert(setting->launcher_list.prev, &launcher->link);
+ }
+ }
+
+ weston_config_destroy(config);
+ return setting;
+}
+
+/**
+ * Main thread
+ *
+ * The basic flow are as followed,
+ * 1/ read configuration from weston.ini by hmi_homescreen_setting_create
+ * 2/ draw png file to surface according to configuration of weston.ini and
+ * set up UI by using ivi-hmi-controller protocol by each create_* method
+ */
+int main(int argc, char **argv)
+{
+ struct wlContextCommon wlCtxCommon;
+ struct wlContextStruct wlCtx_BackGround;
+ struct wlContextStruct wlCtx_Panel;
+ struct wlContextStruct wlCtx_Button_1;
+ struct wlContextStruct wlCtx_Button_2;
+ struct wlContextStruct wlCtx_Button_3;
+ struct wlContextStruct wlCtx_Button_4;
+ struct wlContextStruct wlCtx_HomeButton;
+ struct wlContextStruct wlCtx_WorkSpaceBackGround;
+ struct wl_list launcher_wlCtxList;
+
+ memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon));
+ memset(&wlCtx_BackGround, 0x00, sizeof(wlCtx_BackGround));
+ memset(&wlCtx_Panel, 0x00, sizeof(wlCtx_Panel));
+ memset(&wlCtx_Button_1, 0x00, sizeof(wlCtx_Button_1));
+ memset(&wlCtx_Button_2, 0x00, sizeof(wlCtx_Button_2));
+ memset(&wlCtx_Button_3, 0x00, sizeof(wlCtx_Button_3));
+ memset(&wlCtx_Button_4, 0x00, sizeof(wlCtx_Button_4));
+ memset(&wlCtx_HomeButton, 0x00, sizeof(wlCtx_HomeButton));
+ memset(&wlCtx_WorkSpaceBackGround, 0x00, sizeof(wlCtx_WorkSpaceBackGround));
+ wl_list_init(&launcher_wlCtxList);
+ wlCtxCommon.list_wlContextStruct = MEM_ALLOC(sizeof(struct wl_list));
+ assert(wlCtxCommon.list_wlContextStruct);
+ wl_list_init(wlCtxCommon.list_wlContextStruct);
+
+ struct hmi_homescreen_setting *hmi_setting = hmi_homescreen_setting_create();
+ wlCtxCommon.hmi_setting = hmi_setting;
+
+ gRun = 1;
+
+ wlCtxCommon.wlDisplay = wl_display_connect(NULL);
+ if (NULL == wlCtxCommon.wlDisplay) {
+ printf("Error: wl_display_connect failed.\n");
+ return -1;
+ }
+
+ /* get wl_registry */
+ wlCtxCommon.wlRegistry = wl_display_get_registry(wlCtxCommon.wlDisplay);
+ wl_registry_add_listener(wlCtxCommon.wlRegistry,
+ &registry_listener, &wlCtxCommon);
+ wl_display_dispatch(wlCtxCommon.wlDisplay);
+ wl_display_roundtrip(wlCtxCommon.wlDisplay);
+
+ if (wlCtxCommon.hmi_setting->cursor_theme) {
+ create_cursors(&wlCtxCommon);
+
+ wlCtxCommon.pointer_surface =
+ wl_compositor_create_surface(wlCtxCommon.wlCompositor);
+
+ wlCtxCommon.current_cursor = CURSOR_LEFT_PTR;
+ }
+
+ wlCtx_BackGround.cmm = wlCtxCommon;
+ wlCtx_Panel.cmm = wlCtxCommon;
+ wlCtx_Button_1.cmm = wlCtxCommon;
+ wlCtx_Button_2.cmm = wlCtxCommon;
+ wlCtx_Button_3.cmm = wlCtxCommon;
+ wlCtx_Button_4.cmm = wlCtxCommon;
+ wlCtx_HomeButton.cmm = wlCtxCommon;
+ wlCtx_WorkSpaceBackGround.cmm = wlCtxCommon;
+
+ /* create desktop widgets */
+ create_background(&wlCtx_BackGround, hmi_setting->background.id,
+ hmi_setting->background.filePath);
+
+ create_panel(&wlCtx_Panel, hmi_setting->panel.id,
+ hmi_setting->panel.filePath);
+
+ create_button(&wlCtx_Button_1, hmi_setting->tiling.id,
+ hmi_setting->tiling.filePath, 0);
+
+ create_button(&wlCtx_Button_2, hmi_setting->sidebyside.id,
+ hmi_setting->sidebyside.filePath, 1);
+
+ create_button(&wlCtx_Button_3, hmi_setting->fullscreen.id,
+ hmi_setting->fullscreen.filePath, 2);
+
+ create_button(&wlCtx_Button_4, hmi_setting->random.id,
+ hmi_setting->random.filePath, 3);
+
+ create_workspace_background(&wlCtx_WorkSpaceBackGround,
+ &hmi_setting->workspace_background);
+
+ create_launchers(&wlCtxCommon, &hmi_setting->launcher_list);
+
+ create_home_button(&wlCtx_HomeButton, hmi_setting->home.id,
+ hmi_setting->home.filePath);
+
+ UI_ready(wlCtxCommon.hmiCtrl);
+
+ /* signal handling */
+ signal(SIGINT, sigFunc);
+ signal(SIGKILL, sigFunc);
+
+ while(gRun) {
+ wl_display_dispatch(wlCtxCommon.wlDisplay);
+ }
+
+ struct wlContextStruct* pWlCtxSt = NULL;
+ wl_list_for_each(pWlCtxSt, wlCtxCommon.list_wlContextStruct, link) {
+ destroyWLContextStruct(pWlCtxSt);
+ }
+
+ destroyWLContextCommon(&wlCtxCommon);
+ free(wlCtxCommon.list_wlContextStruct);
+
+ return 0;
+}
diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
index e04fe61..4fd15e8 100644
--- a/ivi-shell/hmi-controller.c
+++ b/ivi-shell/hmi-controller.c
@@ -152,6 +152,10 @@ struct hmi_controller
int32_t workspace_count;
struct wl_array ui_widgets;
int32_t is_initialized;
+
+ struct weston_compositor *compositor;
+ struct weston_process process;
+ struct wl_listener destroy_listener;
};

struct launcher_info
@@ -831,6 +835,9 @@ hmi_server_setting_create(void)

setting->panel_height = 70;

+ weston_config_section_get_string(
+ shellSection, "ivi-shell-user-interface", &setting->ivi_homescreen, NULL);
+
weston_config_destroy(config);

return setting;
@@ -1897,9 +1904,36 @@ bind_hmi_controller(struct wl_client *client,
}

static void
-launch_hmi_client(void *data)
+handle_hmi_client_process_sigchld(struct weston_process *proc, int status)
+{
+ proc->pid = 0;
+}
+
+static void
+hmi_client_destroy(struct wl_listener *listener, void *data)
+{
+ struct hmi_controller *hmi_ctrl =
+ container_of(listener, struct hmi_controller, destroy_listener);
+
+ kill(hmi_ctrl->process.pid, SIGTERM);
+ hmi_ctrl->process.pid = 0;
+}
+
+static void
+launch_hmi_client_process(void *data)
{
- /*Nothing to do here*/
+ struct hmi_controller *hmi_ctrl =
+ (struct hmi_controller *)data;
+
+ weston_client_launch(hmi_ctrl->compositor,
+ &hmi_ctrl->process,
+ hmi_ctrl->hmi_setting->ivi_homescreen,
+ handle_hmi_client_process_sigchld);
+
+ hmi_ctrl->destroy_listener.notify = hmi_client_destroy;
+ wl_signal_add(&hmi_ctrl->compositor->destroy_signal, &hmi_ctrl->destroy_listener);
+
+ free(hmi_ctrl->hmi_setting->ivi_homescreen);
}

/*****************************************************************************
@@ -1911,6 +1945,7 @@ module_init(struct weston_compositor *ec,
int *argc, char *argv[])
{
struct hmi_controller *hmi_ctrl = hmi_controller_create(ec);
+ hmi_ctrl->compositor = ec;

if (wl_global_create(ec->wl_display,
&ivi_hmi_controller_interface, 1,
@@ -1919,7 +1954,7 @@ module_init(struct weston_compositor *ec,
}

struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
- wl_event_loop_add_idle(loop, launch_hmi_client, ec);
+ wl_event_loop_add_idle(loop, launch_hmi_client_process, hmi_ctrl);

return 0;
}
--
1.8.3.1
Nobuhiko Tanibata
2014-06-25 12:08:39 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3, v4, and v5:
- nothing. Version number aligned to the first patch

Changes for v6:
- apply review comment from mailing list; Makefile.am.

Makefile.am | 14 +++++++++++++-
data/Makefile.am | 14 +++++++++++++-
data/background.png | Bin 0 -> 245579 bytes
data/fullscreen.png | Bin 0 -> 3406 bytes
data/home.png | Bin 0 -> 4629 bytes
data/icon_ivi_clickdot.png | Bin 0 -> 39523 bytes
data/icon_ivi_flower.png | Bin 0 -> 24475 bytes
data/icon_ivi_simple-egl.png | Bin 0 -> 29316 bytes
data/icon_ivi_simple-shm.png | Bin 0 -> 71120 bytes
data/icon_ivi_smoke.png | Bin 0 -> 46577 bytes
data/panel.png | Bin 0 -> 41955 bytes
data/random.png | Bin 0 -> 4891 bytes
data/sidebyside.png | Bin 0 -> 3929 bytes
data/tiling.png | Bin 0 -> 5620 bytes
14 files changed, 26 insertions(+), 2 deletions(-)
create mode 100644 data/background.png
create mode 100644 data/fullscreen.png
create mode 100644 data/home.png
create mode 100644 data/icon_ivi_clickdot.png
create mode 100644 data/icon_ivi_flower.png
create mode 100644 data/icon_ivi_simple-egl.png
create mode 100644 data/icon_ivi_simple-shm.png
create mode 100644 data/icon_ivi_smoke.png
create mode 100644 data/panel.png
create mode 100644 data/random.png
create mode 100644 data/sidebyside.png
create mode 100644 data/tiling.png

diff --git a/Makefile.am b/Makefile.am
index 64bdf6d..4c28200 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -644,7 +644,19 @@ dist_westondata_DATA = \
data/icon_window.png \
data/sign_close.png \
data/sign_maximize.png \
- data/sign_minimize.png
+ data/sign_minimize.png \
+ data/background.png \
+ data/tiling.png \
+ data/fullscreen.png \
+ data/panel.png \
+ data/random.png \
+ data/sidebyside.png \
+ data/home.png \
+ data/icon_ivi_clickdot.png \
+ data/icon_ivi_flower.png \
+ data/icon_ivi_simple-egl.png \
+ data/icon_ivi_simple-shm.png \
+ data/icon_ivi_smoke.png


if BUILD_WCAP_TOOLS
diff --git a/data/Makefile.am b/data/Makefile.am
index a7cc944..2aa6e5c 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -9,7 +9,19 @@ dist_westondata_DATA = \
icon_window.png \
sign_close.png \
sign_maximize.png \
- sign_minimize.png
+ sign_minimize.png \
+ background.png \
+ tiling.png \
+ fullscreen.png \
+ panel.png \
+ random.png \
+ sidebyside.png \
+ home.png \
+ icon_ivi_clickdot.png \
+ icon_ivi_flower.png \
+ icon_ivi_simple-egl.png \
+ icon_ivi_simple-shm.png \
+ icon_ivi_smoke.png

if HAVE_RSVG_CONVERT
wayland_icon_png = wayland.png
--
1.8.3.1
Nobuhiko Tanibata
2014-06-25 12:09:35 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4:
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch

Changes for v6:
- the same as v5

Makefile.am | 13 +++++--
ivi-shell/weston.ini.in | 91 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 101 insertions(+), 3 deletions(-)
create mode 100644 ivi-shell/weston.ini.in

diff --git a/Makefile.am b/Makefile.am
index 4c28200..fe0c115 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,7 +8,7 @@ BUILT_SOURCES =

DISTCHECK_CONFIGURE_FLAGS = --disable-setuid-install

-EXTRA_DIST = weston.ini.in
+EXTRA_DIST = weston.ini.in ivi-shell/weston.ini.in

weston.ini : $(srcdir)/weston.ini.in
$(AM_V_GEN)$(SED) \
@@ -17,7 +17,14 @@ weston.ini : $(srcdir)/weston.ini.in
-e 's|@libexecdir[@]|$(libexecdir)|g' \
$< > $@

-all-local : weston.ini
+ivi-shell/weston.ini : $(srcdir)/ivi-shell/weston.ini.in
+ $(AM_V_GEN)$(SED) \
+ -e 's|@bindir[@]|$(bindir)|g' \
+ -e 's|@abs_top_builddir[@]|$(abs_top_builddir)|g' \
+ -e 's|@libexecdir[@]|$(libexecdir)|g' \
+ $< > $@
+
+all-local : weston.ini ivi-shell/weston.ini

AM_CFLAGS = $(GCC_CFLAGS)

@@ -33,7 +40,7 @@ AM_CPPFLAGS = \
-DLIBEXECDIR='"$(libexecdir)"' \
-DBINDIR='"$(bindir)"'

-CLEANFILES = weston.ini $(BUILT_SOURCES)
+CLEANFILES = weston.ini ivi-shell/weston.ini $(BUILT_SOURCES)

bin_PROGRAMS += weston

diff --git a/ivi-shell/weston.ini.in b/ivi-shell/weston.ini.in
new file mode 100644
index 0000000..3c9fb6a
--- /dev/null
+++ b/ivi-shell/weston.ini.in
@@ -0,0 +1,91 @@
+[core]
+shell=ivi-shell.so
+
+[ivi-shell]
+ivi-module=hmi-controller.so
+ivi-shell-user-interface=@abs_top_builddir@/weston-ivi-shell-user-interface
+
+cursor-theme=default
+cursor-size=32
+
+base-layer-id=1000
+workspace-background-layer-id=2000
+workspace-layer-id=3000
+application-layer-id=4000
+
+background-image=@abs_top_builddir@/data/background.png
+background-id=1001
+panel-image=@abs_top_builddir@/data/panel.png
+panel-id=1002
+tiling-image=@abs_top_builddir@/data/tiling.png
+tiling-id=1003
+sidebyside-image=@abs_top_builddir@/data/sidebyside.png
+sidebyside-id=1004
+fullscreen-image=@abs_top_builddir@/data/fullscreen.png
+fullscreen-id=1005
+random-image=@abs_top_builddir@/data/random.png
+random-id=1006
+home-image=@abs_top_builddir@/data/home.png
+home-id=1007
+workspace-background-color=0x99000000
+workspace-background-id=2001
+
+[ivi-launcher]
+workspace-id=0
+icon-id=4001
+icon=@abs_top_builddir@/data/icon_ivi_flower.png
+path=@abs_top_builddir@/clients/weston-flower
+
+[ivi-launcher]
+workspace-id=0
+icon-id=4002
+icon=@abs_top_builddir@/data/icon_ivi_clickdot.png
+path=@abs_top_builddir@/clients/weston-clickdot
+
+[ivi-launcher]
+workspace-id=1
+icon-id=4003
+icon=@abs_top_builddir@/data/icon_ivi_simple-egl.png
+path=@abs_top_builddir@/clients/weston-simple-egl
+
+[ivi-launcher]
+workspace-id=1
+icon-id=4004
+icon=@abs_top_builddir@/data/icon_ivi_simple-shm.png
+path=@abs_top_builddir@/clients/weston-simple-shm
+
+[ivi-launcher]
+workspace-id=2
+icon-id=4005
+icon=@abs_top_builddir@/data/icon_ivi_smoke.png
+path=@abs_top_builddir@/clients/weston-smoke
+
+[ivi-launcher]
+workspace-id=3
+icon-id=4006
+icon=@abs_top_builddir@/data/icon_ivi_flower.png
+path=@abs_top_builddir@/clients/weston-flower
+
+[ivi-launcher]
+workspace-id=3
+icon-id=4007
+icon=@abs_top_builddir@/data/icon_ivi_clickdot.png
+path=@abs_top_builddir@/clients/weston-clickdot
+
+[ivi-launcher]
+workspace-id=3
+icon-id=4008
+icon=@abs_top_builddir@/data/icon_ivi_simple-egl.png
+path=@abs_top_builddir@/clients/weston-simple-egl
+
+[ivi-launcher]
+workspace-id=3
+icon-id=4009
+icon=@abs_top_builddir@/data/icon_ivi_simple-shm.png
+path=@abs_top_builddir@/clients/weston-simple-shm
+
+[ivi-launcher]
+workspace-id=3
+icon-id=4010
+icon=@abs_top_builddir@/data/icon_ivi_smoke.png
+path=@abs_top_builddir@/clients/weston-smoke
--
1.8.3.1
Nobuhiko Tanibata
2014-06-25 12:10:29 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2, v3 and v4:
- nothing. Version number aligned to the first patch

Changes for v5:
- rebase weston v1.5 branch
- remove Macros to enable ivi-application

Changes for v6:
- the same as v5

Makefile.am | 12 ++++++--
clients/simple-egl.c | 70 +++++++++++++++++++++++++++++++++++--------
clients/simple-shm.c | 34 ++++++++++++++++++++-
clients/window.c | 84 ++++++++++++++++++++++++++++++++++++++--------------
4 files changed, 161 insertions(+), 39 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index fe0c115..e2f1642 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -406,7 +406,9 @@ nodist_weston_simple_shm_SOURCES = \
protocol/xdg-shell-protocol.c \
protocol/xdg-shell-client-protocol.h \
protocol/fullscreen-shell-protocol.c \
- protocol/fullscreen-shell-client-protocol.h
+ protocol/fullscreen-shell-client-protocol.h \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-client-protocol.h
weston_simple_shm_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS)
weston_simple_shm_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la

@@ -424,7 +426,9 @@ demo_clients += weston-simple-egl
weston_simple_egl_SOURCES = clients/simple-egl.c
nodist_weston_simple_egl_SOURCES = \
protocol/xdg-shell-protocol.c \
- protocol/xdg-shell-client-protocol.h
+ protocol/xdg-shell-client-protocol.h \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-client-protocol.h
weston_simple_egl_CFLAGS = $(AM_CFLAGS) $(SIMPLE_EGL_CLIENT_CFLAGS)
weston_simple_egl_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
endif
@@ -443,7 +447,9 @@ nodist_libtoytoolkit_la_SOURCES = \
protocol/workspaces-protocol.c \
protocol/workspaces-client-protocol.h \
protocol/xdg-shell-protocol.c \
- protocol/xdg-shell-client-protocol.h
+ protocol/xdg-shell-client-protocol.h \
+ protocol/ivi-application-protocol.c \
+ protocol/ivi-application-client-protocol.h

BUILT_SOURCES += $(nodist_libtoytoolkit_la_SOURCES)

diff --git a/clients/simple-egl.c b/clients/simple-egl.c
index 0d4673b..92f2dc2 100644
--- a/clients/simple-egl.c
+++ b/clients/simple-egl.c
@@ -41,6 +41,10 @@
#include <EGL/eglext.h>

#include "xdg-shell-client-protocol.h"
+#include <sys/types.h>
+#include <unistd.h>
+#include "protocol/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000

#ifndef EGL_EXT_swap_buffers_with_damage
#define EGL_EXT_swap_buffers_with_damage 1
@@ -74,6 +78,7 @@ struct display {
EGLConfig conf;
} egl;
struct window *window;
+ struct ivi_application *ivi_application;

PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
};
@@ -95,6 +100,7 @@ struct window {
struct wl_egl_window *native;
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
+ struct ivi_surface *ivi_surface;
EGLSurface egl_surface;
struct wl_callback *callback;
int fullscreen, opaque, buffer_size, frame_sync;
@@ -254,7 +260,7 @@ init_gl(struct window *window)
}

glUseProgram(program);
-
+
window->gl.pos = 0;
window->gl.col = 1;

@@ -333,13 +339,8 @@ create_surface(struct window *window)
{
struct display *display = window->display;
EGLBoolean ret;
-
- window->surface = wl_compositor_create_surface(display->compositor);
- window->xdg_surface = xdg_shell_get_xdg_surface(display->shell,
- window->surface);

- xdg_surface_add_listener(window->xdg_surface,
- &xdg_surface_listener, window);
+ window->surface = wl_compositor_create_surface(display->compositor);

window->native =
wl_egl_window_create(window->surface,
@@ -350,7 +351,28 @@ create_surface(struct window *window)
display->egl.conf,
window->native, NULL);

- xdg_surface_set_title(window->xdg_surface, "simple-egl");
+ if (display->shell) {
+ window->xdg_surface = xdg_shell_get_xdg_surface(display->shell,
+ window->surface);
+
+ xdg_surface_add_listener(window->xdg_surface,
+ &xdg_surface_listener, window);
+
+ xdg_surface_set_title(window->xdg_surface, "simple-egl");
+ } else if (display->ivi_application ) {
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ window->ivi_surface =
+ ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ handle_surface_configure(window, NULL, 250, 250);
+
+ if (window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+ } else {
+ assert(0);
+ }

ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
window->egl_surface, window->display->egl.ctx);
@@ -359,9 +381,12 @@ create_surface(struct window *window)
if (!window->frame_sync)
eglSwapInterval(display->egl.dpy, 0);

- xdg_surface_request_change_state(window->xdg_surface,
- XDG_SURFACE_STATE_FULLSCREEN,
- window->fullscreen, 0);
+ if (display->shell)
+ {
+ xdg_surface_request_change_state(window->xdg_surface,
+ XDG_SURFACE_STATE_FULLSCREEN,
+ window->fullscreen, 0);
+ }
}

static void
@@ -536,8 +561,13 @@ pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
struct display *display = data;

if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
- xdg_surface_move(display->window->xdg_surface,
- display->seat, serial);
+ {
+ if (display->shell)
+ {
+ xdg_surface_move(display->window->xdg_surface,
+ display->seat, serial);
+ }
+ }
}

static void
@@ -730,6 +760,11 @@ registry_handle_global(void *data, struct wl_registry *registry,
// TODO: abort ?
}
}
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application =
+ wl_registry_bind(registry, name,
+ &ivi_application_interface, 1);
+ }
}

static void
@@ -824,6 +859,12 @@ main(int argc, char **argv)

fprintf(stderr, "simple-egl exiting\n");

+ if (window.display->ivi_application)
+ {
+ ivi_surface_destroy(window.ivi_surface);
+ ivi_application_destroy(window.display->ivi_application);
+ }
+
destroy_surface(&window);
fini_egl(&display);

@@ -838,6 +879,9 @@ main(int argc, char **argv)
wl_compositor_destroy(display.compositor);

wl_registry_destroy(display.registry);
+ if (window.display->ivi_application)
+ wl_display_roundtrip(display.display);
+
wl_display_flush(display.display);
wl_display_disconnect(display.display);

diff --git a/clients/simple-shm.c b/clients/simple-shm.c
index 2087a0e..c54b5d7 100644
--- a/clients/simple-shm.c
+++ b/clients/simple-shm.c
@@ -37,6 +37,10 @@
#include "xdg-shell-client-protocol.h"
#include "fullscreen-shell-client-protocol.h"

+#include <sys/types.h>
+#include "ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+
struct display {
struct wl_display *display;
struct wl_registry *registry;
@@ -45,6 +49,7 @@ struct display {
struct _wl_fullscreen_shell *fshell;
struct wl_shm *shm;
uint32_t formats;
+ struct ivi_application *ivi_application;
};

struct buffer {
@@ -58,6 +63,7 @@ struct window {
int width, height;
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
+ struct ivi_surface *ivi_surface;
struct buffer buffers[2];
struct buffer *prev_buffer;
struct wl_callback *callback;
@@ -179,11 +185,21 @@ create_window(struct display *display, int width, int height)
&xdg_surface_listener, window);

xdg_surface_set_title(window->xdg_surface, "simple-shm");
+
} else if (display->fshell) {
_wl_fullscreen_shell_present_surface(display->fshell,
window->surface,
_WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT,
NULL);
+ } else if (display->ivi_application ) {
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ window->ivi_surface =
+ ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ if (window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
} else {
assert(0);
}
@@ -369,6 +385,11 @@ registry_handle_global(void *data, struct wl_registry *registry,
id, &wl_shm_interface, 1);
wl_shm_add_listener(d->shm, &shm_listener, d);
}
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application =
+ wl_registry_bind(registry, id,
+ &ivi_application_interface, 1);
+ }
}

static void
@@ -413,7 +434,7 @@ create_display(void)
}

wl_display_get_fd(display->display);
-
+
return display;
}

@@ -433,6 +454,10 @@ destroy_display(struct display *display)
wl_compositor_destroy(display->compositor);

wl_registry_destroy(display->registry);
+
+ if (display->ivi_application)
+ wl_display_roundtrip(display->display);
+
wl_display_flush(display->display);
wl_display_disconnect(display->display);
free(display);
@@ -472,6 +497,13 @@ main(int argc, char **argv)
ret = wl_display_dispatch(display->display);

fprintf(stderr, "simple-shm exiting\n");
+
+ if (window->display->ivi_application)
+ {
+ ivi_surface_destroy(window->ivi_surface);
+ ivi_application_destroy(window->display->ivi_application);
+ }
+
destroy_window(window);
destroy_display(display);

diff --git a/clients/window.c b/clients/window.c
index 4592ef9..47434dc 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -72,6 +72,10 @@ typedef void *EGLContext;

#include "window.h"

+#include <sys/types.h>
+#include "ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+
struct shm_pool;

struct global {
@@ -133,6 +137,7 @@ struct display {

int has_rgb565;
int seat_version;
+ struct ivi_application *ivi_application;
};

struct window_output {
@@ -245,6 +250,7 @@ struct window {
struct xdg_popup *xdg_popup;

struct window *transient_for;
+ struct ivi_surface *ivi_surface;

struct window_frame *frame;

@@ -1373,6 +1379,20 @@ surface_create_surface(struct surface *surface, uint32_t flags)
struct display *display = surface->window->display;
struct rectangle allocation = surface->allocation;

+ if (display->ivi_application)
+ {
+ if (!surface->toysurface) {
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ surface->window->ivi_surface =
+ ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, surface->surface);
+ if (surface->window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+ }
+ }
+
if (!surface->toysurface && display->dpy &&
surface->buffer_type == WINDOW_BUFFER_TYPE_EGL_WINDOW) {
surface->toysurface =
@@ -1476,6 +1496,12 @@ surface_destroy(struct surface *surface)
if (surface->toysurface)
surface->toysurface->destroy(surface->toysurface);

+ if (surface->window->display->ivi_application)
+ {
+ ivi_surface_destroy(surface->window->ivi_surface);
+ ivi_application_destroy(surface->window->display->ivi_application);
+ }
+
wl_list_remove(&surface->link);
free(surface);
}
@@ -1490,7 +1516,7 @@ window_destroy(struct window *window)

wl_list_remove(&window->redraw_task.link);

- wl_list_for_each(input, &display->input_list, link) {
+ wl_list_for_each(input, &display->input_list, link) {
if (input->touch_focus == window)
input->touch_focus = NULL;
if (input->pointer_focus == window)
@@ -3006,7 +3032,7 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
wl_list_insert(&input->touch_point_list, &tp->link);

if (widget->touch_down_handler)
- (*widget->touch_down_handler)(widget, input,
+ (*widget->touch_down_handler)(widget, input,
serial, time, id,
sx, sy,
widget->user_data);
@@ -4386,7 +4412,7 @@ window_create_internal(struct display *display, int custom)
surface = surface_create(window);
window->main_surface = surface;

- assert(custom || display->xdg_shell);
+ assert(custom || display->xdg_shell || display->ivi_application);

window->custom = custom;
window->preferred_format = WINDOW_PREFERRED_FORMAT_NONE;
@@ -4409,14 +4435,17 @@ window_create(struct display *display)

window = window_create_internal(display, 0);

- window->xdg_surface =
- xdg_shell_get_xdg_surface(window->display->xdg_shell,
- window->main_surface->surface);
- fail_on_null(window->xdg_surface);
+ if (window->display->xdg_shell)
+ {
+ window->xdg_surface =
+ xdg_shell_get_xdg_surface(window->display->xdg_shell,
+ window->main_surface->surface);
+ fail_on_null(window->xdg_surface);

- xdg_surface_set_user_data(window->xdg_surface, window);
- xdg_surface_add_listener(window->xdg_surface,
- &xdg_surface_listener, window);
+ xdg_surface_set_user_data(window->xdg_surface, window);
+ xdg_surface_add_listener(window->xdg_surface,
+ &xdg_surface_listener, window);
+ }

return window;
}
@@ -4634,19 +4663,22 @@ window_show_menu(struct display *display,

frame_interior(menu->frame, &ix, &iy, NULL, NULL);

- window->xdg_popup = xdg_shell_get_xdg_popup(display->xdg_shell,
- window->main_surface->surface,
- parent->main_surface->surface,
- input->seat,
- display_get_serial(window->display),
- window->x - ix,
- window->y - iy,
- 0);
- fail_on_null(window->xdg_popup);
+ if (display->xdg_shell)
+ {
+ window->xdg_popup = xdg_shell_get_xdg_popup(display->xdg_shell,
+ window->main_surface->surface,
+ parent->main_surface->surface,
+ input->seat,
+ display_get_serial(window->display),
+ window->x - ix,
+ window->y - iy,
+ 0);
+ fail_on_null(window->xdg_popup);

- xdg_popup_set_user_data(window->xdg_popup, window);
- xdg_popup_add_listener(window->xdg_popup,
- &xdg_popup_listener, window);
+ xdg_popup_set_user_data(window->xdg_popup, window);
+ xdg_popup_add_listener(window->xdg_popup,
+ &xdg_popup_listener, window);
+ }
}

void
@@ -5091,6 +5123,11 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
wl_registry_bind(registry, id,
&wl_subcompositor_interface, 1);
}
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application =
+ wl_registry_bind(registry, id,
+ &ivi_application_interface, 1);
+ }

if (d->global_handler)
d->global_handler(d, id, interface, version, d->user_data);
@@ -5400,6 +5437,9 @@ display_destroy(struct display *display)

close(display->epoll_fd);

+ if (display->ivi_application)
+ wl_display_roundtrip(display->display);
+
if (!(display->display_fd_events & EPOLLERR) &&
!(display->display_fd_events & EPOLLHUP))
wl_display_flush(display->display);
--
1.8.3.1
Nobuhiko Tanibata
2014-04-28 05:47:26 UTC
Permalink
2014-04-23 19:40 ? Pekka Paalanen ????????:
> Hi,
>
> it's been a long while since I have looked at this, but I got a bit of
> time to come back. I hope you haven't abandoned this effort yet. :-)
>
> I looked at the PDF from your post on March 6th, 2014, and some of my
> own comments I gave at that time to recall what this was about, but I
> probably still forgot something.
>
> New comments below. I started by reading the global interface, and
> moved on to ivi_surface after it, so the comments might seem
> temporally strange if you read just top-down.
>
>
> On Mon, 17 Mar 2014 15:23:22 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> Add interface ivi_application, which creates ivi_surface objects tied
>> to a given wl_surface with a given id. The given id can be used in a
>> shell to identify which application is assigned to a wl_surface and
>> layout the surface wherever the shell wants. ivi_surface objects can
>> be used to receive status of wl_surface in the scenegraph of the
>> compositor.
>>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2:
>> - Rename "error" to "warning" because meaning of "error" in wayland
>> is fatal.
>>
>> Changes for v3:
>> - Move "warning" from ivi_application to ivi_surface.
>> - Squash Makefile.
>> - Add description to ivi_surface:destroy.
>> - Update description of ivi_application:surface_create.
>>
>> Changes for v4:
>> - Remove detail description of server side from
>> ivi_surface::destroy
>> - Add clear discripton what client shall do if it encounters
>> warning in ivi_surface
>> ::warning.
>> - Add decription what happens when client tries to tie a wl_surface
>> to multiple
>> ivi_surfaces.
>>
>> protocol/Makefile.am | 3 +-
>> protocol/ivi-application.xml | 99
>> ++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 101 insertions(+), 1 deletion(-)
>> create mode 100644 protocol/ivi-application.xml
>>
>> diff --git a/protocol/Makefile.am b/protocol/Makefile.am
>> index 5e331a7..9913f16 100644
>> --- a/protocol/Makefile.am
>> +++ b/protocol/Makefile.am
>> @@ -8,7 +8,8 @@ protocol_sources = \
>> text-cursor-position.xml \
>> wayland-test.xml \
>> xdg-shell.xml \
>> - scaler.xml
>> + scaler.xml \
>> + ivi-application.xml
>>
>> if HAVE_XMLLINT
>> .PHONY: validate
>> diff --git a/protocol/ivi-application.xml
>> b/protocol/ivi-application.xml
>> new file mode 100644
>> index 0000000..37ad489
>> --- /dev/null
>> +++ b/protocol/ivi-application.xml
>> @@ -0,0 +1,99 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<protocol name="ivi_application">
>> +
>> + <copyright>
>> + Copyright (C) 2013 DENSO CORPORATION
>> + Copyright (c) 2013 BMW Car IT GmbH
>> +
>> + Permission is hereby granted, free of charge, to any person
>> obtaining a copy
>> + of this software and associated documentation files (the
>> "Software"), to deal
>> + in the Software without restriction, including without limitation
>> the rights
>> + to use, copy, modify, merge, publish, distribute, sublicense,
>> and/or sell
>> + copies of the Software, and to permit persons to whom the
>> Software is
>> + furnished to do so, subject to the following conditions:
>> +
>> + The above copyright notice and this permission notice shall be
>> included in
>> + all copies or substantial portions of the Software.
>> +
>> + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS OR
>> + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> MERCHANTABILITY,
>> + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
>> SHALL THE
>> + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> OTHER
>> + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> ARISING FROM,
>> + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> DEALINGS IN
>> + THE SOFTWARE.
>> + </copyright>
>> +
>> + <interface name="ivi_surface" version="1">
>> + <description summary="application interface to surface in ivi
>> compositor"/>
>> +
>> + <request name="destroy" type="destructor">
>> + <description summary="destroy ivi_surface">
>> + This removes link from surface_id to wl_surface and
>> destroys ivi_surface.
>> + </description>
>> + </request>
>> +
>> + <event name="visibility">
>> + <description summary="visibility of surface in ivi
>> compositor has changed">
>> + The new visibility state is provided in argument
>> visibility.
>> + If visibility is 0, the surface has become invisible.
>> + If visibility is not 0, the surface has become
>> visible.
>> + </description>
>> + <arg name="visibility" type="int"/>
>> + </event>
>> +
>> + <enum name="warning_code">
>> + <description summary="possible warning codes returned by
>> ivi compositor">
>> + These warning codes define all possible warning codes
>> returned by ivi compositor
>
> Codes define codes? :-)

Thanks. I fix it.

>
>> + on server-side warnings.
>> + invalid_wl_surface: invalid wl_surface is set. This
>> happens if wl_surface is destroyed before this.
>
> Ooh, does this mean that invalid_wl_surface is emitted if wl_surface is
> destroyed before the ivi_surface? Try to use more nouns and less
> pronouns in specification language to keep things explicit.
>
> I was about ask what happens if the wl_surface gets destroyed first.

I agree.

>
>> + surface_id_in_use: surface_id is already assigned by
>> another application.
>> + </description>
>> + <entry name="invalid_wl_surface" value="1"
>> summary="wl_surface is invalid"/>
>> + <entry name="surface_id_in_use" value="2"
>> summary="surface_id is in use and can not be shared"/>
>> + </enum>
>> +
>> + <event name="warning">
>> + <description summary="server-side warning detected">
>> + The ivi compositor encountered warning while
>> processing a request by this
>> + application. The warning is defined by argument
>> warning_code and optional
>> + warning_text. If the warning is detected, client
>> shall destroy the ivi_surface
>> + object.
>> +
>> + When ivi compositor encounters warnings, a request is
>> canceled and there is no
>> + mapping from id_surface/wl_surface to this
>> ivi_surface. Even if there is no
>> + mapping but destroying this ivi_surface is
>> recommended.
>
> I would propose a slightly different wording here, which may or may not
> be what you intended above.
>
> "When a warning event is sent, the compositor turns the ivi_surface
> object inert. The ivi_surface will not deliver further events, all
> requests on it are ignored except 'destroy', and the association to the
> surface_id is removed. The client should destroy the ivi_surface
> object. If an inert ivi_surface object is used as an argument to any
> other object's request, that request will [produce a fatal error /
> produce a warning / be ignored]."
>
> There are no requests other than 'destroy' on ivi_surface, but it is
> better to be explicit just in case later someone adds a new request. On
> the final part, you can pick what suits best, or say that the effect is
> undefined.

I agree.

>
>> + </description>
>> + <arg name="warning_code" type="int"/>
>> + <arg name="warning_text" type="string"
>> allow-null="true"/>
>> + </event>
>> +
>> + </interface>
>> +
>> + <interface name="ivi_application" version="1">
>> + <description summary="interface for ivi applications to use
>> ivi compositor features"/>
>
> Could mention that this is a global interface, isn't it?

Yes. I will fix it.
>
>> + <request name="surface_create">
>> + <description summary="create ivi_surface with numeric ID
>> in ivi compositor">
>> + surface_create will create a interface:ivi_surface
>> with numeric ID; surface_id in
>> + ivi compositor. These surface_ids are defined as
>> unique in the system to identify
>> + it inside of ivi compositor. The ivi compositor
>> implements business logic how to
>> + set properties of the surface with surface_id
>> according to status of the system.
>> + E.g. a unique ID for Car Navigation application is
>> used for implementing special
>> + logic of the application about where it shall be
>> located.
>> +
>> + Created ivi_surface notifies warnings when following
>> situation happens,
>> + - Invalid wl_surface is set. This happen if
>> wl_surface is destroy before this.
>
> How is it possible to destroy the wl_surface before issuing a
> ivi_application.surface_create request? IOW, I cannot understand when a
> wl_surface could be invalid due to "destroy". But it could be if the
> wl_surface already has a role.
>
>> + - surface_id is already assigned by another
>> application.
>> + If a client sets a wl_surface to multiple
>> id_surfaces, no warning is issued. Property
>> + of the surface can be controlled by multiple
>> ivi_surface. However this case shall
>> + be avoided by a client.
>
> By id_surface, do you mean creating multiple ivi_surface objects with
> the same or different surface_id for a single wl_surface? Would it ever
> make any sense to do that?
>
> Is it legal or illegal to do that? If it is illegal, there should be a
> fatal protocol error. I know you prefer non-fatal warnings, but even
> Wayland core has fatal errors like for invalid object id. I would think
> that creating several ivi_surfaces for the same wl_surface would be a
> similar problem as use-after-free producing an invalid object id, if it
> really is illegal.
>
> Also, if ivi_application.surface_create assigns a role to a wl_surface,
> then you cannot have several ivi_surfaces referencing the same
> wl_surface.
>
> In Weston, a role is identified by weston_surface::configure function
> pointer. More conceptually, a role defines how the surface behaves on
> screen: cursor surface moves with the pointer, ivi_surface is
> controlled by your... ivi-controller or something. In principle,
> without a role, a surface cannot be shown at all because the compositor
> does not know how or when to show it.

I agree. I will take care of it as fatal.

>
>> + </description>
>> + <arg name="id_surface" type="uint"/>
>
> id_surface here, surface_id in the doc; maybe pick one form, and use
> that everywhere?
>
> I wonder, could we use a more specific term for the ID? Would "ivi_id"
> be unambiguous? So we could talk about surface's ivi_id, as opposed to
> surface_id which is not obviously an IVI concept. Every Wayland
> protocol
> object has an id, and I would like avoid any chances of confusing
> wl_surface id with ivi_id.

I agree.

>
>> + <arg name="surface" type="object"
>> interface="wl_surface"/>
>> + <arg name="id" type="new_id" interface="ivi_surface"/>
>> + </request>
>> +
>> + </interface>
>> +
>> +</protocol>
>
> This is looking good, mostly just some details in the wording to be
> tuned. :-)

Thank you for reviewing. I will take care of it as your suggestion.

BR,
Nobuhiko

>
> I will see if I can review more of the patches, but I would also
> suggest the following, in case you are still interested in pushing this
> upstream.
>
> Wait for Weston 1.5 to be released. We are currently in freeze, so
> there is no point in re-sending until that is done. Check that the 1.5
> stable branch has been created, or at least the release has been made,
> before you rebase and re-send this series.
>
>
> Thanks,
> pq
Nobuhiko Tanibata
2014-05-20 04:40:03 UTC
Permalink
2014-04-23 19:40 ? Pekka Paalanen ????????:
> Hi,
>
> it's been a long while since I have looked at this, but I got a bit of
> time to come back. I hope you haven't abandoned this effort yet. :-)
>
> I looked at the PDF from your post on March 6th, 2014, and some of my
> own comments I gave at that time to recall what this was about, but I
> probably still forgot something.
>
> New comments below. I started by reading the global interface, and
> moved on to ivi_surface after it, so the comments might seem
> temporally strange if you read just top-down.
>
>
> On Mon, 17 Mar 2014 15:23:22 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> Add interface ivi_application, which creates ivi_surface objects tied
>> to a given wl_surface with a given id. The given id can be used in a
>> shell to identify which application is assigned to a wl_surface and
>> layout the surface wherever the shell wants. ivi_surface objects can
>> be used to receive status of wl_surface in the scenegraph of the
>> compositor.
>>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2:
>> - Rename "error" to "warning" because meaning of "error" in wayland
>> is fatal.
>>
>> Changes for v3:
>> - Move "warning" from ivi_application to ivi_surface.
>> - Squash Makefile.
>> - Add description to ivi_surface:destroy.
>> - Update description of ivi_application:surface_create.
>>
>> Changes for v4:
>> - Remove detail description of server side from
>> ivi_surface::destroy
>> - Add clear discripton what client shall do if it encounters
>> warning in ivi_surface
>> ::warning.
>> - Add decription what happens when client tries to tie a wl_surface
>> to multiple
>> ivi_surfaces.
>>
>> protocol/Makefile.am | 3 +-
>> protocol/ivi-application.xml | 99
>> ++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 101 insertions(+), 1 deletion(-)
>> create mode 100644 protocol/ivi-application.xml
>>
>> diff --git a/protocol/Makefile.am b/protocol/Makefile.am
>> index 5e331a7..9913f16 100644
>> --- a/protocol/Makefile.am
>> +++ b/protocol/Makefile.am
>> @@ -8,7 +8,8 @@ protocol_sources = \
>> text-cursor-position.xml \
>> wayland-test.xml \
>> xdg-shell.xml \
>> - scaler.xml
>> + scaler.xml \
>> + ivi-application.xml
>>
>> if HAVE_XMLLINT
>> .PHONY: validate
>> diff --git a/protocol/ivi-application.xml
>> b/protocol/ivi-application.xml
>> new file mode 100644
>> index 0000000..37ad489
>> --- /dev/null
>> +++ b/protocol/ivi-application.xml
>> @@ -0,0 +1,99 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<protocol name="ivi_application">
>> +
>> + <copyright>
>> + Copyright (C) 2013 DENSO CORPORATION
>> + Copyright (c) 2013 BMW Car IT GmbH
>> +
>> + Permission is hereby granted, free of charge, to any person
>> obtaining a copy
>> + of this software and associated documentation files (the
>> "Software"), to deal
>> + in the Software without restriction, including without limitation
>> the rights
>> + to use, copy, modify, merge, publish, distribute, sublicense,
>> and/or sell
>> + copies of the Software, and to permit persons to whom the
>> Software is
>> + furnished to do so, subject to the following conditions:
>> +
>> + The above copyright notice and this permission notice shall be
>> included in
>> + all copies or substantial portions of the Software.
>> +
>> + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS OR
>> + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> MERCHANTABILITY,
>> + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
>> SHALL THE
>> + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> OTHER
>> + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> ARISING FROM,
>> + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> DEALINGS IN
>> + THE SOFTWARE.
>> + </copyright>
>> +
>> + <interface name="ivi_surface" version="1">
>> + <description summary="application interface to surface in ivi
>> compositor"/>
>> +
>> + <request name="destroy" type="destructor">
>> + <description summary="destroy ivi_surface">
>> + This removes link from surface_id to wl_surface and
>> destroys ivi_surface.
>> + </description>
>> + </request>
>> +
>> + <event name="visibility">
>> + <description summary="visibility of surface in ivi
>> compositor has changed">
>> + The new visibility state is provided in argument
>> visibility.
>> + If visibility is 0, the surface has become invisible.
>> + If visibility is not 0, the surface has become
>> visible.
>> + </description>
>> + <arg name="visibility" type="int"/>
>> + </event>
>> +
>> + <enum name="warning_code">
>> + <description summary="possible warning codes returned by
>> ivi compositor">
>> + These warning codes define all possible warning codes
>> returned by ivi compositor
>
> Codes define codes? :-)
>
>> + on server-side warnings.
>> + invalid_wl_surface: invalid wl_surface is set. This
>> happens if wl_surface is destroyed before this.
>
> Ooh, does this mean that invalid_wl_surface is emitted if wl_surface is
> destroyed before the ivi_surface? Try to use more nouns and less
> pronouns in specification language to keep things explicit.
>
> I was about ask what happens if the wl_surface gets destroyed first.
>
>> + surface_id_in_use: surface_id is already assigned by
>> another application.
>> + </description>
>> + <entry name="invalid_wl_surface" value="1"
>> summary="wl_surface is invalid"/>
>> + <entry name="surface_id_in_use" value="2"
>> summary="surface_id is in use and can not be shared"/>
>> + </enum>
>> +
>> + <event name="warning">
>> + <description summary="server-side warning detected">
>> + The ivi compositor encountered warning while
>> processing a request by this
>> + application. The warning is defined by argument
>> warning_code and optional
>> + warning_text. If the warning is detected, client
>> shall destroy the ivi_surface
>> + object.
>> +
>> + When ivi compositor encounters warnings, a request is
>> canceled and there is no
>> + mapping from id_surface/wl_surface to this
>> ivi_surface. Even if there is no
>> + mapping but destroying this ivi_surface is
>> recommended.
>
> I would propose a slightly different wording here, which may or may not
> be what you intended above.
>
> "When a warning event is sent, the compositor turns the ivi_surface
> object inert. The ivi_surface will not deliver further events, all
> requests on it are ignored except 'destroy', and the association to the
> surface_id is removed. The client should destroy the ivi_surface
> object. If an inert ivi_surface object is used as an argument to any
> other object's request, that request will [produce a fatal error /
> produce a warning / be ignored]."
>
> There are no requests other than 'destroy' on ivi_surface, but it is
> better to be explicit just in case later someone adds a new request. On
> the final part, you can pick what suits best, or say that the effect is
> undefined.
>
>> + </description>
>> + <arg name="warning_code" type="int"/>
>> + <arg name="warning_text" type="string"
>> allow-null="true"/>
>> + </event>
>> +
>> + </interface>
>> +
>> + <interface name="ivi_application" version="1">
>> + <description summary="interface for ivi applications to use
>> ivi compositor features"/>
>
> Could mention that this is a global interface, isn't it?
>
>> + <request name="surface_create">
>> + <description summary="create ivi_surface with numeric ID
>> in ivi compositor">
>> + surface_create will create a interface:ivi_surface
>> with numeric ID; surface_id in
>> + ivi compositor. These surface_ids are defined as
>> unique in the system to identify
>> + it inside of ivi compositor. The ivi compositor
>> implements business logic how to
>> + set properties of the surface with surface_id
>> according to status of the system.
>> + E.g. a unique ID for Car Navigation application is
>> used for implementing special
>> + logic of the application about where it shall be
>> located.
>> +
>> + Created ivi_surface notifies warnings when following
>> situation happens,
>> + - Invalid wl_surface is set. This happen if
>> wl_surface is destroy before this.
>
> How is it possible to destroy the wl_surface before issuing a
> ivi_application.surface_create request? IOW, I cannot understand when a
> wl_surface could be invalid due to "destroy". But it could be if the
> wl_surface already has a role.
>
>> + - surface_id is already assigned by another
>> application.
>> + If a client sets a wl_surface to multiple
>> id_surfaces, no warning is issued. Property
>> + of the surface can be controlled by multiple
>> ivi_surface. However this case shall
>> + be avoided by a client.
>
> By id_surface, do you mean creating multiple ivi_surface objects with
> the same or different surface_id for a single wl_surface? Would it ever
> make any sense to do that?
>
> Is it legal or illegal to do that? If it is illegal, there should be a
> fatal protocol error. I know you prefer non-fatal warnings, but even
> Wayland core has fatal errors like for invalid object id. I would think
> that creating several ivi_surfaces for the same wl_surface would be a
> similar problem as use-after-free producing an invalid object id, if it
> really is illegal.
>
> Also, if ivi_application.surface_create assigns a role to a wl_surface,
> then you cannot have several ivi_surfaces referencing the same
> wl_surface.
>
> In Weston, a role is identified by weston_surface::configure function
> pointer. More conceptually, a role defines how the surface behaves on
> screen: cursor surface moves with the pointer, ivi_surface is
> controlled by your... ivi-controller or something. In principle,
> without a role, a surface cannot be shown at all because the compositor
> does not know how or when to show it.
>

Hi pq,

I update my patch to regard this as fatal in the shell if it already has
an another role. If it happens, client will be disconnected.

BR,
Nobuhiko

>> + </description>
>> + <arg name="id_surface" type="uint"/>
>
> id_surface here, surface_id in the doc; maybe pick one form, and use
> that everywhere?
>
> I wonder, could we use a more specific term for the ID? Would "ivi_id"
> be unambiguous? So we could talk about surface's ivi_id, as opposed to
> surface_id which is not obviously an IVI concept. Every Wayland
> protocol
> object has an id, and I would like avoid any chances of confusing
> wl_surface id with ivi_id.
>
>> + <arg name="surface" type="object"
>> interface="wl_surface"/>
>> + <arg name="id" type="new_id" interface="ivi_surface"/>
>> + </request>
>> +
>> + </interface>
>> +
>> +</protocol>
>
> This is looking good, mostly just some details in the wording to be
> tuned. :-)
>
> I will see if I can review more of the patches, but I would also
> suggest the following, in case you are still interested in pushing this
> upstream.
>
> Wait for Weston 1.5 to be released. We are currently in freeze, so
> there is no point in re-sending until that is done. Check that the 1.5
> stable branch has been created, or at least the release has been made,
> before you rebase and re-send this series.
>
>
> Thanks,
> pq
Nobuhiko Tanibata
2014-03-17 06:25:38 UTC
Permalink
API set of controlling properties of surface and layer which groups
surfaces. An unique ID whose type is integer is required to create
surface and layer. With the unique ID, surface and layer are identified
to control them. The API set consists of APIs to control properties of
surface and layers about followings,

- visibility.
- opacity.
- clipping (x,y,width,height).
- position and size of it to be displayed.
- orientation per 90 degree.
- add or remove surfaces to a layer.
- order of surfaces/layers in layer/screen to be displayed.
- commit to apply property changes.
- notifications of property change.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- move this patch in front of ivi-shell patch to be compiled successfully.
- unsupport weston_layout_takeSurfaceScreenshot because implementation needs to
be discussed more. It is pending.
- support inherit propoerties of id_surface when client attaches another
wl_surface with id_surface after destroying ivi_surface once.
- bug fix of https://bugs.tizen.org/jira/browse/TIVI-2882

Changes for v3 and v4
- nothing. Version number aligned to the first patch

Makefile.am | 1 +
configure.ac | 15 +-
ivi-shell/Makefile.am | 30 +
ivi-shell/weston-layout.c | 2631 +++++++++++++++++++++++++++++++++++++++++++++
ivi-shell/weston-layout.h | 934 ++++++++++++++++
5 files changed, 3610 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/Makefile.am
create mode 100644 ivi-shell/weston-layout.c
create mode 100644 ivi-shell/weston-layout.h

diff --git a/Makefile.am b/Makefile.am
index f22c542..1bc35e2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,6 +11,7 @@ SUBDIRS = \
src \
$(xwayland_subdir) \
desktop-shell \
+ ivi-shell \
clients \
data \
protocol \
diff --git a/configure.ac b/configure.ac
index cce1850..4c0a90f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -409,6 +409,16 @@ if test "x$enable_dbus" != "xno"; then
fi
AM_CONDITIONAL(ENABLE_DBUS, test "x$enable_dbus" = "xyes")

+# ivi-shell support
+AC_ARG_ENABLE(ivi-shell,
+ AS_HELP_STRING([--disable-ivi-shell],
+ [do not build ivi-shell server plugin and client]),,
+ enable_ivi_shell=yes)
+AM_CONDITIONAL(ENABLE_IVI_SHELL, test "x$enable_ivi_shell" = "xyes")
+if test x$enable_ivi_shell = xyes; then
+ PKG_CHECK_MODULES(IVI_SHELL, [cairo])
+fi
+
AC_ARG_ENABLE(wcap-tools, [ --disable-wcap-tools],, enable_wcap_tools=yes)
AM_CONDITIONAL(BUILD_WCAP_TOOLS, test x$enable_wcap_tools = xyes)
if test x$enable_wcap_tools = xyes; then
@@ -505,7 +515,8 @@ AC_CONFIG_FILES([Makefile
data/Makefile
protocol/Makefile
man/Makefile
- tests/Makefile])
+ tests/Makefile
+ ivi-shell/Makefile])
AC_OUTPUT

AC_MSG_RESULT([
@@ -519,6 +530,8 @@ AC_MSG_RESULT([
XWayland ${enable_xwayland}
dbus ${enable_dbus}

+ ivi-shell ${enable_ivi_shell}
+
Build wcap utility ${enable_wcap_tools}

weston-launch utility ${enable_weston_launch}
diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
new file mode 100644
index 0000000..4d54c2d
--- /dev/null
+++ b/ivi-shell/Makefile.am
@@ -0,0 +1,30 @@
+moduledir = $(libdir)/weston
+
+module_LTLIBRARIES = \
+ $(libweston_layout)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/shared \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src \
+ -DDATADIR='"$(datadir)"' \
+ -DMODULEDIR='"$(moduledir)"' \
+ -DLIBEXECDIR='"$(libexecdir)"' \
+ -DIN_WESTON
+
+westonincludedir = $(includedir)/weston
+westoninclude_HEADERS =
+
+if ENABLE_IVI_SHELL
+westoninclude_HEADERS += \
+ weston-layout.h
+
+libweston_layout = libweston-layout.la
+libweston_layout_la_LDFLAGS = -avoid-version
+libweston_layout_la_LIBADD = $(IVI_SHELL_LIBS) ../shared/libshared.la
+libweston_layout_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
+libweston_layout_la_SOURCES = \
+ weston-layout.c \
+ weston-layout.h
+
+endif
diff --git a/ivi-shell/weston-layout.c b/ivi-shell/weston-layout.c
new file mode 100644
index 0000000..9cb571a
--- /dev/null
+++ b/ivi-shell/weston-layout.c
@@ -0,0 +1,2631 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * Implementation of weston-layout library. The actual view on screen is
+ * not updated till calling weston_layout_commitChanges. A overview from
+ * calling API for updating properties of surfaces/layer to asking compositor
+ * to compose them by using weston_compositor_schedule_repaint,
+ * 0/ initialize this library by weston_layout_initWithCompositor
+ * with (struct weston_compositor *ec) from ivi-shell.
+ * 1/ When a API for updating properties of surface/layer, it updates
+ * pending prop of weston_layout_surface/layer/screen which are structure to
+ * store properties.
+ * 2/ Before calling commitChanges, in case of calling a API to get a property,
+ * return current property, not pending property.
+ * 3/ At the timing of calling weston_layout_commitChanges, pending properties
+ * are applied
+ * to properties.
+ * 4/ According properties, set transformation by using weston_matrix and
+ * weston_view per surfaces and layers in while loop.
+ * 5/ Set damage and trigger transform by using weston_view_geometry_dirty and
+ * weston_view_geometry_dirty.
+ * 6/ Notify update of properties.
+ * 7/ Trigger composition by weston_compositor_schedule_repaint.
+ *
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <cairo.h>
+
+#include "compositor.h"
+#include "weston-layout.h"
+
+enum weston_layout_surface_orientation {
+ WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES = 0,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES = 1,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES = 2,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES = 3,
+};
+
+enum weston_layout_surface_pixelformat {
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_R_8 = 0,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGB_888 = 1,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888 = 2,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGB_565 = 3,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_5551 = 4,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_6661 = 5,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_4444 = 6,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_UNKNOWN = 7,
+};
+
+struct link_layer {
+ struct weston_layout_layer *ivilayer;
+ struct wl_list link;
+};
+
+struct link_screen {
+ struct weston_layout_screen *iviscrn;
+ struct wl_list link;
+};
+
+struct link_layerPropertyNotification {
+ layerPropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfacePropertyNotification {
+ surfacePropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerCreateNotification {
+ layerCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerRemoveNotification {
+ layerRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceCreateNotification {
+ surfaceCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceRemoveNotification {
+ surfaceRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceConfigureNotification {
+ surfaceConfigureNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct weston_layout;
+
+struct weston_layout_surface {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_layer;
+ uint32_t update_count;
+ uint32_t id_surface;
+
+ struct weston_layout *layout;
+ struct weston_surface *surface;
+ struct weston_view *view;
+
+ uint32_t buffer_width;
+ uint32_t buffer_height;
+
+ struct wl_listener surface_destroy_listener;
+ struct weston_transform surface_rotation;
+ struct weston_transform layer_rotation;
+ struct weston_transform surface_pos;
+ struct weston_transform layer_pos;
+ struct weston_transform scaling;
+ struct weston_layout_SurfaceProperties prop;
+ int32_t pixelformat;
+ uint32_t event_mask;
+
+ struct {
+ struct weston_layout_SurfaceProperties prop;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list link;
+ struct wl_list list_layer;
+ } order;
+};
+
+struct weston_layout_layer {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_screen;
+ uint32_t id_layer;
+
+ struct weston_layout *layout;
+ struct weston_layer el;
+
+ struct weston_layout_LayerProperties prop;
+ uint32_t event_mask;
+
+ struct {
+ struct weston_layout_LayerProperties prop;
+ struct wl_list list_surface;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_surface;
+ struct wl_list link;
+ } order;
+};
+
+struct weston_layout_screen {
+ struct wl_list link;
+ uint32_t id_screen;
+
+ struct weston_layout *layout;
+ struct weston_output *output;
+
+ uint32_t event_mask;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } order;
+};
+
+struct weston_layout {
+ struct weston_compositor *compositor;
+
+ struct wl_list list_surface;
+ struct wl_list list_layer;
+ struct wl_list list_screen;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ } layer_notification;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ struct wl_list list_configure;
+ } surface_notification;
+
+ /* to enable displaying cursor*/
+ int32_t is_cursor_enabled;
+};
+
+struct weston_layout ivilayout = {0};
+
+static struct weston_layout *
+get_instance(void)
+{
+ return &ivilayout;
+}
+
+/**
+ * Internal API to add/remove a surface from layer.
+ */
+static void
+add_ordersurface_to_layer(struct weston_layout_surface *ivisurf,
+ struct weston_layout_layer *ivilayer)
+{
+ struct link_layer *link_layer = NULL;
+
+ link_layer = malloc(sizeof *link_layer);
+ if (link_layer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_layer->ivilayer = ivilayer;
+ wl_list_init(&link_layer->link);
+ wl_list_insert(&ivisurf->list_layer, &link_layer->link);
+}
+
+static void
+remove_ordersurface_from_layer(struct weston_layout_surface *ivisurf)
+{
+ struct link_layer *link_layer = NULL;
+ struct link_layer *next = NULL;
+
+ wl_list_for_each_safe(link_layer, next, &ivisurf->list_layer, link) {
+ if (!wl_list_empty(&link_layer->link)) {
+ wl_list_remove(&link_layer->link);
+ }
+ free(link_layer);
+ }
+ wl_list_init(&ivisurf->list_layer);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static void
+add_orderlayer_to_screen(struct weston_layout_layer *ivilayer,
+ struct weston_layout_screen *iviscrn)
+{
+ struct link_screen *link_scrn = NULL;
+
+ link_scrn = malloc(sizeof *link_scrn);
+ if (link_scrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_scrn->iviscrn = iviscrn;
+ wl_list_init(&link_scrn->link);
+ wl_list_insert(&ivilayer->list_screen, &link_scrn->link);
+}
+
+static void
+remove_orderlayer_from_screen(struct weston_layout_layer *ivilayer)
+{
+ struct link_screen *link_scrn = NULL;
+ struct link_screen *next = NULL;
+
+ wl_list_for_each_safe(link_scrn, next, &ivilayer->list_screen, link) {
+ if (!wl_list_empty(&link_scrn->link)) {
+ wl_list_remove(&link_scrn->link);
+ }
+ free(link_scrn);
+ }
+ wl_list_init(&ivilayer->list_screen);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static struct weston_layout_surface *
+get_surface(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct weston_layout_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+static struct weston_layout_layer *
+get_layer(struct wl_list *list_layer, uint32_t id_layer)
+{
+ struct weston_layout_layer *ivilayer;
+
+ wl_list_for_each(ivilayer, list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Called at destruction of ivi_surface
+ */
+static void
+westonsurface_destroy_from_ivisurface(struct wl_listener *listener, void *data)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+
+ ivisurf = container_of(listener, struct weston_layout_surface,
+ surface_destroy_listener);
+ ivisurf->surface = NULL;
+ ivisurf->view = NULL;
+}
+
+/**
+ * Internal API to check layer/surface already added in layer/screen.
+ * Called by weston_layout_layerAddSurface/weston_layout_screenAddLayer
+ */
+static int
+is_surface_in_layer(struct weston_layout_surface *ivisurf,
+ struct weston_layout_layer *ivilayer)
+{
+ struct weston_layout_surface *surf = NULL;
+
+ wl_list_for_each(surf, &ivilayer->pending.list_surface, pending.link) {
+ if (surf->id_surface == ivisurf->id_surface) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+is_layer_in_screen(struct weston_layout_layer *ivilayer,
+ struct weston_layout_screen *iviscrn)
+{
+ struct weston_layout_layer *layer = NULL;
+
+ wl_list_for_each(layer, &iviscrn->pending.list_layer, pending.link) {
+ if (layer->id_layer == ivilayer->id_layer) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Internal API to initialize screens found from output_list of weston_compositor.
+ * Called by weston_layout_initWithCompositor.
+ */
+static void
+create_screen(struct weston_compositor *ec)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_output *output = NULL;
+ int32_t count = 0;
+
+ wl_list_for_each(output, &ec->output_list, link) {
+ iviscrn = calloc(1, sizeof *iviscrn);
+ if (iviscrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ continue;
+ }
+
+ wl_list_init(&iviscrn->link);
+ iviscrn->layout = layout;
+
+ iviscrn->id_screen = count;
+ count++;
+
+ iviscrn->output = output;
+ iviscrn->event_mask = 0;
+
+ wl_list_init(&iviscrn->pending.list_layer);
+ wl_list_init(&iviscrn->pending.link);
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_init(&iviscrn->order.link);
+
+ wl_list_insert(&layout->list_screen, &iviscrn->link);
+ }
+}
+
+/**
+ * Internal APIs to initialize properties of surface/layer when they are created.
+ */
+static void
+init_layerProperties(struct weston_layout_LayerProperties *prop,
+ int32_t width, int32_t height)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+ prop->destWidth = width;
+ prop->destHeight = height;
+}
+
+static void
+init_surfaceProperties(struct weston_layout_SurfaceProperties *prop)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+}
+
+/**
+ * Internal APIs to be called from weston_layout_commitChanges.
+ */
+static void
+update_opacity(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ double layer_alpha = wl_fixed_to_double(ivilayer->prop.opacity);
+ double surf_alpha = wl_fixed_to_double(ivisurf->prop.opacity);
+
+ if ((ivilayer->event_mask & IVI_NOTIFICATION_OPACITY) ||
+ (ivisurf->event_mask & IVI_NOTIFICATION_OPACITY)) {
+ if (ivisurf->view == NULL) {
+ return;
+ }
+ ivisurf->view->alpha = layer_alpha * surf_alpha;
+ }
+}
+
+static void
+update_surface_orientation(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->surface_rotation.matrix;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ if (view == NULL) {
+ return;
+ }
+
+ if ((ivilayer->prop.destWidth == 0) ||
+ (ivilayer->prop.destHeight == 0)) {
+ return;
+ }
+ width = (float)ivilayer->prop.destWidth;
+ height = (float)ivilayer->prop.destHeight;
+
+ switch (ivisurf->prop.orientation) {
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->surface_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_layer_orientation(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_surface *es = ivisurf->surface;
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->layer_rotation.matrix;
+ struct weston_output *output = NULL;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ if (es == NULL || view == NULL) {
+ return;
+ }
+
+ output = es->output;
+ if (output == NULL) {
+ return;
+ }
+ if ((output->width == 0) || (output->height == 0)) {
+ return;
+ }
+ width = (float)output->width;
+ height = (float)output->height;
+
+ switch (ivilayer->prop.orientation) {
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->layer_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->layer_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_surface_position(struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ float tx = (float)ivisurf->prop.destX;
+ float ty = (float)ivisurf->prop.destY;
+ struct weston_matrix *matrix = &ivisurf->surface_pos.matrix;
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->surface_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+
+#if 0
+ /* disable zoom animation */
+ weston_zoom_run(es, 0.0, 1.0, NULL, NULL);
+#endif
+
+}
+
+static void
+update_layer_position(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->layer_pos.matrix;
+ float tx = (float)ivilayer->prop.destX;
+ float ty = (float)ivilayer->prop.destY;
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->layer_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(
+ &view->geometry.transformation_list,
+ &ivisurf->layer_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_scale(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->scaling.matrix;
+ float sx = 0.0f;
+ float sy = 0.0f;
+ float lw = 0.0f;
+ float sw = 0.0f;
+ float lh = 0.0f;
+ float sh = 0.0f;
+
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->prop.sourceWidth == 0 && ivisurf->prop.sourceHeight == 0) {
+ ivisurf->prop.sourceWidth = ivisurf->buffer_width;
+ ivisurf->prop.sourceHeight = ivisurf->buffer_height;
+
+ if (ivisurf->prop.destWidth == 0 && ivisurf->prop.destHeight == 0) {
+ ivisurf->prop.destWidth = ivisurf->buffer_width;
+ ivisurf->prop.destHeight = ivisurf->buffer_height;
+ }
+ }
+
+ lw = ((float)ivilayer->prop.destWidth / ivilayer->prop.sourceWidth );
+ sw = ((float)ivisurf->prop.destWidth / ivisurf->prop.sourceWidth );
+ lh = ((float)ivilayer->prop.destHeight / ivilayer->prop.sourceHeight);
+ sh = ((float)ivisurf->prop.destHeight / ivisurf->prop.sourceHeight );
+ sx = sw * lw;
+ sy = sh * lh;
+
+ wl_list_remove(&ivisurf->scaling.link);
+ weston_matrix_init(matrix);
+ weston_matrix_scale(matrix, sx, sy, 1.0f);
+
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->scaling.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_prop(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ if (ivilayer->event_mask | ivisurf->event_mask) {
+ update_opacity(ivilayer, ivisurf);
+ update_layer_orientation(ivilayer, ivisurf);
+ update_layer_position(ivilayer, ivisurf);
+ update_surface_position(ivisurf);
+ update_surface_orientation(ivilayer, ivisurf);
+ update_scale(ivilayer, ivisurf);
+
+ ivisurf->update_count++;
+
+ if (ivisurf->view != NULL) {
+ weston_view_geometry_dirty(ivisurf->view);
+ }
+
+ if (ivisurf->surface != NULL) {
+ weston_surface_damage(ivisurf->surface);
+ }
+ }
+}
+
+static void
+commit_changes(struct weston_layout *layout)
+{
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ update_prop(ivilayer, ivisurf);
+ }
+ }
+ }
+}
+
+static void
+commit_list_surface(struct weston_layout *layout)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ ivisurf->prop = ivisurf->pending.prop;
+ }
+}
+
+static void
+commit_list_layer(struct weston_layout *layout)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ ivilayer->prop = ivilayer->pending.prop;
+
+ if (!(ivilayer->event_mask &
+ (IVI_NOTIFICATION_ADD | IVI_NOTIFICATION_REMOVE)) ) {
+ continue;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->order.list_surface, order.link) {
+ remove_ordersurface_from_layer(ivisurf);
+
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_for_each(ivisurf, &ivilayer->pending.list_surface,
+ pending.link) {
+ if(!wl_list_empty(&ivisurf->order.link)){
+ wl_list_remove(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_insert(&ivilayer->order.list_surface,
+ &ivisurf->order.link);
+ add_ordersurface_to_layer(ivisurf, ivilayer);
+ }
+ }
+}
+
+static void
+commit_list_screen(struct weston_layout *layout)
+{
+ struct weston_compositor *ec = layout->compositor;
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_layer *next = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ if (iviscrn->event_mask & IVI_NOTIFICATION_ADD) {
+ wl_list_for_each_safe(ivilayer, next,
+ &iviscrn->order.list_layer, order.link) {
+ remove_orderlayer_from_screen(ivilayer);
+
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.link);
+ }
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_for_each(ivilayer, &iviscrn->pending.list_layer,
+ pending.link) {
+ wl_list_insert(&iviscrn->order.list_layer,
+ &ivilayer->order.link);
+ add_orderlayer_to_screen(ivilayer, iviscrn);
+ }
+ iviscrn->event_mask = 0;
+ }
+
+ /* For rendering */
+ wl_list_init(&ec->layer_list);
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+ if (ivilayer->prop.visibility == 0) {
+ continue;
+ }
+
+ wl_list_insert(&ec->layer_list, &ivilayer->el.link);
+ wl_list_init(&ivilayer->el.view_list);
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ if (ivisurf->prop.visibility == 0) {
+ continue;
+ }
+
+ if (ivisurf->surface == NULL || ivisurf->view == NULL) {
+ continue;
+ }
+
+ wl_list_insert(&ivilayer->el.view_list,
+ &ivisurf->view->layer_link);
+ ivisurf->surface->output = iviscrn->output;
+ }
+ }
+
+ /*Add cursor layer if cursor is configured.*/
+ if (layout->is_cursor_enabled) {
+ wl_list_insert(&ec->layer_list, &ec->cursor_layer.link);
+ }
+
+ break;
+ }
+}
+
+static void
+send_surface_prop(struct weston_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivisurf->list_notification, link) {
+ notification->callback(ivisurf, &ivisurf->prop,
+ ivisurf->event_mask,
+ notification->userdata);
+ }
+
+ ivisurf->event_mask = 0;
+}
+
+static void
+send_layer_prop(struct weston_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivilayer->list_notification, link) {
+ notification->callback(ivilayer, &ivilayer->prop,
+ ivilayer->event_mask,
+ notification->userdata);
+ }
+
+ ivilayer->event_mask = 0;
+}
+
+static void
+send_prop(struct weston_layout *layout)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ send_layer_prop(ivilayer);
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ send_surface_prop(ivisurf);
+ }
+}
+
+/**
+ * Exported APIs of weston-layout library are implemented from here.
+ * Brief of APIs is described in weston-layout.h.
+ */
+WL_EXPORT struct weston_view *
+weston_layout_get_weston_view(struct weston_layout_surface *surface)
+{
+ return (surface != NULL) ? surface->view : NULL;
+}
+
+WL_EXPORT void
+weston_layout_initWithCompositor(struct weston_compositor *ec)
+{
+ struct weston_layout *layout = get_instance();
+
+ layout->compositor = ec;
+
+ wl_list_init(&layout->list_surface);
+ wl_list_init(&layout->list_layer);
+ wl_list_init(&layout->list_screen);
+
+ wl_list_init(&layout->layer_notification.list_create);
+ wl_list_init(&layout->layer_notification.list_remove);
+
+ wl_list_init(&layout->surface_notification.list_create);
+ wl_list_init(&layout->surface_notification.list_remove);
+ wl_list_init(&layout->surface_notification.list_configure);
+
+ create_screen(ec);
+
+ struct weston_config *config = weston_config_parse("weston.ini");
+ struct weston_config_section *s =
+ weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ /*A cursor is configured if weston.ini has keys.*/
+ char* cursor_theme = NULL;
+ weston_config_section_get_string(s, "cursor-theme", &cursor_theme, NULL);
+ layout->is_cursor_enabled = (NULL != cursor_theme);
+ free(cursor_theme);
+ weston_config_destroy(config);
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationCreateLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationRemoveLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationCreateSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceConfigureNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationConfigureSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_configure, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT uint32_t
+weston_layout_getIdOfSurface(struct weston_layout_surface *ivisurf)
+{
+ return ivisurf->id_surface;
+}
+
+WL_EXPORT uint32_t
+weston_layout_getIdOfLayer(struct weston_layout_layer *ivilayer)
+{
+ return ivilayer->id_layer;
+}
+
+WL_EXPORT struct weston_layout_layer *
+weston_layout_getLayerFromId(uint32_t id_layer)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct weston_layout_surface *
+weston_layout_getSurfaceFromId(uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct weston_layout_screen *
+weston_layout_getScreenFromId(uint32_t id_screen)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ (void)id_screen;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+//FIXME : select iviscrn from list_screen by id_screen
+ return iviscrn;
+ break;
+ }
+
+ return NULL;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreenResolution(struct weston_layout_screen *iviscrn,
+ uint32_t *pWidth, uint32_t *pHeight)
+{
+ struct weston_output *output = NULL;
+
+ if (pWidth == NULL || pHeight == NULL) {
+ weston_log("weston_layout_getScreenResolution: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ *pWidth = output->current_mode->width;
+ *pHeight = output->current_mode->height;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceAddNotification(struct weston_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ if (ivisurf == NULL || callback == NULL) {
+ weston_log("weston_layout_surfaceAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivisurf->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceRemoveNotification(struct weston_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+ struct link_surfacePropertyNotification *next = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivisurf->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ }
+ wl_list_init(&ivisurf->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT struct weston_layout_surface*
+weston_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (wl_surface == NULL) {
+ weston_log("weston_layout_surfaceCreate: invalid argument\n");
+ return NULL;
+ }
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf != NULL) {
+ if (ivisurf->surface != NULL) {
+ weston_log("id_surface(%d) is already created\n", id_surface);
+ return NULL;
+ } else {
+ /* if ivisurf->surface exist, wl_surface is tied to id_surface again */
+ /* This means client destroys ivi_surface once, and then tries to tie
+ the id_surface to new wl_surface again. The property of id_surface can
+ be inherited.
+ */
+ weston_layout_surfaceSetNativeContent(
+ wl_surface, wl_surface->width, wl_surface->height, id_surface);
+ return ivisurf;
+ }
+ }
+
+ ivisurf = calloc(1, sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivisurf->link);
+ wl_list_init(&ivisurf->list_notification);
+ wl_list_init(&ivisurf->list_layer);
+ ivisurf->id_surface = id_surface;
+ ivisurf->layout = layout;
+
+ ivisurf->surface = wl_surface;
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(wl_surface->resource,
+ &ivisurf->surface_destroy_listener);
+
+ ivisurf->view = weston_view_create(wl_surface);
+ if (ivisurf->view == NULL) {
+ weston_log("fails to allocate memory\n");
+ }
+
+ ivisurf->buffer_width = 0;
+ ivisurf->buffer_height = 0;
+
+ wl_list_init(&ivisurf->surface_rotation.link);
+ wl_list_init(&ivisurf->layer_rotation.link);
+ wl_list_init(&ivisurf->surface_pos.link);
+ wl_list_init(&ivisurf->layer_pos.link);
+ wl_list_init(&ivisurf->scaling.link);
+
+ init_surfaceProperties(&ivisurf->prop);
+ ivisurf->pixelformat = WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+ ivisurf->event_mask = 0;
+
+ ivisurf->pending.prop = ivisurf->prop;
+ wl_list_init(&ivisurf->pending.link);
+
+ wl_list_init(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.list_layer);
+
+ wl_list_insert(&layout->list_surface, &ivisurf->link);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return ivisurf;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetNativeContent(struct weston_surface *surface,
+ uint32_t width,
+ uint32_t height,
+ uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf == NULL) {
+ weston_log("layout surface is not found\n");
+ return -1;
+ }
+
+ if (ivisurf->surface != NULL) {
+ if (surface != NULL) {
+ weston_log("id_surface(%d) is already set the native content\n",
+ id_surface);
+ return -1;
+ }
+
+ wl_list_remove(&ivisurf->surface_destroy_listener.link);
+ weston_view_destroy(ivisurf->view);
+
+ ivisurf->surface = NULL;
+ ivisurf->view = NULL;
+ }
+
+ if (surface == NULL)
+ return 0;
+
+ ivisurf->surface = surface;
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(surface->resource,
+ &ivisurf->surface_destroy_listener);
+ ivisurf->view = weston_view_create(surface);
+ if (ivisurf->view == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ ivisurf->buffer_width = width;
+ ivisurf->buffer_height = height;
+ ivisurf->pixelformat = WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return 0;
+}
+
+WL_EXPORT void
+weston_layout_surfaceConfigure(struct weston_layout_surface *ivisurf,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf->buffer_width = width;
+ ivisurf->buffer_height = height;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_configure, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceRemove(struct weston_layout_surface *ivisurf)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceRemove: invalid argument\n");
+ return -1;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+ if (!wl_list_empty(&ivisurf->link)) {
+ wl_list_remove(&ivisurf->link);
+ }
+ remove_ordersurface_from_layer(ivisurf);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ free(ivisurf);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_UpdateInputEventAcceptanceOn(struct weston_layout_surface *ivisurf,
+ uint32_t devices, uint32_t acceptance)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)devices;
+ (void)acceptance;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceInitialize(struct weston_layout_surface **pSurfaceId)
+{
+ /* not supported */
+ (void)pSurfaceId;
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getPropertiesOfLayer(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties *pLayerProperties)
+{
+ if (ivilayer == NULL || pLayerProperties == NULL) {
+ weston_log("weston_layout_getPropertiesOfLayer: invalid argument\n");
+ return -1;
+ }
+
+ *pLayerProperties = ivilayer->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ uint32_t *pNumberOfHardwareLayers)
+{
+ /* not supported */
+ (void)id_screen;
+ (void)pNumberOfHardwareLayers;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreens(uint32_t *pLength, weston_layout_screen_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getScreens: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_screen_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ (*ppArray)[n++] = iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreensUnderLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_screen_ptr **ppArray)
+{
+ struct link_screen *link_scrn = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getScreensUnderLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_screen_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_scrn, &ivilayer->list_screen, link) {
+ (*ppArray)[n++] = link_scrn->iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayers(uint32_t *pLength, weston_layout_layer_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayersOnScreen(struct weston_layout_screen *iviscrn,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (iviscrn == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayersOnScreen: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&iviscrn->order.list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayersUnderSurface(struct weston_layout_surface *ivisurf,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray)
+{
+ struct link_layer *link_layer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivisurf == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivisurf->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_layer, &ivisurf->list_layer, link) {
+ (*ppArray)[n++] = link_layer->ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getSurfaces(uint32_t *pLength, weston_layout_surface_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getSurfaces: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_surface);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_surface_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getSurfacesOnLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_surface_ptr **ppArray)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getSurfaceIDsOnLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->order.list_surface);
+
+ if (length != 0) {
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_surface_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT struct weston_layout_layer *
+weston_layout_layerCreateWithDimension(uint32_t id_layer,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ struct link_layerCreateNotification *notification = NULL;
+
+ ivilayer = get_layer(&layout->list_layer, id_layer);
+ if (ivilayer != NULL) {
+ weston_log("id_layer is already created\n");
+ return ivilayer;
+ }
+
+ ivilayer = calloc(1, sizeof *ivilayer);
+ if (ivilayer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivilayer->link);
+ wl_list_init(&ivilayer->list_notification);
+ wl_list_init(&ivilayer->list_screen);
+ ivilayer->layout = layout;
+ ivilayer->id_layer = id_layer;
+
+ init_layerProperties(&ivilayer->prop, width, height);
+ ivilayer->event_mask = 0;
+
+ wl_list_init(&ivilayer->pending.list_surface);
+ wl_list_init(&ivilayer->pending.link);
+ ivilayer->pending.prop = ivilayer->prop;
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_init(&ivilayer->order.link);
+
+ wl_list_insert(&layout->list_layer, &ivilayer->link);
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ return ivilayer;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemove(struct weston_layout_layer *ivilayer)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerRemove: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+ if (!wl_list_empty(&ivilayer->link)) {
+ wl_list_remove(&ivilayer->link);
+ }
+ remove_orderlayer_from_screen(ivilayer);
+
+ free(ivilayer);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetType(struct weston_layout_layer *ivilayer,
+ uint32_t *pLayerType)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pLayerType;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t newVisibility)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetVisibility(struct weston_layout_layer *ivilayer, uint32_t *pVisibility)
+{
+ if (ivilayer == NULL || pVisibility == NULL) {
+ weston_log("weston_layout_layerGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivilayer->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetOpacity(struct weston_layout_layer *ivilayer,
+ float opacity)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->opacity = opacity;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetOpacity(struct weston_layout_layer *ivilayer,
+ float *pOpacity)
+{
+ if (ivilayer == NULL || pOpacity == NULL) {
+ weston_log("weston_layout_layerGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivilayer->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetSourceRectangle(struct weston_layout_layer *ivilayer,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetDestinationRectangle(struct weston_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension)
+{
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_layerGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivilayer->prop.destX;
+ pDimension[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_layerSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetPosition(struct weston_layout_layer *ivilayer, int32_t *pPosition)
+{
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("weston_layout_layerGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivilayer->prop.destX;
+ pPosition[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetPosition(struct weston_layout_layer *ivilayer, int32_t *pPosition)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("weston_layout_layerSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t orientation)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->orientation = orientation;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t *pOrientation)
+{
+ if (ivilayer == NULL || pOrientation == NULL) {
+ weston_log("weston_layout_layerGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivilayer->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetChromaKey(struct weston_layout_layer *ivilayer, uint32_t* pColor)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetRenderOrder(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface **pSurface,
+ uint32_t number)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t *id_surface = NULL;
+ uint32_t i = 0;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_init(&ivilayer->pending.list_surface);
+
+ if (pSurface == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_surface = &pSurface[i]->id_surface;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (*id_surface != ivisurf->id_surface) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetCapabilities(struct weston_layout_layer *ivilayer,
+ uint32_t *pCapabilities)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerTypeGetCapabilities(uint32_t layerType,
+ uint32_t *pCapabilities)
+{
+ /* not supported */
+ (void)layerType;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t newVisibility)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t *pVisibility)
+{
+ if (ivisurf == NULL || pVisibility == NULL) {
+ weston_log("weston_layout_surfaceGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivisurf->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetOpacity(struct weston_layout_surface *ivisurf,
+ float opacity)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->opacity = opacity;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetOpacity(struct weston_layout_surface *ivisurf,
+ float *pOpacity)
+{
+ if (ivisurf == NULL || pOpacity == NULL) {
+ weston_log("weston_layout_surfaceGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivisurf->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_SetKeyboardFocusOn(struct weston_layout_surface *ivisurf)
+{
+ /* not supported */
+ (void)ivisurf;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_GetKeyboardFocusSurfaceId(struct weston_layout_surface **pSurfaceId)
+{
+ /* not supported */
+ (void)pSurfaceId;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetDestinationRectangle(struct weston_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetDimension(struct weston_layout_surface *ivisurf, uint32_t *pDimension)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_surfaceSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension)
+{
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_surfaceGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivisurf->prop.destWidth;
+ pDimension[1] = ivisurf->prop.destHeight;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("weston_layout_surfaceSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("weston_layout_surfaceGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivisurf->prop.destX;
+ pPosition[1] = ivisurf->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t orientation)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->orientation = orientation;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t *pOrientation)
+{
+ if (ivisurf == NULL || pOrientation == NULL) {
+ weston_log("weston_layout_surfaceGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivisurf->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetPixelformat(struct weston_layout_layer *ivisurf, uint32_t *pPixelformat)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)pPixelformat;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetChromaKey(struct weston_layout_surface *ivisurf, uint32_t* pColor)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_screenAddLayer(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer *addlayer)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_layer *next = NULL;
+ int is_layer_in_scrn = 0;
+
+ if (iviscrn == NULL || addlayer == NULL) {
+ weston_log("weston_layout_screenAddLayer: invalid argument\n");
+ return -1;
+ }
+
+ is_layer_in_scrn = is_layer_in_screen(addlayer, iviscrn);
+ if (is_layer_in_scrn == 1) {
+ weston_log("weston_layout_screenAddLayer: addlayer is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivilayer, next, &layout->list_layer, link) {
+ if (ivilayer->id_layer == addlayer->id_layer) {
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_screenSetRenderOrder(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer **pLayer,
+ const uint32_t number)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t *id_layer = NULL;
+ uint32_t i = 0;
+
+ if (iviscrn == NULL) {
+ weston_log("weston_layout_screenSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_init(&iviscrn->pending.list_layer);
+
+ if (pLayer == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_layer = &pLayer[i]->id_layer;
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (*id_layer == ivilayer->id_layer) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeScreenshot(struct weston_layout_screen *iviscrn,
+ const char *filename)
+{
+ struct weston_output *output = NULL;
+ cairo_surface_t *cairo_surf = NULL;
+ int32_t i = 0;
+ int32_t width = 0;
+ int32_t height = 0;
+ int32_t stride = 0;
+ uint8_t *readpixs = NULL;
+ uint8_t *writepixs = NULL;
+ uint8_t *d = NULL;
+ uint8_t *s = NULL;
+
+ if (iviscrn == NULL || filename == NULL) {
+ weston_log("weston_layout_takeScreenshot: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ output->disable_planes--;
+
+ width = output->current_mode->width;
+ height = output->current_mode->height;
+ stride = width * (PIXMAN_FORMAT_BPP(output->compositor->read_format) / 8);
+
+ readpixs = malloc(stride * height);
+ if (readpixs == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+ writepixs = malloc(stride * height);
+ if (writepixs == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ output->compositor->renderer->read_pixels(output,
+ output->compositor->read_format, readpixs,
+ 0, 0, width, height);
+
+ s = readpixs;
+ d = writepixs + stride * (height - 1);
+
+ for (i = 0; i < height; i++) {
+ memcpy(d, s, stride);
+ d -= stride;
+ s += stride;
+ }
+
+ cairo_surf = cairo_image_surface_create_for_data(writepixs,
+ CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+ cairo_surface_write_to_png(cairo_surf, filename);
+ cairo_surface_destroy(cairo_surf);
+ free(writepixs);
+ free(readpixs);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeLayerScreenshot(const char *filename, struct weston_layout_layer *ivilayer)
+{
+ /* not supported */
+ (void)filename;
+ (void)ivilayer;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeSurfaceScreenshot(const char *filename,
+ struct weston_layout_surface *ivisurf)
+{
+ weston_log("weston_layout_takeSurfaceScreenshot: "
+ "This function is not supported now\n");
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_SetOptimizationMode(uint32_t id, uint32_t mode)
+{
+ /* not supported */
+ (void)id;
+ (void)mode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_GetOptimizationMode(uint32_t id, uint32_t *pMode)
+{
+ /* not supported */
+ (void)id;
+ (void)pMode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerAddNotification(struct weston_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ if (ivilayer == NULL || callback == NULL) {
+ weston_log("weston_layout_layerAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivilayer->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemoveNotification(struct weston_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+ struct link_layerPropertyNotification *next = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivilayer->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ }
+ wl_list_init(&ivilayer->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getPropertiesOfSurface(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties *pSurfaceProperties)
+{
+ if (ivisurf == NULL || pSurfaceProperties == NULL) {
+ weston_log("weston_layout_getPropertiesOfSurface: invalid argument\n");
+ return -1;
+ }
+
+ *pSurfaceProperties = ivisurf->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerAddSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *addsurf)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+ int is_surf_in_layer = 0;
+
+ if (ivilayer == NULL || addsurf == NULL) {
+ weston_log("weston_layout_layerAddSurface: invalid argument\n");
+ return -1;
+ }
+
+ is_surf_in_layer = is_surface_in_layer(addsurf, ivilayer);
+ if (is_surf_in_layer == 1) {
+ weston_log("weston_layout_layerAddSurface: addsurf is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivisurf, next, &layout->list_surface, link) {
+ if (ivisurf->id_surface == addsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemoveSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *remsurf)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+
+ if (ivilayer == NULL || remsurf == NULL) {
+ weston_log("weston_layout_layerRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->pending.list_surface, pending.link) {
+ if (ivisurf->id_surface == remsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_REMOVE;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetSourceRectangle(struct weston_layout_surface *ivisurf,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_commitChanges(void)
+{
+ struct weston_layout *layout = get_instance();
+
+ commit_list_surface(layout);
+ commit_list_layer(layout);
+ commit_list_screen(layout);
+
+ commit_changes(layout);
+ send_prop(layout);
+ weston_compositor_schedule_repaint(layout->compositor);
+
+ return 0;
+}
diff --git a/ivi-shell/weston-layout.h b/ivi-shell/weston-layout.h
new file mode 100644
index 0000000..2667784
--- /dev/null
+++ b/ivi-shell/weston-layout.h
@@ -0,0 +1,934 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * The weston-layout library supports API set of controlling properties of
+ * surface and layer which groups surfaces. An unique ID whose type is integer
+ * is required to create surface and layer. With the unique ID, surface and
+ * layer are identified to control them. The API set consists of APIs to control
+ * properties of surface and layers about followings,
+ * - visibility.
+ * - opacity.
+ * - clipping (x,y,width,height).
+ * - position and size of it to be displayed.
+ * - orientation per 90 degree.
+ * - add or remove surfaces to a layer.
+ * - order of surfaces/layers in layer/screen to be displayed.
+ * - commit to apply property changes.
+ * - notifications of property change.
+ *
+ * Management of surfaces and layers grouping these surfaces are common way in
+ * In-Vehicle Infotainment system, which integrate several domains in one system.
+ * A layer is allocated to a domain in order to control application surfaces
+ * grouped to the layer all together.
+ */
+
+#ifndef _WESTON_LAYOUT_H_
+#define _WESTON_LAYOUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "compositor.h"
+
+struct weston_layout_SurfaceProperties
+{
+ float opacity;
+ uint32_t sourceX;
+ uint32_t sourceY;
+ uint32_t sourceWidth;
+ uint32_t sourceHeight;
+ uint32_t origSourceWidth;
+ uint32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ uint32_t destWidth;
+ uint32_t destHeight;
+ uint32_t orientation;
+ uint32_t visibility;
+ uint32_t frameCounter;
+ uint32_t drawCounter;
+ uint32_t updateCounter;
+ uint32_t pixelformat;
+ uint32_t nativeSurface;
+ uint32_t inputDevicesAcceptance;
+ uint32_t chromaKeyEnabled;
+ uint32_t chromaKeyRed;
+ uint32_t chromaKeyGreen;
+ uint32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct weston_layout_LayerProperties
+{
+ float opacity;
+ uint32_t sourceX;
+ uint32_t sourceY;
+ uint32_t sourceWidth;
+ uint32_t sourceHeight;
+ uint32_t origSourceWidth;
+ uint32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ uint32_t destWidth;
+ uint32_t destHeight;
+ uint32_t orientation;
+ uint32_t visibility;
+ uint32_t type;
+ uint32_t chromaKeyEnabled;
+ uint32_t chromaKeyRed;
+ uint32_t chromaKeyGreen;
+ uint32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct weston_layout_layer;
+struct weston_layout_surface;
+struct weston_layout_screen;
+
+typedef struct weston_layout_surface* weston_layout_surface_ptr;
+typedef struct weston_layout_layer* weston_layout_layer_ptr;
+typedef struct weston_layout_screen* weston_layout_screen_ptr;
+
+#define IVI_BIT(x) (1 << (x))
+enum weston_layout_notification_mask {
+ IVI_NOTIFICATION_OPACITY = IVI_BIT(1),
+ IVI_NOTIFICATION_SOURCE_RECT = IVI_BIT(2),
+ IVI_NOTIFICATION_DEST_RECT = IVI_BIT(3),
+ IVI_NOTIFICATION_DIMENSION = IVI_BIT(4),
+ IVI_NOTIFICATION_POSITION = IVI_BIT(5),
+ IVI_NOTIFICATION_ORIENTATION = IVI_BIT(6),
+ IVI_NOTIFICATION_VISIBILITY = IVI_BIT(7),
+ IVI_NOTIFICATION_PIXELFORMAT = IVI_BIT(8),
+ IVI_NOTIFICATION_ADD = IVI_BIT(9),
+ IVI_NOTIFICATION_REMOVE = IVI_BIT(10),
+ IVI_NOTIFICATION_ALL = 0xFFFF
+};
+
+typedef void(*layerPropertyNotificationFunc)(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties*,
+ enum weston_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*surfacePropertyNotificationFunc)(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties*,
+ enum weston_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*layerCreateNotificationFunc)(struct weston_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*layerRemoveNotificationFunc)(struct weston_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*surfaceCreateNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceRemoveNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceConfigureNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+/**
+ * \brief to be called by ivi-shell in order to set initail view of
+ * weston_surface.
+ */
+struct weston_view *
+weston_layout_get_weston_view(struct weston_layout_surface *surface);
+
+/**
+ * \brief initialize weston-layout
+ */
+void
+weston_layout_initWithCompositor(struct weston_compositor *ec);
+
+/**
+ * \brief register for notification when layer is created
+ */
+int32_t
+weston_layout_setNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when layer is removed
+ */
+int32_t
+weston_layout_setNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is created
+ */
+int32_t
+weston_layout_setNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is removed
+ */
+int32_t
+weston_layout_setNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is configured
+ */
+int32_t
+weston_layout_setNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief get id of surface from weston_layout_surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+uint32_t
+weston_layout_getIdOfSurface(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief get id of layer from weston_layout_layer
+ *
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+uint32_t
+weston_layout_getIdOfLayer(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief get weston_layout_layer from id of layer
+ *
+ * \return (struct weston_layout_layer *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_layer *
+weston_layout_getLayerFromId(uint32_t id_layer);
+
+/**
+ * \brief get weston_layout_surface from id of surface
+ *
+ * \return (struct weston_layout_surface *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_surface *
+weston_layout_getSurfaceFromId(uint32_t id_surface);
+
+/**
+ * \brief get weston_layout_screen from id of screen
+ *
+ * \return (struct weston_layout_screen *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_screen *
+weston_layout_getScreenFromId(uint32_t id_screen);
+
+/**
+ * \brief Get the screen resolution of a specific screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreenResolution(struct weston_layout_screen *iviscrn,
+ uint32_t *pWidth,
+ uint32_t *pHeight);
+
+/**
+ * \brief register for notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceAddNotification(struct weston_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceRemoveNotification(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Create a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+struct weston_layout_surface *
+weston_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface);
+
+/**
+ * \brief Set the native content of an application to be used as surface content.
+ * If wl_surface is NULL, remove the native content of a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetNativeContent(struct weston_surface *wl_surface,
+ uint32_t width,
+ uint32_t height,
+ uint32_t id_surface);
+
+/**
+ * \brief initialize weston_layout_surface dest/source width and height
+ */
+void
+weston_layout_surfaceConfigure(struct weston_layout_surface *ivisurf,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Remove a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceRemove(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Set from which kind of devices the surface can accept input events.
+ * By default, a surface accept input events from all kind of devices (keyboards, pointer, ...)
+ * By calling this function, you can adjust surface preferences. Note that this function only
+ * adjust the acceptance for the specified devices. Non specified are keept untouched.
+ *
+ * Typicall use case for this function is when dealing with pointer or touch events.
+ * Those are normally dispatched to the first visible surface below the coordinate.
+ * If you want a different behavior (i.e. forward events to an other surface below the coordinate,
+ * you can set all above surfaces to refuse input events)
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_UpdateInputEventAcceptanceOn(struct weston_layout_surface *ivisurf,
+ uint32_t devices,
+ uint32_t acceptance);
+
+/**
+ * \brief Get the layer properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getPropertiesOfLayer(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties *pLayerProperties);
+
+/**
+ * \brief Get the number of hardware layers of a screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ uint32_t *pNumberOfHardwareLayers);
+
+/**
+ * \brief Get the screens
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreens(uint32_t *pLength, weston_layout_screen_ptr **ppArray);
+
+/**
+ * \brief Get the screens under the given layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreensUnderLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_screen_ptr **ppArray);
+
+/**
+ * \brief Get all Layers which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayers(uint32_t *pLength, weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Layers of the given screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayersOnScreen(struct weston_layout_screen *iviscrn,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Layers under the given surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayersUnderSurface(struct weston_layout_surface *ivisurf,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getSurfaces(uint32_t *pLength, weston_layout_surface_ptr **ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered to a given layer and are managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getSurfacesOnLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_surface_ptr **ppArray);
+
+/**
+ * \brief Create a layer which should be managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+struct weston_layout_layer *
+weston_layout_layerCreateWithDimension(uint32_t id_layer,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Removes a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemove(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Get the current type of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetType(struct weston_layout_layer *ivilayer,
+ uint32_t *pLayerType);
+
+/**
+ * \brief Set the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetOpacity(struct weston_layout_layer *ivilayer, float opacity);
+
+/**
+ * \brief Get the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetOpacity(struct weston_layout_layer *ivilayer, float *pOpacity);
+
+/**
+ * \brief Set the area of a layer which should be used for the rendering.
+ * Only this part will be visible.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetSourceRectangle(struct weston_layout_layer *ivilayer,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Set the destination area on the display for a layer.
+ * The layer will be scaled and positioned to this rectangle for rendering
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetDestinationRectangle(struct weston_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetPosition(struct weston_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetPosition(struct weston_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t orientation);
+
+/**
+ * \brief Gets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t *pOrientation);
+
+/**
+ * \brief Sets the color value which defines the transparency value.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetChromaKey(struct weston_layout_layer *ivilayer,
+ uint32_t* pColor);
+
+/**
+ * \brief Sets render order of surfaces within one layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetRenderOrder(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface **pSurface,
+ uint32_t number);
+
+/**
+ * \brief Get the capabilities of a layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetCapabilities(struct weston_layout_layer *ivilayer,
+ uint32_t *pCapabilities);
+
+/**
+ * \brief Get the possible capabilities of a layertype
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerTypeGetCapabilities(uint32_t layerType,
+ uint32_t *pCapabilities);
+
+/**
+ * \brief Create the logical surface, which has no native buffer associated
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceInitialize(struct weston_layout_surface **pSurface);
+
+/**
+ * \brief Set the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetOpacity(struct weston_layout_surface *ivisurf,
+ float opacity);
+
+/**
+ * \brief Get the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetOpacity(struct weston_layout_surface *ivisurf,
+ float *pOpacity);
+
+/**
+ * \brief Set the keyboard focus on a certain surface
+ * To receive keyboard events, 2 conditions must be fulfilled:
+ * 1- The surface must accept events from keyboard. See ilm_UpdateInputEventAcceptanceOn
+ * 2- The keyboard focus must be set on that surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_SetKeyboardFocusOn(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Get the indentifier of the surface which hold the keyboard focus
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_GetKeyboardFocusSurfaceId(struct weston_layout_surface **pSurfaceId);
+
+/**
+ * \brief Set the destination area of a surface within a layer for rendering.
+ * The surface will be scaled to this rectangle for rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetDestinationRectangle(struct weston_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension);
+
+/**
+ * \brief Sets the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Get the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t orientation);
+
+/**
+ * \brief Gets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t *pOrientation);
+
+/**
+ * \brief Gets the pixelformat of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetPixelformat(struct weston_layout_layer *ivisurf,
+ uint32_t *pPixelformat);
+
+/**
+ * \brief Sets the color value which defines the transparency value of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetChromaKey(struct weston_layout_surface *ivisurf,
+ uint32_t* pColor);
+
+/**
+ * \brief Add a layer to a screen which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_screenAddLayer(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer *addlayer);
+
+/**
+ * \brief Sets render order of layers on a display
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_screenSetRenderOrder(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer **pLayer,
+ const uint32_t number);
+
+/**
+ * \brief Take a screenshot from the current displayed layer scene.
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeScreenshot(struct weston_layout_screen *iviscrn,
+ const char *filename);
+
+/**
+ * \brief Take a screenshot of a certain layer
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeLayerScreenshot(const char *filename,
+ struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Take a screenshot of a certain surface
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeSurfaceScreenshot(const char *filename,
+ struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Enable or disable a rendering optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_SetOptimizationMode(uint32_t id, uint32_t mode);
+
+/**
+ * \brief Get the current enablement for an optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_GetOptimizationMode(uint32_t id, uint32_t *pMode);
+
+/**
+ * \brief register for notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerAddNotification(struct weston_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemoveNotification(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Get the surface properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getPropertiesOfSurface(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties *pSurfaceProperties);
+
+/**
+ * \brief Add a surface to a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerAddSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *addsurf);
+
+/**
+ * \brief Removes a surface from a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemoveSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *remsurf);
+
+/**
+ * \brief Set the area of a surface which should be used for the rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetSourceRectangle(struct weston_layout_surface *ivisurf,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Commit all changes and execute all enqueued commands since last commit.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_commitChanges(void);
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _WESTON_LAYOUT_H_ */
--
1.8.3.1
Nobuhiko Tanibata
2014-03-20 06:59:34 UTC
Permalink
API set of controlling properties of surface and layer which groups
surfaces. An unique ID whose type is integer is required to create
surface and layer. With the unique ID, surface and layer are identified
to control them. The API set consists of APIs to control properties of
surface and layers about followings,

- visibility.
- opacity.
- clipping (x,y,width,height).
- position and size of it to be displayed.
- orientation per 90 degree.
- add or remove surfaces to a layer.
- order of surfaces/layers in layer/screen to be displayed.
- commit to apply property changes.
- notifications of property change.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- move this patch in front of ivi-shell patch to be compiled successfully.
- unsupport weston_layout_takeSurfaceScreenshot because implementation needs to
be discussed more. It is pending.
- support inherit propoerties of id_surface when client attaches another
wl_surface with id_surface after destroying ivi_surface once.
- bug fix of https://bugs.tizen.org/jira/browse/TIVI-2882

Changes for v3 and v4:
- nothing. Version number aligned to the first patch

Changes for v5:
- bug fix of https://bugs.tizen.org/jira/browse/TIVI-2881

Makefile.am | 1 +
configure.ac | 15 +-
ivi-shell/Makefile.am | 30 +
ivi-shell/weston-layout.c | 2639 +++++++++++++++++++++++++++++++++++++++++++++
ivi-shell/weston-layout.h | 934 ++++++++++++++++
5 files changed, 3618 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/Makefile.am
create mode 100644 ivi-shell/weston-layout.c
create mode 100644 ivi-shell/weston-layout.h

diff --git a/Makefile.am b/Makefile.am
index f22c542..1bc35e2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,6 +11,7 @@ SUBDIRS = \
src \
$(xwayland_subdir) \
desktop-shell \
+ ivi-shell \
clients \
data \
protocol \
diff --git a/configure.ac b/configure.ac
index cce1850..4c0a90f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -409,6 +409,16 @@ if test "x$enable_dbus" != "xno"; then
fi
AM_CONDITIONAL(ENABLE_DBUS, test "x$enable_dbus" = "xyes")

+# ivi-shell support
+AC_ARG_ENABLE(ivi-shell,
+ AS_HELP_STRING([--disable-ivi-shell],
+ [do not build ivi-shell server plugin and client]),,
+ enable_ivi_shell=yes)
+AM_CONDITIONAL(ENABLE_IVI_SHELL, test "x$enable_ivi_shell" = "xyes")
+if test x$enable_ivi_shell = xyes; then
+ PKG_CHECK_MODULES(IVI_SHELL, [cairo])
+fi
+
AC_ARG_ENABLE(wcap-tools, [ --disable-wcap-tools],, enable_wcap_tools=yes)
AM_CONDITIONAL(BUILD_WCAP_TOOLS, test x$enable_wcap_tools = xyes)
if test x$enable_wcap_tools = xyes; then
@@ -505,7 +515,8 @@ AC_CONFIG_FILES([Makefile
data/Makefile
protocol/Makefile
man/Makefile
- tests/Makefile])
+ tests/Makefile
+ ivi-shell/Makefile])
AC_OUTPUT

AC_MSG_RESULT([
@@ -519,6 +530,8 @@ AC_MSG_RESULT([
XWayland ${enable_xwayland}
dbus ${enable_dbus}

+ ivi-shell ${enable_ivi_shell}
+
Build wcap utility ${enable_wcap_tools}

weston-launch utility ${enable_weston_launch}
diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
new file mode 100644
index 0000000..4d54c2d
--- /dev/null
+++ b/ivi-shell/Makefile.am
@@ -0,0 +1,30 @@
+moduledir = $(libdir)/weston
+
+module_LTLIBRARIES = \
+ $(libweston_layout)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/shared \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src \
+ -DDATADIR='"$(datadir)"' \
+ -DMODULEDIR='"$(moduledir)"' \
+ -DLIBEXECDIR='"$(libexecdir)"' \
+ -DIN_WESTON
+
+westonincludedir = $(includedir)/weston
+westoninclude_HEADERS =
+
+if ENABLE_IVI_SHELL
+westoninclude_HEADERS += \
+ weston-layout.h
+
+libweston_layout = libweston-layout.la
+libweston_layout_la_LDFLAGS = -avoid-version
+libweston_layout_la_LIBADD = $(IVI_SHELL_LIBS) ../shared/libshared.la
+libweston_layout_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
+libweston_layout_la_SOURCES = \
+ weston-layout.c \
+ weston-layout.h
+
+endif
diff --git a/ivi-shell/weston-layout.c b/ivi-shell/weston-layout.c
new file mode 100644
index 0000000..6fabf48
--- /dev/null
+++ b/ivi-shell/weston-layout.c
@@ -0,0 +1,2639 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * Implementation of weston-layout library. The actual view on screen is
+ * not updated till calling weston_layout_commitChanges. A overview from
+ * calling API for updating properties of surfaces/layer to asking compositor
+ * to compose them by using weston_compositor_schedule_repaint,
+ * 0/ initialize this library by weston_layout_initWithCompositor
+ * with (struct weston_compositor *ec) from ivi-shell.
+ * 1/ When a API for updating properties of surface/layer, it updates
+ * pending prop of weston_layout_surface/layer/screen which are structure to
+ * store properties.
+ * 2/ Before calling commitChanges, in case of calling a API to get a property,
+ * return current property, not pending property.
+ * 3/ At the timing of calling weston_layout_commitChanges, pending properties
+ * are applied
+ * to properties.
+ * 4/ According properties, set transformation by using weston_matrix and
+ * weston_view per surfaces and layers in while loop.
+ * 5/ Set damage and trigger transform by using weston_view_geometry_dirty and
+ * weston_view_geometry_dirty.
+ * 6/ Notify update of properties.
+ * 7/ Trigger composition by weston_compositor_schedule_repaint.
+ *
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <cairo.h>
+
+#include "compositor.h"
+#include "weston-layout.h"
+
+enum weston_layout_surface_orientation {
+ WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES = 0,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES = 1,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES = 2,
+ WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES = 3,
+};
+
+enum weston_layout_surface_pixelformat {
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_R_8 = 0,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGB_888 = 1,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888 = 2,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGB_565 = 3,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_5551 = 4,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_6661 = 5,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_4444 = 6,
+ WESTON_LAYOUT_SURFACE_PIXELFORMAT_UNKNOWN = 7,
+};
+
+struct link_layer {
+ struct weston_layout_layer *ivilayer;
+ struct wl_list link;
+};
+
+struct link_screen {
+ struct weston_layout_screen *iviscrn;
+ struct wl_list link;
+};
+
+struct link_layerPropertyNotification {
+ layerPropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfacePropertyNotification {
+ surfacePropertyNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerCreateNotification {
+ layerCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_layerRemoveNotification {
+ layerRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceCreateNotification {
+ surfaceCreateNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceRemoveNotification {
+ surfaceRemoveNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct link_surfaceConfigureNotification {
+ surfaceConfigureNotificationFunc callback;
+ void *userdata;
+ struct wl_list link;
+};
+
+struct weston_layout;
+
+struct weston_layout_surface {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_layer;
+ uint32_t update_count;
+ uint32_t id_surface;
+
+ struct weston_layout *layout;
+ struct weston_surface *surface;
+ struct weston_view *view;
+
+ uint32_t buffer_width;
+ uint32_t buffer_height;
+
+ struct wl_listener surface_destroy_listener;
+ struct weston_transform surface_rotation;
+ struct weston_transform layer_rotation;
+ struct weston_transform surface_pos;
+ struct weston_transform layer_pos;
+ struct weston_transform scaling;
+ struct weston_layout_SurfaceProperties prop;
+ int32_t pixelformat;
+ uint32_t event_mask;
+
+ struct {
+ struct weston_layout_SurfaceProperties prop;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list link;
+ struct wl_list list_layer;
+ } order;
+};
+
+struct weston_layout_layer {
+ struct wl_list link;
+ struct wl_list list_notification;
+ struct wl_list list_screen;
+ uint32_t id_layer;
+
+ struct weston_layout *layout;
+ struct weston_layer el;
+
+ struct weston_layout_LayerProperties prop;
+ uint32_t event_mask;
+
+ struct {
+ struct weston_layout_LayerProperties prop;
+ struct wl_list list_surface;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_surface;
+ struct wl_list link;
+ } order;
+};
+
+struct weston_layout_screen {
+ struct wl_list link;
+ uint32_t id_screen;
+
+ struct weston_layout *layout;
+ struct weston_output *output;
+
+ uint32_t event_mask;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } pending;
+
+ struct {
+ struct wl_list list_layer;
+ struct wl_list link;
+ } order;
+};
+
+struct weston_layout {
+ struct weston_compositor *compositor;
+
+ struct wl_list list_surface;
+ struct wl_list list_layer;
+ struct wl_list list_screen;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ } layer_notification;
+
+ struct {
+ struct wl_list list_create;
+ struct wl_list list_remove;
+ struct wl_list list_configure;
+ } surface_notification;
+
+ /* to enable displaying cursor*/
+ int32_t is_cursor_enabled;
+};
+
+struct weston_layout ivilayout = {0};
+
+static struct weston_layout *
+get_instance(void)
+{
+ return &ivilayout;
+}
+
+/**
+ * Internal API to add/remove a surface from layer.
+ */
+static void
+add_ordersurface_to_layer(struct weston_layout_surface *ivisurf,
+ struct weston_layout_layer *ivilayer)
+{
+ struct link_layer *link_layer = NULL;
+
+ link_layer = malloc(sizeof *link_layer);
+ if (link_layer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_layer->ivilayer = ivilayer;
+ wl_list_init(&link_layer->link);
+ wl_list_insert(&ivisurf->list_layer, &link_layer->link);
+}
+
+static void
+remove_ordersurface_from_layer(struct weston_layout_surface *ivisurf)
+{
+ struct link_layer *link_layer = NULL;
+ struct link_layer *next = NULL;
+
+ wl_list_for_each_safe(link_layer, next, &ivisurf->list_layer, link) {
+ if (!wl_list_empty(&link_layer->link)) {
+ wl_list_remove(&link_layer->link);
+ }
+ free(link_layer);
+ }
+ wl_list_init(&ivisurf->list_layer);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static void
+add_orderlayer_to_screen(struct weston_layout_layer *ivilayer,
+ struct weston_layout_screen *iviscrn)
+{
+ struct link_screen *link_scrn = NULL;
+
+ link_scrn = malloc(sizeof *link_scrn);
+ if (link_scrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ link_scrn->iviscrn = iviscrn;
+ wl_list_init(&link_scrn->link);
+ wl_list_insert(&ivilayer->list_screen, &link_scrn->link);
+}
+
+static void
+remove_orderlayer_from_screen(struct weston_layout_layer *ivilayer)
+{
+ struct link_screen *link_scrn = NULL;
+ struct link_screen *next = NULL;
+
+ wl_list_for_each_safe(link_scrn, next, &ivilayer->list_screen, link) {
+ if (!wl_list_empty(&link_scrn->link)) {
+ wl_list_remove(&link_scrn->link);
+ }
+ free(link_scrn);
+ }
+ wl_list_init(&ivilayer->list_screen);
+}
+
+/**
+ * Internal API to add/remove a layer from screen.
+ */
+static struct weston_layout_surface *
+get_surface(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct weston_layout_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+static struct weston_layout_layer *
+get_layer(struct wl_list *list_layer, uint32_t id_layer)
+{
+ struct weston_layout_layer *ivilayer;
+
+ wl_list_for_each(ivilayer, list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Called at destruction of ivi_surface
+ */
+static void
+westonsurface_destroy_from_ivisurface(struct wl_listener *listener, void *data)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+
+ ivisurf = container_of(listener, struct weston_layout_surface,
+ surface_destroy_listener);
+ ivisurf->surface = NULL;
+ ivisurf->view = NULL;
+}
+
+/**
+ * Internal API to check layer/surface already added in layer/screen.
+ * Called by weston_layout_layerAddSurface/weston_layout_screenAddLayer
+ */
+static int
+is_surface_in_layer(struct weston_layout_surface *ivisurf,
+ struct weston_layout_layer *ivilayer)
+{
+ struct weston_layout_surface *surf = NULL;
+
+ wl_list_for_each(surf, &ivilayer->pending.list_surface, pending.link) {
+ if (surf->id_surface == ivisurf->id_surface) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+is_layer_in_screen(struct weston_layout_layer *ivilayer,
+ struct weston_layout_screen *iviscrn)
+{
+ struct weston_layout_layer *layer = NULL;
+
+ wl_list_for_each(layer, &iviscrn->pending.list_layer, pending.link) {
+ if (layer->id_layer == ivilayer->id_layer) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Internal API to initialize screens found from output_list of weston_compositor.
+ * Called by weston_layout_initWithCompositor.
+ */
+static void
+create_screen(struct weston_compositor *ec)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_output *output = NULL;
+ int32_t count = 0;
+
+ wl_list_for_each(output, &ec->output_list, link) {
+ iviscrn = calloc(1, sizeof *iviscrn);
+ if (iviscrn == NULL) {
+ weston_log("fails to allocate memory\n");
+ continue;
+ }
+
+ wl_list_init(&iviscrn->link);
+ iviscrn->layout = layout;
+
+ iviscrn->id_screen = count;
+ count++;
+
+ iviscrn->output = output;
+ iviscrn->event_mask = 0;
+
+ wl_list_init(&iviscrn->pending.list_layer);
+ wl_list_init(&iviscrn->pending.link);
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_init(&iviscrn->order.link);
+
+ wl_list_insert(&layout->list_screen, &iviscrn->link);
+ }
+}
+
+/**
+ * Internal APIs to initialize properties of surface/layer when they are created.
+ */
+static void
+init_layerProperties(struct weston_layout_LayerProperties *prop,
+ int32_t width, int32_t height)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+ prop->destWidth = width;
+ prop->destHeight = height;
+}
+
+static void
+init_surfaceProperties(struct weston_layout_SurfaceProperties *prop)
+{
+ memset(prop, 0, sizeof *prop);
+ prop->opacity = wl_fixed_from_double(1.0);
+}
+
+/**
+ * Internal APIs to be called from weston_layout_commitChanges.
+ */
+static void
+update_opacity(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ double layer_alpha = wl_fixed_to_double(ivilayer->prop.opacity);
+ double surf_alpha = wl_fixed_to_double(ivisurf->prop.opacity);
+
+ if ((ivilayer->event_mask & IVI_NOTIFICATION_OPACITY) ||
+ (ivisurf->event_mask & IVI_NOTIFICATION_OPACITY)) {
+ if (ivisurf->view == NULL) {
+ return;
+ }
+ ivisurf->view->alpha = layer_alpha * surf_alpha;
+ }
+}
+
+static void
+update_surface_orientation(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->surface_rotation.matrix;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ if (view == NULL) {
+ return;
+ }
+
+ if ((ivilayer->prop.destWidth == 0) ||
+ (ivilayer->prop.destHeight == 0)) {
+ return;
+ }
+ width = (float)ivilayer->prop.destWidth;
+ height = (float)ivilayer->prop.destHeight;
+
+ switch (ivisurf->prop.orientation) {
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->surface_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_layer_orientation(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_surface *es = ivisurf->surface;
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->layer_rotation.matrix;
+ struct weston_output *output = NULL;
+ float width = 0.0f;
+ float height = 0.0f;
+ float v_sin = 0.0f;
+ float v_cos = 0.0f;
+ float cx = 0.0f;
+ float cy = 0.0f;
+ float sx = 1.0f;
+ float sy = 1.0f;
+
+ if (es == NULL || view == NULL) {
+ return;
+ }
+
+ output = es->output;
+ if (output == NULL) {
+ return;
+ }
+ if ((output->width == 0) || (output->height == 0)) {
+ return;
+ }
+ width = (float)output->width;
+ height = (float)output->height;
+
+ switch (ivilayer->prop.orientation) {
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES:
+ v_sin = 0.0f;
+ v_cos = 1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES:
+ v_sin = 1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES:
+ v_sin = 0.0f;
+ v_cos = -1.0f;
+ break;
+ case WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES:
+ default:
+ v_sin = -1.0f;
+ v_cos = 0.0f;
+ sx = width / height;
+ sy = height / width;
+ break;
+ }
+ wl_list_remove(&ivisurf->layer_rotation.link);
+ weston_view_geometry_dirty(view);
+
+ weston_matrix_init(matrix);
+ cx = 0.5f * width;
+ cy = 0.5f * height;
+ weston_matrix_translate(matrix, -cx, -cy, 0.0f);
+ weston_matrix_rotate_xy(matrix, v_cos, v_sin);
+ weston_matrix_scale(matrix, sx, sy, 1.0);
+ weston_matrix_translate(matrix, cx, cy, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->layer_rotation.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_surface_position(struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ float tx = (float)ivisurf->prop.destX;
+ float ty = (float)ivisurf->prop.destY;
+ struct weston_matrix *matrix = &ivisurf->surface_pos.matrix;
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->surface_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->surface_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+
+#if 0
+ /* disable zoom animation */
+ weston_zoom_run(es, 0.0, 1.0, NULL, NULL);
+#endif
+
+}
+
+static void
+update_layer_position(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->layer_pos.matrix;
+ float tx = (float)ivilayer->prop.destX;
+ float ty = (float)ivilayer->prop.destY;
+
+ if (view == NULL) {
+ return;
+ }
+
+ wl_list_remove(&ivisurf->layer_pos.link);
+
+ weston_matrix_init(matrix);
+ weston_matrix_translate(matrix, tx, ty, 0.0f);
+ wl_list_insert(
+ &view->geometry.transformation_list,
+ &ivisurf->layer_pos.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_scale(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ struct weston_view *view = ivisurf->view;
+ struct weston_matrix *matrix = &ivisurf->scaling.matrix;
+ float sx = 0.0f;
+ float sy = 0.0f;
+ float lw = 0.0f;
+ float sw = 0.0f;
+ float lh = 0.0f;
+ float sh = 0.0f;
+
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->prop.sourceWidth == 0 && ivisurf->prop.sourceHeight == 0) {
+ ivisurf->prop.sourceWidth = ivisurf->buffer_width;
+ ivisurf->prop.sourceHeight = ivisurf->buffer_height;
+
+ if (ivisurf->prop.destWidth == 0 && ivisurf->prop.destHeight == 0) {
+ ivisurf->prop.destWidth = ivisurf->buffer_width;
+ ivisurf->prop.destHeight = ivisurf->buffer_height;
+ }
+ }
+
+ lw = ((float)ivilayer->prop.destWidth / ivilayer->prop.sourceWidth );
+ sw = ((float)ivisurf->prop.destWidth / ivisurf->prop.sourceWidth );
+ lh = ((float)ivilayer->prop.destHeight / ivilayer->prop.sourceHeight);
+ sh = ((float)ivisurf->prop.destHeight / ivisurf->prop.sourceHeight );
+ sx = sw * lw;
+ sy = sh * lh;
+
+ wl_list_remove(&ivisurf->scaling.link);
+ weston_matrix_init(matrix);
+ weston_matrix_scale(matrix, sx, sy, 1.0f);
+
+ wl_list_insert(&view->geometry.transformation_list,
+ &ivisurf->scaling.link);
+
+ weston_view_set_transform_parent(view, NULL);
+ weston_view_update_transform(view);
+}
+
+static void
+update_prop(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *ivisurf)
+{
+ if (ivilayer->event_mask | ivisurf->event_mask) {
+ update_opacity(ivilayer, ivisurf);
+ update_layer_orientation(ivilayer, ivisurf);
+ update_layer_position(ivilayer, ivisurf);
+ update_surface_position(ivisurf);
+ update_surface_orientation(ivilayer, ivisurf);
+ update_scale(ivilayer, ivisurf);
+
+ ivisurf->update_count++;
+
+ if (ivisurf->view != NULL) {
+ weston_view_geometry_dirty(ivisurf->view);
+ }
+
+ if (ivisurf->surface != NULL) {
+ weston_surface_damage(ivisurf->surface);
+ }
+ }
+}
+
+static void
+commit_changes(struct weston_layout *layout)
+{
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ update_prop(ivilayer, ivisurf);
+ }
+ }
+ }
+}
+
+static void
+commit_list_surface(struct weston_layout *layout)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ ivisurf->prop = ivisurf->pending.prop;
+ }
+}
+
+static void
+commit_list_layer(struct weston_layout *layout)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ ivilayer->prop = ivilayer->pending.prop;
+
+ if (!(ivilayer->event_mask &
+ (IVI_NOTIFICATION_ADD | IVI_NOTIFICATION_REMOVE)) ) {
+ continue;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->order.list_surface, order.link) {
+ remove_ordersurface_from_layer(ivisurf);
+
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_for_each(ivisurf, &ivilayer->pending.list_surface,
+ pending.link) {
+ if(!wl_list_empty(&ivisurf->order.link)){
+ wl_list_remove(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.link);
+ }
+
+ wl_list_insert(&ivilayer->order.list_surface,
+ &ivisurf->order.link);
+ add_ordersurface_to_layer(ivisurf, ivilayer);
+ }
+ }
+}
+
+static void
+commit_list_screen(struct weston_layout *layout)
+{
+ struct weston_compositor *ec = layout->compositor;
+ struct weston_layout_screen *iviscrn = NULL;
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_layer *next = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ if (iviscrn->event_mask & IVI_NOTIFICATION_ADD) {
+ wl_list_for_each_safe(ivilayer, next,
+ &iviscrn->order.list_layer, order.link) {
+ remove_orderlayer_from_screen(ivilayer);
+
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+
+ wl_list_init(&ivilayer->order.link);
+ }
+
+ wl_list_init(&iviscrn->order.list_layer);
+ wl_list_for_each(ivilayer, &iviscrn->pending.list_layer,
+ pending.link) {
+ wl_list_insert(&iviscrn->order.list_layer,
+ &ivilayer->order.link);
+ add_orderlayer_to_screen(ivilayer, iviscrn);
+ }
+ iviscrn->event_mask = 0;
+ }
+
+ /* For rendering */
+ wl_list_init(&ec->layer_list);
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, order.link) {
+ if (ivilayer->prop.visibility == 0) {
+ continue;
+ }
+
+ wl_list_insert(&ec->layer_list, &ivilayer->el.link);
+ wl_list_init(&ivilayer->el.view_list);
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ if (ivisurf->prop.visibility == 0) {
+ continue;
+ }
+
+ if (ivisurf->surface == NULL || ivisurf->view == NULL) {
+ continue;
+ }
+
+ wl_list_insert(&ivilayer->el.view_list,
+ &ivisurf->view->layer_link);
+ ivisurf->surface->output = iviscrn->output;
+ }
+ }
+
+ /*Add cursor layer if cursor is configured.*/
+ if (layout->is_cursor_enabled) {
+ wl_list_insert(&ec->layer_list, &ec->cursor_layer.link);
+ }
+
+ break;
+ }
+}
+
+static void
+send_surface_prop(struct weston_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivisurf->list_notification, link) {
+ notification->callback(ivisurf, &ivisurf->prop,
+ ivisurf->event_mask,
+ notification->userdata);
+ }
+
+ ivisurf->event_mask = 0;
+}
+
+static void
+send_layer_prop(struct weston_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ wl_list_for_each(notification, &ivilayer->list_notification, link) {
+ notification->callback(ivilayer, &ivilayer->prop,
+ ivilayer->event_mask,
+ notification->userdata);
+ }
+
+ ivilayer->event_mask = 0;
+}
+
+static void
+send_prop(struct weston_layout *layout)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ send_layer_prop(ivilayer);
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ send_surface_prop(ivisurf);
+ }
+}
+
+/**
+ * Exported APIs of weston-layout library are implemented from here.
+ * Brief of APIs is described in weston-layout.h.
+ */
+WL_EXPORT struct weston_view *
+weston_layout_get_weston_view(struct weston_layout_surface *surface)
+{
+ return (surface != NULL) ? surface->view : NULL;
+}
+
+WL_EXPORT void
+weston_layout_initWithCompositor(struct weston_compositor *ec)
+{
+ struct weston_layout *layout = get_instance();
+
+ layout->compositor = ec;
+
+ wl_list_init(&layout->list_surface);
+ wl_list_init(&layout->list_layer);
+ wl_list_init(&layout->list_screen);
+
+ wl_list_init(&layout->layer_notification.list_create);
+ wl_list_init(&layout->layer_notification.list_remove);
+
+ wl_list_init(&layout->surface_notification.list_create);
+ wl_list_init(&layout->surface_notification.list_remove);
+ wl_list_init(&layout->surface_notification.list_configure);
+
+ create_screen(ec);
+
+ struct weston_config *config = weston_config_parse("weston.ini");
+ struct weston_config_section *s =
+ weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ /*A cursor is configured if weston.ini has keys.*/
+ char* cursor_theme = NULL;
+ weston_config_section_get_string(s, "cursor-theme", &cursor_theme, NULL);
+ layout->is_cursor_enabled = (NULL != cursor_theme);
+ free(cursor_theme);
+ weston_config_destroy(config);
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationCreateLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationRemoveLayer: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->layer_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationCreateSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_create, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_remove, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_setNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceConfigureNotification *notification = NULL;
+
+ if (callback == NULL) {
+ weston_log("weston_layout_setNotificationConfigureSurface: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&layout->surface_notification.list_configure, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT uint32_t
+weston_layout_getIdOfSurface(struct weston_layout_surface *ivisurf)
+{
+ return ivisurf->id_surface;
+}
+
+WL_EXPORT uint32_t
+weston_layout_getIdOfLayer(struct weston_layout_layer *ivilayer)
+{
+ return ivilayer->id_layer;
+}
+
+WL_EXPORT struct weston_layout_layer *
+weston_layout_getLayerFromId(uint32_t id_layer)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (ivilayer->id_layer == id_layer) {
+ return ivilayer;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct weston_layout_surface *
+weston_layout_getSurfaceFromId(uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+WL_EXPORT struct weston_layout_screen *
+weston_layout_getScreenFromId(uint32_t id_screen)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ (void)id_screen;
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+//FIXME : select iviscrn from list_screen by id_screen
+ return iviscrn;
+ break;
+ }
+
+ return NULL;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreenResolution(struct weston_layout_screen *iviscrn,
+ uint32_t *pWidth, uint32_t *pHeight)
+{
+ struct weston_output *output = NULL;
+
+ if (pWidth == NULL || pHeight == NULL) {
+ weston_log("weston_layout_getScreenResolution: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ *pWidth = output->current_mode->width;
+ *pHeight = output->current_mode->height;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceAddNotification(struct weston_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+
+ if (ivisurf == NULL || callback == NULL) {
+ weston_log("weston_layout_surfaceAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivisurf->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceRemoveNotification(struct weston_layout_surface *ivisurf)
+{
+ struct link_surfacePropertyNotification *notification = NULL;
+ struct link_surfacePropertyNotification *next = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivisurf->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ }
+ wl_list_init(&ivisurf->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT struct weston_layout_surface*
+weston_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ if (wl_surface == NULL) {
+ weston_log("weston_layout_surfaceCreate: invalid argument\n");
+ return NULL;
+ }
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf != NULL) {
+ if (ivisurf->surface != NULL) {
+ weston_log("id_surface(%d) is already created\n", id_surface);
+ return NULL;
+ } else {
+ /* if ivisurf->surface exist, wl_surface is tied to id_surface again */
+ /* This means client destroys ivi_surface once, and then tries to tie
+ the id_surface to new wl_surface again. The property of id_surface can
+ be inherited.
+ */
+ weston_layout_surfaceSetNativeContent(
+ wl_surface, wl_surface->width, wl_surface->height, id_surface);
+ return ivisurf;
+ }
+ }
+
+ ivisurf = calloc(1, sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivisurf->link);
+ wl_list_init(&ivisurf->list_notification);
+ wl_list_init(&ivisurf->list_layer);
+ ivisurf->id_surface = id_surface;
+ ivisurf->layout = layout;
+
+ ivisurf->surface = wl_surface;
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(wl_surface->resource,
+ &ivisurf->surface_destroy_listener);
+
+ ivisurf->view = weston_view_create(wl_surface);
+ if (ivisurf->view == NULL) {
+ weston_log("fails to allocate memory\n");
+ }
+
+ ivisurf->buffer_width = 0;
+ ivisurf->buffer_height = 0;
+
+ weston_matrix_init(&ivisurf->view->transform.matrix);
+
+ weston_matrix_init(&ivisurf->surface_rotation.matrix);
+ weston_matrix_init(&ivisurf->layer_rotation.matrix);
+ weston_matrix_init(&ivisurf->surface_pos.matrix);
+ weston_matrix_init(&ivisurf->layer_pos.matrix);
+ weston_matrix_init(&ivisurf->scaling.matrix);
+
+ wl_list_init(&ivisurf->surface_rotation.link);
+ wl_list_init(&ivisurf->layer_rotation.link);
+ wl_list_init(&ivisurf->surface_pos.link);
+ wl_list_init(&ivisurf->layer_pos.link);
+ wl_list_init(&ivisurf->scaling.link);
+
+ init_surfaceProperties(&ivisurf->prop);
+ ivisurf->pixelformat = WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+ ivisurf->event_mask = 0;
+
+ ivisurf->pending.prop = ivisurf->prop;
+ wl_list_init(&ivisurf->pending.link);
+
+ wl_list_init(&ivisurf->order.link);
+ wl_list_init(&ivisurf->order.list_layer);
+
+ wl_list_insert(&layout->list_surface, &ivisurf->link);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return ivisurf;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetNativeContent(struct weston_surface *surface,
+ uint32_t width,
+ uint32_t height,
+ uint32_t id_surface)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf;
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf = get_surface(&layout->list_surface, id_surface);
+ if (ivisurf == NULL) {
+ weston_log("layout surface is not found\n");
+ return -1;
+ }
+
+ if (ivisurf->surface != NULL) {
+ if (surface != NULL) {
+ weston_log("id_surface(%d) is already set the native content\n",
+ id_surface);
+ return -1;
+ }
+
+ wl_list_remove(&ivisurf->surface_destroy_listener.link);
+ weston_view_destroy(ivisurf->view);
+
+ ivisurf->surface = NULL;
+ ivisurf->view = NULL;
+ }
+
+ if (surface == NULL)
+ return 0;
+
+ ivisurf->surface = surface;
+ ivisurf->surface_destroy_listener.notify =
+ westonsurface_destroy_from_ivisurface;
+ wl_resource_add_destroy_listener(surface->resource,
+ &ivisurf->surface_destroy_listener);
+ ivisurf->view = weston_view_create(surface);
+ if (ivisurf->view == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ ivisurf->buffer_width = width;
+ ivisurf->buffer_height = height;
+ ivisurf->pixelformat = WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ return 0;
+}
+
+WL_EXPORT void
+weston_layout_surfaceConfigure(struct weston_layout_surface *ivisurf,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceCreateNotification *notification = NULL;
+
+ ivisurf->buffer_width = width;
+ ivisurf->buffer_height = height;
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_configure, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceRemove(struct weston_layout_surface *ivisurf)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_surfaceRemoveNotification *notification = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceRemove: invalid argument\n");
+ return -1;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ if (!wl_list_empty(&ivisurf->order.link)) {
+ wl_list_remove(&ivisurf->order.link);
+ }
+ if (!wl_list_empty(&ivisurf->link)) {
+ wl_list_remove(&ivisurf->link);
+ }
+ remove_ordersurface_from_layer(ivisurf);
+
+ wl_list_for_each(notification,
+ &layout->surface_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivisurf, notification->userdata);
+ }
+ }
+
+ free(ivisurf);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_UpdateInputEventAcceptanceOn(struct weston_layout_surface *ivisurf,
+ uint32_t devices, uint32_t acceptance)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)devices;
+ (void)acceptance;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceInitialize(struct weston_layout_surface **pSurfaceId)
+{
+ /* not supported */
+ (void)pSurfaceId;
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getPropertiesOfLayer(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties *pLayerProperties)
+{
+ if (ivilayer == NULL || pLayerProperties == NULL) {
+ weston_log("weston_layout_getPropertiesOfLayer: invalid argument\n");
+ return -1;
+ }
+
+ *pLayerProperties = ivilayer->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ uint32_t *pNumberOfHardwareLayers)
+{
+ /* not supported */
+ (void)id_screen;
+ (void)pNumberOfHardwareLayers;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreens(uint32_t *pLength, weston_layout_screen_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_screen *iviscrn = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getScreens: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_screen_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(iviscrn, &layout->list_screen, link) {
+ (*ppArray)[n++] = iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getScreensUnderLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_screen_ptr **ppArray)
+{
+ struct link_screen *link_scrn = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getScreensUnderLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->list_screen);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_screen_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_scrn, &ivilayer->list_screen, link) {
+ (*ppArray)[n++] = link_scrn->iviscrn;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayers(uint32_t *pLength, weston_layout_layer_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayersOnScreen(struct weston_layout_screen *iviscrn,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray)
+{
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (iviscrn == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayersOnScreen: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&iviscrn->order.list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivilayer, &iviscrn->order.list_layer, link) {
+ (*ppArray)[n++] = ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getLayersUnderSurface(struct weston_layout_surface *ivisurf,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray)
+{
+ struct link_layer *link_layer = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivisurf == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getLayers: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivisurf->list_layer);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_layer_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(link_layer, &ivisurf->list_layer, link) {
+ (*ppArray)[n++] = link_layer->ivilayer;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getSurfaces(uint32_t *pLength, weston_layout_surface_ptr **ppArray)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getSurfaces: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&layout->list_surface);
+
+ if (length != 0){
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_surface_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getSurfacesOnLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_surface_ptr **ppArray)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t length = 0;
+ uint32_t n = 0;
+
+ if (ivilayer == NULL || pLength == NULL || ppArray == NULL) {
+ weston_log("weston_layout_getSurfaceIDsOnLayer: invalid argument\n");
+ return -1;
+ }
+
+ length = wl_list_length(&ivilayer->order.list_surface);
+
+ if (length != 0) {
+ /* the Array must be free by module which called this function */
+ *ppArray = calloc(length, sizeof(weston_layout_surface_ptr));
+ if (*ppArray == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ wl_list_for_each(ivisurf, &ivilayer->order.list_surface, order.link) {
+ (*ppArray)[n++] = ivisurf;
+ }
+ }
+
+ *pLength = length;
+
+ return 0;
+}
+
+WL_EXPORT struct weston_layout_layer *
+weston_layout_layerCreateWithDimension(uint32_t id_layer,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ struct link_layerCreateNotification *notification = NULL;
+
+ ivilayer = get_layer(&layout->list_layer, id_layer);
+ if (ivilayer != NULL) {
+ weston_log("id_layer is already created\n");
+ return ivilayer;
+ }
+
+ ivilayer = calloc(1, sizeof *ivilayer);
+ if (ivilayer == NULL) {
+ weston_log("fails to allocate memory\n");
+ return NULL;
+ }
+
+ wl_list_init(&ivilayer->link);
+ wl_list_init(&ivilayer->list_notification);
+ wl_list_init(&ivilayer->list_screen);
+ ivilayer->layout = layout;
+ ivilayer->id_layer = id_layer;
+
+ init_layerProperties(&ivilayer->prop, width, height);
+ ivilayer->event_mask = 0;
+
+ wl_list_init(&ivilayer->pending.list_surface);
+ wl_list_init(&ivilayer->pending.link);
+ ivilayer->pending.prop = ivilayer->prop;
+
+ wl_list_init(&ivilayer->order.list_surface);
+ wl_list_init(&ivilayer->order.link);
+
+ wl_list_insert(&layout->list_layer, &ivilayer->link);
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_create, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ return ivilayer;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemove(struct weston_layout_layer *ivilayer)
+{
+ struct weston_layout *layout = get_instance();
+ struct link_layerRemoveNotification *notification = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerRemove: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each(notification,
+ &layout->layer_notification.list_remove, link) {
+ if (notification->callback != NULL) {
+ notification->callback(ivilayer, notification->userdata);
+ }
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ if (!wl_list_empty(&ivilayer->order.link)) {
+ wl_list_remove(&ivilayer->order.link);
+ }
+ if (!wl_list_empty(&ivilayer->link)) {
+ wl_list_remove(&ivilayer->link);
+ }
+ remove_orderlayer_from_screen(ivilayer);
+
+ free(ivilayer);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetType(struct weston_layout_layer *ivilayer,
+ uint32_t *pLayerType)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pLayerType;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t newVisibility)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetVisibility(struct weston_layout_layer *ivilayer, uint32_t *pVisibility)
+{
+ if (ivilayer == NULL || pVisibility == NULL) {
+ weston_log("weston_layout_layerGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivilayer->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetOpacity(struct weston_layout_layer *ivilayer,
+ float opacity)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->opacity = opacity;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetOpacity(struct weston_layout_layer *ivilayer,
+ float *pOpacity)
+{
+ if (ivilayer == NULL || pOpacity == NULL) {
+ weston_log("weston_layout_layerGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivilayer->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetSourceRectangle(struct weston_layout_layer *ivilayer,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetDestinationRectangle(struct weston_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension)
+{
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_layerGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivilayer->prop.destX;
+ pDimension[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_layerSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetPosition(struct weston_layout_layer *ivilayer, int32_t *pPosition)
+{
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("weston_layout_layerGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivilayer->prop.destX;
+ pPosition[1] = ivilayer->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetPosition(struct weston_layout_layer *ivilayer, int32_t *pPosition)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL || pPosition == NULL) {
+ weston_log("weston_layout_layerSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t orientation)
+{
+ struct weston_layout_LayerProperties *prop = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivilayer->pending.prop;
+ prop->orientation = orientation;
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t *pOrientation)
+{
+ if (ivilayer == NULL || pOrientation == NULL) {
+ weston_log("weston_layout_layerGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivilayer->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetChromaKey(struct weston_layout_layer *ivilayer, uint32_t* pColor)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerSetRenderOrder(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface **pSurface,
+ uint32_t number)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t *id_surface = NULL;
+ uint32_t i = 0;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_init(&ivilayer->pending.list_surface);
+
+ if (pSurface == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_surface = &pSurface[i]->id_surface;
+
+ wl_list_for_each(ivisurf, &layout->list_surface, link) {
+ if (*id_surface != ivisurf->id_surface) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerGetCapabilities(struct weston_layout_layer *ivilayer,
+ uint32_t *pCapabilities)
+{
+ /* not supported */
+ (void)ivilayer;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerTypeGetCapabilities(uint32_t layerType,
+ uint32_t *pCapabilities)
+{
+ /* not supported */
+ (void)layerType;
+ (void)pCapabilities;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t newVisibility)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->visibility = newVisibility;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_VISIBILITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t *pVisibility)
+{
+ if (ivisurf == NULL || pVisibility == NULL) {
+ weston_log("weston_layout_surfaceGetVisibility: invalid argument\n");
+ return -1;
+ }
+
+ *pVisibility = ivisurf->prop.visibility;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetOpacity(struct weston_layout_surface *ivisurf,
+ float opacity)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->opacity = opacity;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_OPACITY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetOpacity(struct weston_layout_surface *ivisurf,
+ float *pOpacity)
+{
+ if (ivisurf == NULL || pOpacity == NULL) {
+ weston_log("weston_layout_surfaceGetOpacity: invalid argument\n");
+ return -1;
+ }
+
+ *pOpacity = ivisurf->prop.opacity;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_SetKeyboardFocusOn(struct weston_layout_surface *ivisurf)
+{
+ /* not supported */
+ (void)ivisurf;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_GetKeyboardFocusSurfaceId(struct weston_layout_surface **pSurfaceId)
+{
+ /* not supported */
+ (void)pSurfaceId;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetDestinationRectangle(struct weston_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetDestinationRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = x;
+ prop->destY = y;
+ prop->destWidth = width;
+ prop->destHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DEST_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetDimension(struct weston_layout_surface *ivisurf, uint32_t *pDimension)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_surfaceSetDimension: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destWidth = pDimension[0];
+ prop->destHeight = pDimension[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_DIMENSION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension)
+{
+ if (ivisurf == NULL || &pDimension[0] == NULL || &pDimension[1] == NULL) {
+ weston_log("weston_layout_surfaceGetDimension: invalid argument\n");
+ return -1;
+ }
+
+ pDimension[0] = ivisurf->prop.destWidth;
+ pDimension[1] = ivisurf->prop.destHeight;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("weston_layout_surfaceSetPosition: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->destX = pPosition[0];
+ prop->destY = pPosition[1];
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_POSITION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition)
+{
+ if (ivisurf == NULL || pPosition == NULL) {
+ weston_log("weston_layout_surfaceGetPosition: invalid argument\n");
+ return -1;
+ }
+
+ pPosition[0] = ivisurf->prop.destX;
+ pPosition[1] = ivisurf->prop.destY;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t orientation)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->orientation = orientation;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_ORIENTATION;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t *pOrientation)
+{
+ if (ivisurf == NULL || pOrientation == NULL) {
+ weston_log("weston_layout_surfaceGetOrientation: invalid argument\n");
+ return -1;
+ }
+
+ *pOrientation = ivisurf->prop.orientation;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceGetPixelformat(struct weston_layout_layer *ivisurf, uint32_t *pPixelformat)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)pPixelformat;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetChromaKey(struct weston_layout_surface *ivisurf, uint32_t* pColor)
+{
+ /* not supported */
+ (void)ivisurf;
+ (void)pColor;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_screenAddLayer(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer *addlayer)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ struct weston_layout_layer *next = NULL;
+ int is_layer_in_scrn = 0;
+
+ if (iviscrn == NULL || addlayer == NULL) {
+ weston_log("weston_layout_screenAddLayer: invalid argument\n");
+ return -1;
+ }
+
+ is_layer_in_scrn = is_layer_in_screen(addlayer, iviscrn);
+ if (is_layer_in_scrn == 1) {
+ weston_log("weston_layout_screenAddLayer: addlayer is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivilayer, next, &layout->list_layer, link) {
+ if (ivilayer->id_layer == addlayer->id_layer) {
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_screenSetRenderOrder(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer **pLayer,
+ const uint32_t number)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_layer *ivilayer = NULL;
+ uint32_t *id_layer = NULL;
+ uint32_t i = 0;
+
+ if (iviscrn == NULL) {
+ weston_log("weston_layout_screenSetRenderOrder: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_init(&iviscrn->pending.list_layer);
+
+ if (pLayer == NULL) {
+ return 0;
+ }
+
+ for (i = 0; i < number; i++) {
+ id_layer = &pLayer[i]->id_layer;
+ wl_list_for_each(ivilayer, &layout->list_layer, link) {
+ if (*id_layer == ivilayer->id_layer) {
+ continue;
+ }
+
+ if (!wl_list_empty(&ivilayer->pending.link)) {
+ wl_list_remove(&ivilayer->pending.link);
+ }
+ wl_list_init(&ivilayer->pending.link);
+ wl_list_insert(&iviscrn->pending.list_layer,
+ &ivilayer->pending.link);
+ break;
+ }
+ }
+
+ iviscrn->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeScreenshot(struct weston_layout_screen *iviscrn,
+ const char *filename)
+{
+ struct weston_output *output = NULL;
+ cairo_surface_t *cairo_surf = NULL;
+ int32_t i = 0;
+ int32_t width = 0;
+ int32_t height = 0;
+ int32_t stride = 0;
+ uint8_t *readpixs = NULL;
+ uint8_t *writepixs = NULL;
+ uint8_t *d = NULL;
+ uint8_t *s = NULL;
+
+ if (iviscrn == NULL || filename == NULL) {
+ weston_log("weston_layout_takeScreenshot: invalid argument\n");
+ return -1;
+ }
+
+ output = iviscrn->output;
+ output->disable_planes--;
+
+ width = output->current_mode->width;
+ height = output->current_mode->height;
+ stride = width * (PIXMAN_FORMAT_BPP(output->compositor->read_format) / 8);
+
+ readpixs = malloc(stride * height);
+ if (readpixs == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+ writepixs = malloc(stride * height);
+ if (writepixs == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ output->compositor->renderer->read_pixels(output,
+ output->compositor->read_format, readpixs,
+ 0, 0, width, height);
+
+ s = readpixs;
+ d = writepixs + stride * (height - 1);
+
+ for (i = 0; i < height; i++) {
+ memcpy(d, s, stride);
+ d -= stride;
+ s += stride;
+ }
+
+ cairo_surf = cairo_image_surface_create_for_data(writepixs,
+ CAIRO_FORMAT_ARGB32,
+ width, height, stride);
+ cairo_surface_write_to_png(cairo_surf, filename);
+ cairo_surface_destroy(cairo_surf);
+ free(writepixs);
+ free(readpixs);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeLayerScreenshot(const char *filename, struct weston_layout_layer *ivilayer)
+{
+ /* not supported */
+ (void)filename;
+ (void)ivilayer;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_takeSurfaceScreenshot(const char *filename,
+ struct weston_layout_surface *ivisurf)
+{
+ weston_log("weston_layout_takeSurfaceScreenshot: "
+ "This function is not supported now\n");
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_SetOptimizationMode(uint32_t id, uint32_t mode)
+{
+ /* not supported */
+ (void)id;
+ (void)mode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_GetOptimizationMode(uint32_t id, uint32_t *pMode)
+{
+ /* not supported */
+ (void)id;
+ (void)pMode;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerAddNotification(struct weston_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+
+ if (ivilayer == NULL || callback == NULL) {
+ weston_log("weston_layout_layerAddNotification: invalid argument\n");
+ return -1;
+ }
+
+ notification = malloc(sizeof *notification);
+ if (notification == NULL) {
+ weston_log("fails to allocate memory\n");
+ return -1;
+ }
+
+ notification->callback = callback;
+ notification->userdata = userdata;
+ wl_list_init(&notification->link);
+ wl_list_insert(&ivilayer->list_notification, &notification->link);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemoveNotification(struct weston_layout_layer *ivilayer)
+{
+ struct link_layerPropertyNotification *notification = NULL;
+ struct link_layerPropertyNotification *next = NULL;
+
+ if (ivilayer == NULL) {
+ weston_log("weston_layout_layerRemoveNotification: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(notification, next,
+ &ivilayer->list_notification, link) {
+ if (!wl_list_empty(&notification->link)) {
+ wl_list_remove(&notification->link);
+ }
+ free(notification);
+ }
+ wl_list_init(&ivilayer->list_notification);
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_getPropertiesOfSurface(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties *pSurfaceProperties)
+{
+ if (ivisurf == NULL || pSurfaceProperties == NULL) {
+ weston_log("weston_layout_getPropertiesOfSurface: invalid argument\n");
+ return -1;
+ }
+
+ *pSurfaceProperties = ivisurf->prop;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerAddSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *addsurf)
+{
+ struct weston_layout *layout = get_instance();
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+ int is_surf_in_layer = 0;
+
+ if (ivilayer == NULL || addsurf == NULL) {
+ weston_log("weston_layout_layerAddSurface: invalid argument\n");
+ return -1;
+ }
+
+ is_surf_in_layer = is_surface_in_layer(addsurf, ivilayer);
+ if (is_surf_in_layer == 1) {
+ weston_log("weston_layout_layerAddSurface: addsurf is already available\n");
+ return 0;
+ }
+
+ wl_list_for_each_safe(ivisurf, next, &layout->list_surface, link) {
+ if (ivisurf->id_surface == addsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ wl_list_insert(&ivilayer->pending.list_surface,
+ &ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_ADD;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_layerRemoveSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *remsurf)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_surface *next = NULL;
+
+ if (ivilayer == NULL || remsurf == NULL) {
+ weston_log("weston_layout_layerRemoveSurface: invalid argument\n");
+ return -1;
+ }
+
+ wl_list_for_each_safe(ivisurf, next,
+ &ivilayer->pending.list_surface, pending.link) {
+ if (ivisurf->id_surface == remsurf->id_surface) {
+ if (!wl_list_empty(&ivisurf->pending.link)) {
+ wl_list_remove(&ivisurf->pending.link);
+ }
+ wl_list_init(&ivisurf->pending.link);
+ break;
+ }
+ }
+
+ ivilayer->event_mask |= IVI_NOTIFICATION_REMOVE;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_surfaceSetSourceRectangle(struct weston_layout_surface *ivisurf,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ struct weston_layout_SurfaceProperties *prop = NULL;
+
+ if (ivisurf == NULL) {
+ weston_log("weston_layout_surfaceSetSourceRectangle: invalid argument\n");
+ return -1;
+ }
+
+ prop = &ivisurf->pending.prop;
+ prop->sourceX = x;
+ prop->sourceY = y;
+ prop->sourceWidth = width;
+ prop->sourceHeight = height;
+
+ ivisurf->event_mask |= IVI_NOTIFICATION_SOURCE_RECT;
+
+ return 0;
+}
+
+WL_EXPORT int32_t
+weston_layout_commitChanges(void)
+{
+ struct weston_layout *layout = get_instance();
+
+ commit_list_surface(layout);
+ commit_list_layer(layout);
+ commit_list_screen(layout);
+
+ commit_changes(layout);
+ send_prop(layout);
+ weston_compositor_schedule_repaint(layout->compositor);
+
+ return 0;
+}
diff --git a/ivi-shell/weston-layout.h b/ivi-shell/weston-layout.h
new file mode 100644
index 0000000..2667784
--- /dev/null
+++ b/ivi-shell/weston-layout.h
@@ -0,0 +1,934 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * The weston-layout library supports API set of controlling properties of
+ * surface and layer which groups surfaces. An unique ID whose type is integer
+ * is required to create surface and layer. With the unique ID, surface and
+ * layer are identified to control them. The API set consists of APIs to control
+ * properties of surface and layers about followings,
+ * - visibility.
+ * - opacity.
+ * - clipping (x,y,width,height).
+ * - position and size of it to be displayed.
+ * - orientation per 90 degree.
+ * - add or remove surfaces to a layer.
+ * - order of surfaces/layers in layer/screen to be displayed.
+ * - commit to apply property changes.
+ * - notifications of property change.
+ *
+ * Management of surfaces and layers grouping these surfaces are common way in
+ * In-Vehicle Infotainment system, which integrate several domains in one system.
+ * A layer is allocated to a domain in order to control application surfaces
+ * grouped to the layer all together.
+ */
+
+#ifndef _WESTON_LAYOUT_H_
+#define _WESTON_LAYOUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "compositor.h"
+
+struct weston_layout_SurfaceProperties
+{
+ float opacity;
+ uint32_t sourceX;
+ uint32_t sourceY;
+ uint32_t sourceWidth;
+ uint32_t sourceHeight;
+ uint32_t origSourceWidth;
+ uint32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ uint32_t destWidth;
+ uint32_t destHeight;
+ uint32_t orientation;
+ uint32_t visibility;
+ uint32_t frameCounter;
+ uint32_t drawCounter;
+ uint32_t updateCounter;
+ uint32_t pixelformat;
+ uint32_t nativeSurface;
+ uint32_t inputDevicesAcceptance;
+ uint32_t chromaKeyEnabled;
+ uint32_t chromaKeyRed;
+ uint32_t chromaKeyGreen;
+ uint32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct weston_layout_LayerProperties
+{
+ float opacity;
+ uint32_t sourceX;
+ uint32_t sourceY;
+ uint32_t sourceWidth;
+ uint32_t sourceHeight;
+ uint32_t origSourceWidth;
+ uint32_t origSourceHeight;
+ int32_t destX;
+ int32_t destY;
+ uint32_t destWidth;
+ uint32_t destHeight;
+ uint32_t orientation;
+ uint32_t visibility;
+ uint32_t type;
+ uint32_t chromaKeyEnabled;
+ uint32_t chromaKeyRed;
+ uint32_t chromaKeyGreen;
+ uint32_t chromaKeyBlue;
+ int32_t creatorPid;
+};
+
+struct weston_layout_layer;
+struct weston_layout_surface;
+struct weston_layout_screen;
+
+typedef struct weston_layout_surface* weston_layout_surface_ptr;
+typedef struct weston_layout_layer* weston_layout_layer_ptr;
+typedef struct weston_layout_screen* weston_layout_screen_ptr;
+
+#define IVI_BIT(x) (1 << (x))
+enum weston_layout_notification_mask {
+ IVI_NOTIFICATION_OPACITY = IVI_BIT(1),
+ IVI_NOTIFICATION_SOURCE_RECT = IVI_BIT(2),
+ IVI_NOTIFICATION_DEST_RECT = IVI_BIT(3),
+ IVI_NOTIFICATION_DIMENSION = IVI_BIT(4),
+ IVI_NOTIFICATION_POSITION = IVI_BIT(5),
+ IVI_NOTIFICATION_ORIENTATION = IVI_BIT(6),
+ IVI_NOTIFICATION_VISIBILITY = IVI_BIT(7),
+ IVI_NOTIFICATION_PIXELFORMAT = IVI_BIT(8),
+ IVI_NOTIFICATION_ADD = IVI_BIT(9),
+ IVI_NOTIFICATION_REMOVE = IVI_BIT(10),
+ IVI_NOTIFICATION_ALL = 0xFFFF
+};
+
+typedef void(*layerPropertyNotificationFunc)(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties*,
+ enum weston_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*surfacePropertyNotificationFunc)(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties*,
+ enum weston_layout_notification_mask mask,
+ void *userdata);
+
+typedef void(*layerCreateNotificationFunc)(struct weston_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*layerRemoveNotificationFunc)(struct weston_layout_layer *ivilayer,
+ void *userdata);
+
+typedef void(*surfaceCreateNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceRemoveNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+typedef void(*surfaceConfigureNotificationFunc)(struct weston_layout_surface *ivisurf,
+ void *userdata);
+
+/**
+ * \brief to be called by ivi-shell in order to set initail view of
+ * weston_surface.
+ */
+struct weston_view *
+weston_layout_get_weston_view(struct weston_layout_surface *surface);
+
+/**
+ * \brief initialize weston-layout
+ */
+void
+weston_layout_initWithCompositor(struct weston_compositor *ec);
+
+/**
+ * \brief register for notification when layer is created
+ */
+int32_t
+weston_layout_setNotificationCreateLayer(layerCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when layer is removed
+ */
+int32_t
+weston_layout_setNotificationRemoveLayer(layerRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is created
+ */
+int32_t
+weston_layout_setNotificationCreateSurface(surfaceCreateNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is removed
+ */
+int32_t
+weston_layout_setNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief register for notification when surface is configured
+ */
+int32_t
+weston_layout_setNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief get id of surface from weston_layout_surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+uint32_t
+weston_layout_getIdOfSurface(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief get id of layer from weston_layout_layer
+ *
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+uint32_t
+weston_layout_getIdOfLayer(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief get weston_layout_layer from id of layer
+ *
+ * \return (struct weston_layout_layer *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_layer *
+weston_layout_getLayerFromId(uint32_t id_layer);
+
+/**
+ * \brief get weston_layout_surface from id of surface
+ *
+ * \return (struct weston_layout_surface *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_surface *
+weston_layout_getSurfaceFromId(uint32_t id_surface);
+
+/**
+ * \brief get weston_layout_screen from id of screen
+ *
+ * \return (struct weston_layout_screen *)
+ * if the method call was successful
+ * \return NULL if the client can not call the method on the service.
+ */
+struct weston_layout_screen *
+weston_layout_getScreenFromId(uint32_t id_screen);
+
+/**
+ * \brief Get the screen resolution of a specific screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreenResolution(struct weston_layout_screen *iviscrn,
+ uint32_t *pWidth,
+ uint32_t *pHeight);
+
+/**
+ * \brief register for notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceAddNotification(struct weston_layout_surface *ivisurf,
+ surfacePropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceRemoveNotification(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Create a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+struct weston_layout_surface *
+weston_layout_surfaceCreate(struct weston_surface *wl_surface,
+ uint32_t id_surface);
+
+/**
+ * \brief Set the native content of an application to be used as surface content.
+ * If wl_surface is NULL, remove the native content of a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetNativeContent(struct weston_surface *wl_surface,
+ uint32_t width,
+ uint32_t height,
+ uint32_t id_surface);
+
+/**
+ * \brief initialize weston_layout_surface dest/source width and height
+ */
+void
+weston_layout_surfaceConfigure(struct weston_layout_surface *ivisurf,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Remove a surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceRemove(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Set from which kind of devices the surface can accept input events.
+ * By default, a surface accept input events from all kind of devices (keyboards, pointer, ...)
+ * By calling this function, you can adjust surface preferences. Note that this function only
+ * adjust the acceptance for the specified devices. Non specified are keept untouched.
+ *
+ * Typicall use case for this function is when dealing with pointer or touch events.
+ * Those are normally dispatched to the first visible surface below the coordinate.
+ * If you want a different behavior (i.e. forward events to an other surface below the coordinate,
+ * you can set all above surfaces to refuse input events)
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_UpdateInputEventAcceptanceOn(struct weston_layout_surface *ivisurf,
+ uint32_t devices,
+ uint32_t acceptance);
+
+/**
+ * \brief Get the layer properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getPropertiesOfLayer(struct weston_layout_layer *ivilayer,
+ struct weston_layout_LayerProperties *pLayerProperties);
+
+/**
+ * \brief Get the number of hardware layers of a screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getNumberOfHardwareLayers(uint32_t id_screen,
+ uint32_t *pNumberOfHardwareLayers);
+
+/**
+ * \brief Get the screens
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreens(uint32_t *pLength, weston_layout_screen_ptr **ppArray);
+
+/**
+ * \brief Get the screens under the given layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getScreensUnderLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_screen_ptr **ppArray);
+
+/**
+ * \brief Get all Layers which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayers(uint32_t *pLength, weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Layers of the given screen
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayersOnScreen(struct weston_layout_screen *iviscrn,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Layers under the given surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getLayersUnderSurface(struct weston_layout_surface *ivisurf,
+ uint32_t *pLength,
+ weston_layout_layer_ptr **ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered and managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getSurfaces(uint32_t *pLength, weston_layout_surface_ptr **ppArray);
+
+/**
+ * \brief Get all Surfaces which are currently registered to a given layer and are managed by the services
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getSurfacesOnLayer(struct weston_layout_layer *ivilayer,
+ uint32_t *pLength,
+ weston_layout_surface_ptr **ppArray);
+
+/**
+ * \brief Create a layer which should be managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+struct weston_layout_layer *
+weston_layout_layerCreateWithDimension(uint32_t id_layer,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Removes a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemove(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Get the current type of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetType(struct weston_layout_layer *ivilayer,
+ uint32_t *pLayerType);
+
+/**
+ * \brief Set the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a layer. If a layer is not visible, the layer and its
+ * surfaces will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetVisibility(struct weston_layout_layer *ivilayer,
+ uint32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetOpacity(struct weston_layout_layer *ivilayer, float opacity);
+
+/**
+ * \brief Get the opacity of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetOpacity(struct weston_layout_layer *ivilayer, float *pOpacity);
+
+/**
+ * \brief Set the area of a layer which should be used for the rendering.
+ * Only this part will be visible.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetSourceRectangle(struct weston_layout_layer *ivilayer,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Set the destination area on the display for a layer.
+ * The layer will be scaled and positioned to this rectangle for rendering
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetDestinationRectangle(struct weston_layout_layer *ivilayer,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetDimension(struct weston_layout_layer *ivilayer,
+ uint32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetPosition(struct weston_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the horizontal and vertical position of the layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetPosition(struct weston_layout_layer *ivilayer,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t orientation);
+
+/**
+ * \brief Gets the orientation of a layer.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetOrientation(struct weston_layout_layer *ivilayer,
+ uint32_t *pOrientation);
+
+/**
+ * \brief Sets the color value which defines the transparency value.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetChromaKey(struct weston_layout_layer *ivilayer,
+ uint32_t* pColor);
+
+/**
+ * \brief Sets render order of surfaces within one layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerSetRenderOrder(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface **pSurface,
+ uint32_t number);
+
+/**
+ * \brief Get the capabilities of a layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerGetCapabilities(struct weston_layout_layer *ivilayer,
+ uint32_t *pCapabilities);
+
+/**
+ * \brief Get the possible capabilities of a layertype
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerTypeGetCapabilities(uint32_t layerType,
+ uint32_t *pCapabilities);
+
+/**
+ * \brief Create the logical surface, which has no native buffer associated
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceInitialize(struct weston_layout_surface **pSurface);
+
+/**
+ * \brief Set the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t newVisibility);
+
+/**
+ * \brief Get the visibility of a surface.
+ * If a surface is not visible it will not be rendered.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetVisibility(struct weston_layout_surface *ivisurf,
+ uint32_t *pVisibility);
+
+/**
+ * \brief Set the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetOpacity(struct weston_layout_surface *ivisurf,
+ float opacity);
+
+/**
+ * \brief Get the opacity of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetOpacity(struct weston_layout_surface *ivisurf,
+ float *pOpacity);
+
+/**
+ * \brief Set the keyboard focus on a certain surface
+ * To receive keyboard events, 2 conditions must be fulfilled:
+ * 1- The surface must accept events from keyboard. See ilm_UpdateInputEventAcceptanceOn
+ * 2- The keyboard focus must be set on that surface
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_SetKeyboardFocusOn(struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Get the indentifier of the surface which hold the keyboard focus
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_GetKeyboardFocusSurfaceId(struct weston_layout_surface **pSurfaceId);
+
+/**
+ * \brief Set the destination area of a surface within a layer for rendering.
+ * The surface will be scaled to this rectangle for rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetDestinationRectangle(struct weston_layout_surface *ivisurf,
+ int32_t x, int32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Set the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension);
+
+/**
+ * \brief Get the horizontal and vertical dimension of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetDimension(struct weston_layout_surface *ivisurf,
+ uint32_t *pDimension);
+
+/**
+ * \brief Sets the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Get the horizontal and vertical position of the surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetPosition(struct weston_layout_surface *ivisurf,
+ int32_t *pPosition);
+
+/**
+ * \brief Sets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t orientation);
+
+/**
+ * \brief Gets the orientation of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetOrientation(struct weston_layout_surface *ivisurf,
+ uint32_t *pOrientation);
+
+/**
+ * \brief Gets the pixelformat of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceGetPixelformat(struct weston_layout_layer *ivisurf,
+ uint32_t *pPixelformat);
+
+/**
+ * \brief Sets the color value which defines the transparency value of a surface.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetChromaKey(struct weston_layout_surface *ivisurf,
+ uint32_t* pColor);
+
+/**
+ * \brief Add a layer to a screen which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_screenAddLayer(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer *addlayer);
+
+/**
+ * \brief Sets render order of layers on a display
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_screenSetRenderOrder(struct weston_layout_screen *iviscrn,
+ struct weston_layout_layer **pLayer,
+ const uint32_t number);
+
+/**
+ * \brief Take a screenshot from the current displayed layer scene.
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeScreenshot(struct weston_layout_screen *iviscrn,
+ const char *filename);
+
+/**
+ * \brief Take a screenshot of a certain layer
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeLayerScreenshot(const char *filename,
+ struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Take a screenshot of a certain surface
+ * The screenshot is saved as bmp file with the corresponding filename.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_takeSurfaceScreenshot(const char *filename,
+ struct weston_layout_surface *ivisurf);
+
+/**
+ * \brief Enable or disable a rendering optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_SetOptimizationMode(uint32_t id, uint32_t mode);
+
+/**
+ * \brief Get the current enablement for an optimization
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_GetOptimizationMode(uint32_t id, uint32_t *pMode);
+
+/**
+ * \brief register for notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerAddNotification(struct weston_layout_layer *ivilayer,
+ layerPropertyNotificationFunc callback,
+ void *userdata);
+
+/**
+ * \brief remove notification on property changes of layer
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemoveNotification(struct weston_layout_layer *ivilayer);
+
+/**
+ * \brief Get the surface properties
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_getPropertiesOfSurface(struct weston_layout_surface *ivisurf,
+ struct weston_layout_SurfaceProperties *pSurfaceProperties);
+
+/**
+ * \brief Add a surface to a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerAddSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *addsurf);
+
+/**
+ * \brief Removes a surface from a layer which is currently managed by the service
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_layerRemoveSurface(struct weston_layout_layer *ivilayer,
+ struct weston_layout_surface *remsurf);
+
+/**
+ * \brief Set the area of a surface which should be used for the rendering.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_surfaceSetSourceRectangle(struct weston_layout_surface *ivisurf,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height);
+
+/**
+ * \brief Commit all changes and execute all enqueued commands since last commit.
+ *
+ * \return 0 if the method call was successful
+ * \return -1 if the client can not call the method on the service.
+ */
+int32_t
+weston_layout_commitChanges(void);
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _WESTON_LAYOUT_H_ */
--
1.8.3.1
Pekka Paalanen
2014-04-25 07:24:07 UTC
Permalink
On Thu, 20 Mar 2014 15:59:34 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> API set of controlling properties of surface and layer which groups
> surfaces. An unique ID whose type is integer is required to create
> surface and layer. With the unique ID, surface and layer are identified
> to control them. The API set consists of APIs to control properties of
> surface and layers about followings,
>
> - visibility.
> - opacity.
> - clipping (x,y,width,height).
> - position and size of it to be displayed.
> - orientation per 90 degree.
> - add or remove surfaces to a layer.
> - order of surfaces/layers in layer/screen to be displayed.
> - commit to apply property changes.
> - notifications of property change.
>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - move this patch in front of ivi-shell patch to be compiled successfully.
> - unsupport weston_layout_takeSurfaceScreenshot because implementation needs to
> be discussed more. It is pending.
> - support inherit propoerties of id_surface when client attaches another
> wl_surface with id_surface after destroying ivi_surface once.
> - bug fix of https://bugs.tizen.org/jira/browse/TIVI-2882
>
> Changes for v3 and v4:
> - nothing. Version number aligned to the first patch
>
> Changes for v5:
> - bug fix of https://bugs.tizen.org/jira/browse/TIVI-2881
>
> Makefile.am | 1 +
> configure.ac | 15 +-
> ivi-shell/Makefile.am | 30 +
> ivi-shell/weston-layout.c | 2639 +++++++++++++++++++++++++++++++++++++++++++++
> ivi-shell/weston-layout.h | 934 ++++++++++++++++
> 5 files changed, 3618 insertions(+), 1 deletion(-)
> create mode 100644 ivi-shell/Makefile.am
> create mode 100644 ivi-shell/weston-layout.c
> create mode 100644 ivi-shell/weston-layout.h
>
> diff --git a/Makefile.am b/Makefile.am
> index f22c542..1bc35e2 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -11,6 +11,7 @@ SUBDIRS = \
> src \
> $(xwayland_subdir) \
> desktop-shell \
> + ivi-shell \
> clients \
> data \
> protocol \

Weston recently moved to monolithic Makefile, so the automake stuff
will need porting.

> diff --git a/configure.ac b/configure.ac
> index cce1850..4c0a90f 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -409,6 +409,16 @@ if test "x$enable_dbus" != "xno"; then
> fi
> AM_CONDITIONAL(ENABLE_DBUS, test "x$enable_dbus" = "xyes")
>
> +# ivi-shell support
> +AC_ARG_ENABLE(ivi-shell,
> + AS_HELP_STRING([--disable-ivi-shell],
> + [do not build ivi-shell server plugin and client]),,
> + enable_ivi_shell=yes)
> +AM_CONDITIONAL(ENABLE_IVI_SHELL, test "x$enable_ivi_shell" = "xyes")
> +if test x$enable_ivi_shell = xyes; then
> + PKG_CHECK_MODULES(IVI_SHELL, [cairo])

Only cairo? Or maybe cairo-image?

Hmm, I didn't see this patch add any Cairo calls.

> +fi
> +
> AC_ARG_ENABLE(wcap-tools, [ --disable-wcap-tools],, enable_wcap_tools=yes)
> AM_CONDITIONAL(BUILD_WCAP_TOOLS, test x$enable_wcap_tools = xyes)
> if test x$enable_wcap_tools = xyes; then
> @@ -505,7 +515,8 @@ AC_CONFIG_FILES([Makefile
> data/Makefile
> protocol/Makefile
> man/Makefile
> - tests/Makefile])
> + tests/Makefile
> + ivi-shell/Makefile])
> AC_OUTPUT
>
> AC_MSG_RESULT([
> @@ -519,6 +530,8 @@ AC_MSG_RESULT([
> XWayland ${enable_xwayland}
> dbus ${enable_dbus}
>
> + ivi-shell ${enable_ivi_shell}
> +
> Build wcap utility ${enable_wcap_tools}
>
> weston-launch utility ${enable_weston_launch}
> diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
> new file mode 100644
> index 0000000..4d54c2d
> --- /dev/null
> +++ b/ivi-shell/Makefile.am
> @@ -0,0 +1,30 @@
> +moduledir = $(libdir)/weston
> +
> +module_LTLIBRARIES = \
> + $(libweston_layout)
> +
> +AM_CPPFLAGS = \
> + -I$(top_srcdir)/shared \
> + -I$(top_srcdir)/src \
> + -I$(top_builddir)/src \
> + -DDATADIR='"$(datadir)"' \
> + -DMODULEDIR='"$(moduledir)"' \
> + -DLIBEXECDIR='"$(libexecdir)"' \
> + -DIN_WESTON
> +
> +westonincludedir = $(includedir)/weston
> +westoninclude_HEADERS =
> +
> +if ENABLE_IVI_SHELL
> +westoninclude_HEADERS += \
> + weston-layout.h
> +
> +libweston_layout = libweston-layout.la
> +libweston_layout_la_LDFLAGS = -avoid-version

This is not a Weston plugin, right?
You intend other stuff to link to this library during build and not by
dlopen(), and you intend to install this library along with weston, by
the name libweston-layout.so?

In that case I think you should version this, and fully commit to the
API/ABI stability as it is public. I'd like to see the guarantees
documented somewhere.

Could you explain again, why this is a separate library?
Who and why would want to replace this in a Weston-IVI system?

If libweston-layout.so is Weston-specific, why build it as a separate
library instead of having ivi-shell.so export the same ABI? A little
like we have the EGL specification and standard headers, but vendors
still make their own libEGL.so exporting the specified ABI; though
looking at the header it seems to be very Weston-specific, so no need
for such standardization.

I mean, something (ivi-shell.so?) needs to load hmi-controller.so and/or
ivi-controller.so into Weston by dlopen(), right? So is there some
problem having ivi-shell.so expose the API they need? Or do you just
need something to link ivi-controller.so against for building?

Looking at the PDF picture about the architecture, there are very many
moving pieces with ABIs between them, so reducing them even by one
should help.

I do not have clear picture on which interfaces have ABI stability
guarantees. Usually all installed libraries must have stable and
properly versioned ABI. Weston plugins are not libraries per se; the ABI
stability guarantees apply to symbols exported from Weston core. The
plugin itself usually exports only a single symbol to initialize it. But
if a Weston plugin like ivi-shell.so was to export symbols to be used by
further dynamically loaded code, those symbols become exported ABI
again.

I'd like to see some clarification here, and how you intend to version
the ABIs. In Weston's case, the Weston core exported ABI towards
plugins is stable in 1.x.*, but is allowed to break between 1.x and
1.x+1. Weston is an executable, so I don't think it can have the
library versioning as .so libraries do, but if you build a lib*.so with
the intention of build-time linking, I believe you should do the proper
library versioning, not '-avoid-version'.

> +libweston_layout_la_LIBADD = $(IVI_SHELL_LIBS) ../shared/libshared.la
> +libweston_layout_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
> +libweston_layout_la_SOURCES = \
> + weston-layout.c \
> + weston-layout.h
> +
> +endif
> diff --git a/ivi-shell/weston-layout.c b/ivi-shell/weston-layout.c
> new file mode 100644
> index 0000000..6fabf48
> --- /dev/null
> +++ b/ivi-shell/weston-layout.c
> @@ -0,0 +1,2639 @@
> +/*
> + * Copyright (C) 2013 DENSO CORPORATION
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission. The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose. It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +/**
> + * Implementation of weston-layout library. The actual view on screen is
> + * not updated till calling weston_layout_commitChanges. A overview from
> + * calling API for updating properties of surfaces/layer to asking compositor
> + * to compose them by using weston_compositor_schedule_repaint,
> + * 0/ initialize this library by weston_layout_initWithCompositor
> + * with (struct weston_compositor *ec) from ivi-shell.
> + * 1/ When a API for updating properties of surface/layer, it updates
> + * pending prop of weston_layout_surface/layer/screen which are structure to
> + * store properties.
> + * 2/ Before calling commitChanges, in case of calling a API to get a property,
> + * return current property, not pending property.
> + * 3/ At the timing of calling weston_layout_commitChanges, pending properties
> + * are applied
> + * to properties.
> + * 4/ According properties, set transformation by using weston_matrix and
> + * weston_view per surfaces and layers in while loop.
> + * 5/ Set damage and trigger transform by using weston_view_geometry_dirty and
> + * weston_view_geometry_dirty.
> + * 6/ Notify update of properties.
> + * 7/ Trigger composition by weston_compositor_schedule_repaint.

Ok.

> + *
> + */
> +
> +#include <sys/wait.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <linux/input.h>
> +#include <cairo.h>
> +
> +#include "compositor.h"
> +#include "weston-layout.h"
> +
> +enum weston_layout_surface_orientation {
> + WESTON_LAYOUT_SURFACE_ORIENTATION_0_DEGREES = 0,
> + WESTON_LAYOUT_SURFACE_ORIENTATION_90_DEGREES = 1,
> + WESTON_LAYOUT_SURFACE_ORIENTATION_180_DEGREES = 2,
> + WESTON_LAYOUT_SURFACE_ORIENTATION_270_DEGREES = 3,
> +};
> +
> +enum weston_layout_surface_pixelformat {
> + WESTON_LAYOUT_SURFACE_PIXELFORMAT_R_8 = 0,
> + WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGB_888 = 1,
> + WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_8888 = 2,
> + WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGB_565 = 3,
> + WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_5551 = 4,
> + WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_6661 = 5,
> + WESTON_LAYOUT_SURFACE_PIXELFORMAT_RGBA_4444 = 6,
> + WESTON_LAYOUT_SURFACE_PIXELFORMAT_UNKNOWN = 7,
> +};
> +
> +struct link_layer {
> + struct weston_layout_layer *ivilayer;
> + struct wl_list link;
> +};
> +
> +struct link_screen {
> + struct weston_layout_screen *iviscrn;
> + struct wl_list link;
> +};

Do you have an arbitrary number of lists, where a ivilayer or iviscrn
can be in?

If not, why not embed the wl_list member into weston_layout_* structs?

> +
> +struct link_layerPropertyNotification {
> + layerPropertyNotificationFunc callback;
> + void *userdata;
> + struct wl_list link;
> +};
> +
> +struct link_surfacePropertyNotification {
> + surfacePropertyNotificationFunc callback;
> + void *userdata;
> + struct wl_list link;
> +};
> +
> +struct link_layerCreateNotification {
> + layerCreateNotificationFunc callback;
> + void *userdata;
> + struct wl_list link;
> +};
> +
> +struct link_layerRemoveNotification {
> + layerRemoveNotificationFunc callback;
> + void *userdata;
> + struct wl_list link;
> +};
> +
> +struct link_surfaceCreateNotification {
> + surfaceCreateNotificationFunc callback;
> + void *userdata;
> + struct wl_list link;
> +};
> +
> +struct link_surfaceRemoveNotification {
> + surfaceRemoveNotificationFunc callback;
> + void *userdata;
> + struct wl_list link;
> +};
> +
> +struct link_surfaceConfigureNotification {
> + surfaceConfigureNotificationFunc callback;
> + void *userdata;
> + struct wl_list link;
> +};

Any reason you defined all these different structs, and didn't use the
wl_signal/wl_listener pattern?

> +
> +struct weston_layout;
> +
> +struct weston_layout_surface {
> + struct wl_list link;

For link members, I would personally prefer some indication of which
(kind of) list the link will belong to, if possible and especially if
there are multiple links in a struct.

> + struct wl_list list_notification;
> + struct wl_list list_layer;

The Weston convention is to say "notification_list", "layer_list". I
would also add a comment saying what link the list will hold, e.g.
... foo_list; /* struct weston_layout_layer::link */
That explicitly says what the struct embedding the 'link' member is, as
one list can only ever contain one type of objects, and explains how to
access that object from a link pointer.

Hmm... so one surface can be in multiple layers??

> + uint32_t update_count;
> + uint32_t id_surface;
> +
> + struct weston_layout *layout;
> + struct weston_surface *surface;
> + struct weston_view *view;

Why have the view pointer explicitly here? Can't you access that via
weston_surface?

> +
> + uint32_t buffer_width;
> + uint32_t buffer_height;

Would these perhaps happen to be the same as
weston_surface::width_from_buffer and
weston_surface::height_from_buffer?

They feel a bit out of place here.

> +
> + struct wl_listener surface_destroy_listener;
> + struct weston_transform surface_rotation;
> + struct weston_transform layer_rotation;
> + struct weston_transform surface_pos;
> + struct weston_transform layer_pos;
> + struct weston_transform scaling;
> + struct weston_layout_SurfaceProperties prop;
> + int32_t pixelformat;
> + uint32_t event_mask;
> +
> + struct {
> + struct weston_layout_SurfaceProperties prop;
> + struct wl_list link;
> + } pending;
> +
> + struct {
> + struct wl_list link;
> + struct wl_list list_layer;
> + } order;
> +};
> +
> +struct weston_layout_layer {
> + struct wl_list link;
> + struct wl_list list_notification;
> + struct wl_list list_screen;
> + uint32_t id_layer;
> +
> + struct weston_layout *layout;
> + struct weston_layer el;
> +
> + struct weston_layout_LayerProperties prop;
> + uint32_t event_mask;
> +
> + struct {
> + struct weston_layout_LayerProperties prop;
> + struct wl_list list_surface;
> + struct wl_list link;
> + } pending;
> +
> + struct {
> + struct wl_list list_surface;
> + struct wl_list link;
> + } order;
> +};
> +
> +struct weston_layout_screen {
> + struct wl_list link;
> + uint32_t id_screen;
> +
> + struct weston_layout *layout;
> + struct weston_output *output;
> +
> + uint32_t event_mask;
> +
> + struct {
> + struct wl_list list_layer;
> + struct wl_list link;
> + } pending;
> +
> + struct {
> + struct wl_list list_layer;
> + struct wl_list link;
> + } order;
> +};
> +
> +struct weston_layout {
> + struct weston_compositor *compositor;
> +
> + struct wl_list list_surface;
> + struct wl_list list_layer;
> + struct wl_list list_screen;
> +
> + struct {
> + struct wl_list list_create;
> + struct wl_list list_remove;
> + } layer_notification;
> +
> + struct {
> + struct wl_list list_create;
> + struct wl_list list_remove;
> + struct wl_list list_configure;
> + } surface_notification;
> +
> + /* to enable displaying cursor*/
> + int32_t is_cursor_enabled;
> +};
> +
> +struct weston_layout ivilayout = {0};

A global, non-static variable, what for?
Should it be static at least?

> +
> +static struct weston_layout *
> +get_instance(void)
> +{
> + return &ivilayout;
> +}
> +

...

> +/**
> + * Internal API to initialize screens found from output_list of weston_compositor.
> + * Called by weston_layout_initWithCompositor.
> + */
> +static void
> +create_screen(struct weston_compositor *ec)
> +{
> + struct weston_layout *layout = get_instance();
> + struct weston_layout_screen *iviscrn = NULL;
> + struct weston_output *output = NULL;
> + int32_t count = 0;
> +
> + wl_list_for_each(output, &ec->output_list, link) {
> + iviscrn = calloc(1, sizeof *iviscrn);
> + if (iviscrn == NULL) {
> + weston_log("fails to allocate memory\n");
> + continue;
> + }
> +
> + wl_list_init(&iviscrn->link);
> + iviscrn->layout = layout;
> +
> + iviscrn->id_screen = count;
> + count++;
> +
> + iviscrn->output = output;
> + iviscrn->event_mask = 0;
> +
> + wl_list_init(&iviscrn->pending.list_layer);
> + wl_list_init(&iviscrn->pending.link);
> +
> + wl_list_init(&iviscrn->order.list_layer);
> + wl_list_init(&iviscrn->order.link);
> +
> + wl_list_insert(&layout->list_screen, &iviscrn->link);
> + }
> +}

Do you handle at all the case of hotplugging outputs?
Does the IVI software architecture simply not support any kind of
hotplug?

> +/**
> + * Exported APIs of weston-layout library are implemented from here.
> + * Brief of APIs is described in weston-layout.h.
> + */
> +WL_EXPORT struct weston_view *
> +weston_layout_get_weston_view(struct weston_layout_surface *surface)
> +{
> + return (surface != NULL) ? surface->view : NULL;
> +}
> +
> +WL_EXPORT void
> +weston_layout_initWithCompositor(struct weston_compositor *ec)
> +{
> + struct weston_layout *layout = get_instance();
> +
> + layout->compositor = ec;
> +
> + wl_list_init(&layout->list_surface);
> + wl_list_init(&layout->list_layer);
> + wl_list_init(&layout->list_screen);
> +
> + wl_list_init(&layout->layer_notification.list_create);
> + wl_list_init(&layout->layer_notification.list_remove);
> +
> + wl_list_init(&layout->surface_notification.list_create);
> + wl_list_init(&layout->surface_notification.list_remove);
> + wl_list_init(&layout->surface_notification.list_configure);
> +
> + create_screen(ec);
> +
> + struct weston_config *config = weston_config_parse("weston.ini");
> + struct weston_config_section *s =
> + weston_config_get_section(config, "ivi-shell", NULL, NULL);
> +
> + /*A cursor is configured if weston.ini has keys.*/
> + char* cursor_theme = NULL;
> + weston_config_section_get_string(s, "cursor-theme", &cursor_theme, NULL);
> + layout->is_cursor_enabled = (NULL != cursor_theme);
> + free(cursor_theme);
> + weston_config_destroy(config);
> +}
> +
> +WL_EXPORT int32_t
> +weston_layout_setNotificationCreateLayer(layerCreateNotificationFunc callback,
> + void *userdata)
> +{
> + struct weston_layout *layout = get_instance();
> + struct link_layerCreateNotification *notification = NULL;
> +
> + if (callback == NULL) {
> + weston_log("weston_layout_setNotificationCreateLayer: invalid argument\n");
> + return -1;
> + }
> +
> + notification = malloc(sizeof *notification);
> + if (notification == NULL) {
> + weston_log("fails to allocate memory\n");
> + return -1;
> + }
> +
> + notification->callback = callback;
> + notification->userdata = userdata;
> + wl_list_init(&notification->link);
> + wl_list_insert(&layout->layer_notification.list_create, &notification->link);
> +
> + return 0;
> +}

How does a user of this API remove a notification callback?

Also seems like this is more of an "add" rather than "set", since you
can add many callbacks and they all work.

> +WL_EXPORT struct weston_layout_screen *
> +weston_layout_getScreenFromId(uint32_t id_screen)
> +{
> + struct weston_layout *layout = get_instance();
> + struct weston_layout_screen *iviscrn = NULL;
> + (void)id_screen;
> +
> + wl_list_for_each(iviscrn, &layout->list_screen, link) {
> +//FIXME : select iviscrn from list_screen by id_screen

Ahha ;-)

> + return iviscrn;
> + break;
> + }
> +
> + return NULL;
> +}

...

> +WL_EXPORT int32_t
> +weston_layout_UpdateInputEventAcceptanceOn(struct weston_layout_surface *ivisurf,
> + uint32_t devices, uint32_t acceptance)
> +{
> + /* not supported */
> + (void)ivisurf;
> + (void)devices;
> + (void)acceptance;
> +
> + return 0;

Error, or silently ignored?
Do you plan to implement this function?

There are a lot more similar functions which have the same "not
supported" comment.

...

> diff --git a/ivi-shell/weston-layout.h b/ivi-shell/weston-layout.h
> new file mode 100644
> index 0000000..2667784
> --- /dev/null
> +++ b/ivi-shell/weston-layout.h
> @@ -0,0 +1,934 @@
> +/*
> + * Copyright (C) 2013 DENSO CORPORATION
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission. The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose. It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +/**
> + * The weston-layout library supports API set of controlling properties of
> + * surface and layer which groups surfaces. An unique ID whose type is integer
> + * is required to create surface and layer. With the unique ID, surface and
> + * layer are identified to control them. The API set consists of APIs to control
> + * properties of surface and layers about followings,
> + * - visibility.
> + * - opacity.
> + * - clipping (x,y,width,height).
> + * - position and size of it to be displayed.
> + * - orientation per 90 degree.
> + * - add or remove surfaces to a layer.
> + * - order of surfaces/layers in layer/screen to be displayed.
> + * - commit to apply property changes.
> + * - notifications of property change.
> + *
> + * Management of surfaces and layers grouping these surfaces are common way in
> + * In-Vehicle Infotainment system, which integrate several domains in one system.
> + * A layer is allocated to a domain in order to control application surfaces
> + * grouped to the layer all together.
> + */
> +
> +#ifndef _WESTON_LAYOUT_H_
> +#define _WESTON_LAYOUT_H_
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif /* __cplusplus */
> +
> +#include "compositor.h"
> +
> +struct weston_layout_SurfaceProperties
> +{
> + float opacity;
> + uint32_t sourceX;
> + uint32_t sourceY;
> + uint32_t sourceWidth;
> + uint32_t sourceHeight;
> + uint32_t origSourceWidth;
> + uint32_t origSourceHeight;
> + int32_t destX;
> + int32_t destY;
> + uint32_t destWidth;
> + uint32_t destHeight;

All these unsigned members seem like they are calling for mismatching
signed and unsigned variables in computations, which can lead to
surprising bugs. Is there a reason why these coordinate related members
(position and size) are unsigned?

Weston code base and even Wayland protocol categorically uses signed
integers for everything that is computed with, like size which can
never be legally negative. Only flags, bitfields, object ids and such
are unsigned, because they will never be used in computations that may
include signed integers.

> + uint32_t orientation;
> + uint32_t visibility;
> + uint32_t frameCounter;
> + uint32_t drawCounter;
> + uint32_t updateCounter;
> + uint32_t pixelformat;
> + uint32_t nativeSurface;
> + uint32_t inputDevicesAcceptance;
> + uint32_t chromaKeyEnabled;
> + uint32_t chromaKeyRed;
> + uint32_t chromaKeyGreen;
> + uint32_t chromaKeyBlue;
> + int32_t creatorPid;
> +};
> +
> +struct weston_layout_LayerProperties
> +{
> + float opacity;
> + uint32_t sourceX;
> + uint32_t sourceY;
> + uint32_t sourceWidth;
> + uint32_t sourceHeight;
> + uint32_t origSourceWidth;
> + uint32_t origSourceHeight;
> + int32_t destX;
> + int32_t destY;
> + uint32_t destWidth;
> + uint32_t destHeight;
> + uint32_t orientation;
> + uint32_t visibility;
> + uint32_t type;
> + uint32_t chromaKeyEnabled;
> + uint32_t chromaKeyRed;
> + uint32_t chromaKeyGreen;
> + uint32_t chromaKeyBlue;
> + int32_t creatorPid;
> +};
> +
> +struct weston_layout_layer;
> +struct weston_layout_surface;
> +struct weston_layout_screen;
> +
> +typedef struct weston_layout_surface* weston_layout_surface_ptr;
> +typedef struct weston_layout_layer* weston_layout_layer_ptr;
> +typedef struct weston_layout_screen* weston_layout_screen_ptr;

Weston coding style seems to avoid this kind of typedefs, it is the
same rationale as in the kernel coding style.

> +
> +#define IVI_BIT(x) (1 << (x))
> +enum weston_layout_notification_mask {
> + IVI_NOTIFICATION_OPACITY = IVI_BIT(1),
> + IVI_NOTIFICATION_SOURCE_RECT = IVI_BIT(2),
> + IVI_NOTIFICATION_DEST_RECT = IVI_BIT(3),
> + IVI_NOTIFICATION_DIMENSION = IVI_BIT(4),
> + IVI_NOTIFICATION_POSITION = IVI_BIT(5),
> + IVI_NOTIFICATION_ORIENTATION = IVI_BIT(6),
> + IVI_NOTIFICATION_VISIBILITY = IVI_BIT(7),
> + IVI_NOTIFICATION_PIXELFORMAT = IVI_BIT(8),
> + IVI_NOTIFICATION_ADD = IVI_BIT(9),
> + IVI_NOTIFICATION_REMOVE = IVI_BIT(10),

Would probably be shorter to just write = 1 << 7,
;-)
Bit 0 unused?

> + IVI_NOTIFICATION_ALL = 0xFFFF
> +};
> +
> +typedef void(*layerPropertyNotificationFunc)(struct weston_layout_layer *ivilayer,
> + struct weston_layout_LayerProperties*,
> + enum weston_layout_notification_mask mask,
> + void *userdata);

OTOH, function pointer typedefs are useful.

> +
> +typedef void(*surfacePropertyNotificationFunc)(struct weston_layout_surface *ivisurf,
> + struct weston_layout_SurfaceProperties*,
> + enum weston_layout_notification_mask mask,
> + void *userdata);
> +
> +typedef void(*layerCreateNotificationFunc)(struct weston_layout_layer *ivilayer,
> + void *userdata);
> +
> +typedef void(*layerRemoveNotificationFunc)(struct weston_layout_layer *ivilayer,
> + void *userdata);
> +
> +typedef void(*surfaceCreateNotificationFunc)(struct weston_layout_surface *ivisurf,
> + void *userdata);
> +
> +typedef void(*surfaceRemoveNotificationFunc)(struct weston_layout_surface *ivisurf,
> + void *userdata);
> +
> +typedef void(*surfaceConfigureNotificationFunc)(struct weston_layout_surface *ivisurf,
> + void *userdata);
> +
> +/**
> + * \brief to be called by ivi-shell in order to set initail view of
> + * weston_surface.
> + */
> +struct weston_view *
> +weston_layout_get_weston_view(struct weston_layout_surface *surface);

This creates a weston_view? No, it doesn't. What does this have to do
with the initial view?

A side note; If you built weston-layout into ivi-shell.so instead of
making a weston-layout.so, you would not need to export all these
functions that only ivi-shell would use. I think that would be a big
benefit, if you can do that, reducing the API surface.

> +
> +/**
> + * \brief initialize weston-layout
> + */
> +void
> +weston_layout_initWithCompositor(struct weston_compositor *ec);

Mixing two different naming conventions like this looks strange,
especially for a function that I assume will be called by ivi-shell,
not ivi-controller.

> +
> +/**
> + * \brief register for notification when layer is created
> + */
> +int32_t
> +weston_layout_setNotificationCreateLayer(layerCreateNotificationFunc callback,
> + void *userdata);
> +
> +/**
> + * \brief register for notification when layer is removed
> + */
> +int32_t
> +weston_layout_setNotificationRemoveLayer(layerRemoveNotificationFunc callback,
> + void *userdata);
> +
> +/**
> + * \brief register for notification when surface is created
> + */
> +int32_t
> +weston_layout_setNotificationCreateSurface(surfaceCreateNotificationFunc callback,
> + void *userdata);
> +
> +/**
> + * \brief register for notification when surface is removed
> + */
> +int32_t
> +weston_layout_setNotificationRemoveSurface(surfaceRemoveNotificationFunc callback,
> + void *userdata);
> +
> +/**
> + * \brief register for notification when surface is configured
> + */
> +int32_t
> +weston_layout_setNotificationConfigureSurface(surfaceConfigureNotificationFunc callback,
> + void *userdata);
> +
> +/**
> + * \brief get id of surface from weston_layout_surface
> + *
> + * \return 0 if the method call was successful
> + * \return -1 if the client can not call the method on the service.

Where do you actually return the id the caller wanted to get?

> + */
> +uint32_t
> +weston_layout_getIdOfSurface(struct weston_layout_surface *ivisurf);
> +
> +/**
> + * \brief get id of layer from weston_layout_layer
> + *
> + *
> + * \return 0 if the method call was successful
> + * \return -1 if the client can not call the method on the service.

Ditto.

> + */
> +uint32_t
> +weston_layout_getIdOfLayer(struct weston_layout_layer *ivilayer);
> +
> +/**
> + * \brief get weston_layout_layer from id of layer
> + *
> + * \return (struct weston_layout_layer *)
> + * if the method call was successful
> + * \return NULL if the client can not call the method on the service.

What does it mean that "the client can not call the method on the
service"? This is server code, not client code.

> + */
> +struct weston_layout_layer *
> +weston_layout_getLayerFromId(uint32_t id_layer);

...

> +/**
> + * \brief Set from which kind of devices the surface can accept input events.
> + * By default, a surface accept input events from all kind of devices (keyboards, pointer, ...)
> + * By calling this function, you can adjust surface preferences. Note that this function only
> + * adjust the acceptance for the specified devices. Non specified are keept untouched.
> + *
> + * Typicall use case for this function is when dealing with pointer or touch events.
> + * Those are normally dispatched to the first visible surface below the coordinate.
> + * If you want a different behavior (i.e. forward events to an other surface below the coordinate,
> + * you can set all above surfaces to refuse input events)
> + *
> + * \return 0 if the method call was successful
> + * \return -1 if the client can not call the method on the service.
> + */
> +int32_t
> +weston_layout_UpdateInputEventAcceptanceOn(struct weston_layout_surface *ivisurf,
> + uint32_t devices,
> + uint32_t acceptance);

Why this? Isn't the input region enough?

I would probably have lots of questions about all the API defined here,
but it would be too much effort to ask, explain and understand it all,
and I'm not even sure if it matters to Weston that much in the end.
Some of that effort would also we wasted, if you can merge this code
into ivi-shell.so instead of keeping it as a separate library.


Thanks,
pq
Nobuhiko Tanibata
2014-05-20 04:52:55 UTC
Permalink
Hi,

I apply review comments as v5 except following comments.

>> +
>> +struct link_layerPropertyNotification {
>> + layerPropertyNotificationFunc callback;
>> + void *userdata;
>> + struct wl_list link;
>> +};
>> +
>> +struct link_surfacePropertyNotification {
>> + surfacePropertyNotificationFunc callback;
>> + void *userdata;
>> + struct wl_list link;
>> +};
>> +
>> +struct link_layerCreateNotification {
>> + layerCreateNotificationFunc callback;
>> + void *userdata;
>> + struct wl_list link;
>> +};
>> +
>> +struct link_layerRemoveNotification {
>> + layerRemoveNotificationFunc callback;
>> + void *userdata;
>> + struct wl_list link;
>> +};
>> +
>> +struct link_surfaceCreateNotification {
>> + surfaceCreateNotificationFunc callback;
>> + void *userdata;
>> + struct wl_list link;
>> +};
>> +
>> +struct link_surfaceRemoveNotification {
>> + surfaceRemoveNotificationFunc callback;
>> + void *userdata;
>> + struct wl_list link;
>> +};
>> +
>> +struct link_surfaceConfigureNotification {
>> + surfaceConfigureNotificationFunc callback;
>> + void *userdata;
>> + struct wl_list link;
>> +};
>
> Any reason you defined all these different structs, and didn't use the
> wl_signal/wl_listener pattern?
>

I wants callback with some information. I think wl_signal/wl_listener
can not give such a information. So I keep this. However if there is an
another solution with wl_signal/wl_listener, I promise I would fix this
code.

>> +
>> +struct weston_layout;
>> +
>> +struct weston_layout_surface {
>> + struct wl_list link;
>
> For link members, I would personally prefer some indication of which
> (kind of) list the link will belong to, if possible and especially if
> there are multiple links in a struct.
>
>> + struct wl_list list_notification;
>> + struct wl_list list_layer;
>
> The Weston convention is to say "notification_list", "layer_list". I
> would also add a comment saying what link the list will hold, e.g.
> ... foo_list; /* struct weston_layout_layer::link */
> That explicitly says what the struct embedding the 'link' member is, as
> one list can only ever contain one type of objects, and explains how to
> access that object from a link pointer.
>
> Hmm... so one surface can be in multiple layers??

Yes. There is a use case to display a surface to several layer. E.g.
lane guidance can be shown in a small panel in cluster.

>
>> + uint32_t update_count;
>> + uint32_t id_surface;
>> +
>> + struct weston_layout *layout;
>> + struct weston_surface *surface;
>> + struct weston_view *view;
>
> Why have the view pointer explicitly here? Can't you access that via
> weston_surface?
>
>> +
>> + uint32_t buffer_width;
>> + uint32_t buffer_height;
>
> Would these perhaps happen to be the same as
> weston_surface::width_from_buffer and
> weston_surface::height_from_buffer?
>

I promise I will fix it soon.

>
> Do you handle at all the case of hotplugging outputs?
> Does the IVI software architecture simply not support any kind of
> hotplug?
>

No. there is no use case like hot plug.

>
> Error, or silently ignored?
> Do you plan to implement this function?
>
> There are a lot more similar functions which have the same "not
> supported" comment.
>
> ...

Yes. I will plan to support soon.


>
> All these unsigned members seem like they are calling for mismatching
> signed and unsigned variables in computations, which can lead to
> surprising bugs. Is there a reason why these coordinate related members
> (position and size) are unsigned?
>
> Weston code base and even Wayland protocol categorically uses signed
> integers for everything that is computed with, like size which can
> never be legally negative. Only flags, bitfields, object ids and such
> are unsigned, because they will never be used in computations that may
> include signed integers.
>

Yes. you are right. I have to modify many things. I promise I will fix
this next steps.

BR,
Nobuhiko
Nobuhiko Tanibata
2014-03-17 06:26:38 UTC
Permalink
In-Vehicle Infotainment system traditionally manages surfaces with global
identification. A protocol, ivi_application, supports such a feature by
implementing a request, ivi_application::surface_creation defined in
ivi_application.xml. Additionally, it initialize a library, weston-layout,
to manage properties of surfaces and group surfaces in layer. In detail,
refer library, weston_layout.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- apply review comments of mailing list.
- squash update of Makefile into this patch.
- move this patch after patch of weston-layout.
- support inherit propoerties of id_surface when client attaches another
wl_surface with id_surface after destroying ivi_surface once.

Changes for v3:
- squash internal method, configure, to ivi_shell_surface_configure.

Changes for v4:
- nothing. Version number aligned to the first patch

ivi-shell/Makefile.am | 24 +++-
ivi-shell/ivi-shell.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 337 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/ivi-shell.c

diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
index 4d54c2d..d0c0d62 100644
--- a/ivi-shell/Makefile.am
+++ b/ivi-shell/Makefile.am
@@ -1,7 +1,8 @@
moduledir = $(libdir)/weston

module_LTLIBRARIES = \
- $(libweston_layout)
+ $(libweston_layout) \
+ $(ivi_shell)

AM_CPPFLAGS = \
-I$(top_srcdir)/shared \
@@ -17,6 +18,7 @@ westoninclude_HEADERS =

if ENABLE_IVI_SHELL
westoninclude_HEADERS += \
+ ivi-application-client-protocol.h \
weston-layout.h

libweston_layout = libweston-layout.la
@@ -27,4 +29,24 @@ libweston_layout_la_SOURCES = \
weston-layout.c \
weston-layout.h

+ivi_shell = ivi-shell.la
+ivi_shell_la_LDFLAGS = -module -avoid-version
+ivi_shell_la_LIBADD = $(COMPOSITOR_LIBS) $(IVI_SHELL_LIBS) ./libweston-layout.la
+ivi_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(IVI_SHELL_CFLAGS)
+ivi_shell_la_SOURCES = \
+ ivi-shell.c \
+ weston-layout.h \
+ ivi-application-protocol.c \
+ ivi-application-server-protocol.h
+
endif
+
+BUILT_SOURCES = \
+ ivi-application-protocol.c \
+ ivi-application-server-protocol.h \
+ ivi-application-client-protocol.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+wayland_protocoldir = $(top_srcdir)/protocol
+include $(top_srcdir)/wayland-scanner.mk
diff --git a/ivi-shell/ivi-shell.c b/ivi-shell/ivi-shell.c
new file mode 100644
index 0000000..31d39cc
--- /dev/null
+++ b/ivi-shell/ivi-shell.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/**
+ * ivi-shell supports a type of shell for In-Vehicle Infotainment system.
+ * In-Vehicle Infotainment system traditionally manages surfaces with global
+ * identification. A protocol, ivi_application, supports such a feature
+ * by implementing a request, ivi_application::surface_creation defined in
+ * ivi_application.xml.
+ *
+ * Additionally, it initialize a library, weston-layout, to manage properties of
+ * surfaces and group surfaces in layer. In detail, refer weston_layout.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+
+#include "compositor.h"
+#include "ivi-application-server-protocol.h"
+#include "weston-layout.h"
+
+struct ivi_shell;
+
+struct ivi_shell_surface
+{
+ struct ivi_shell *shell;
+ struct weston_layout_surface *layout_surface;
+
+ struct weston_surface *surface;
+ uint32_t id_surface;
+
+ int32_t width;
+ int32_t height;
+
+ struct wl_list link;
+};
+
+struct ivi_shell
+{
+ struct wl_resource *resource;
+ struct wl_listener destroy_listener;
+
+ struct weston_compositor *compositor;
+
+ struct wl_list ivi_surface_list; /* struct ivi_shell_surface::link */
+};
+
+/* ------------------------------------------------------------------------- */
+/* common functions */
+/* ------------------------------------------------------------------------- */
+
+/**
+ * Implementation of ivi_surface
+ */
+
+static void
+ivi_shell_surface_configure(struct weston_surface *, int32_t, int32_t);
+
+static struct ivi_shell_surface *
+get_ivi_shell_surface(struct weston_surface *surface)
+{
+ if (surface->configure == ivi_shell_surface_configure) {
+ return surface->configure_private;
+ } else {
+ return NULL;
+ }
+}
+
+static void
+ivi_shell_surface_configure(struct weston_surface *es,
+ int32_t sx, int32_t sy)
+{
+ struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(es);
+ struct weston_view *view = NULL;
+ float from_x = 0.0f;
+ float from_y = 0.0f;
+ float to_x = 0.0f;
+ float to_y = 0.0f;
+
+ if ((es->width == 0) || (es->height == 0) || (ivisurf == NULL)) {
+ return;
+ }
+
+ view = weston_layout_get_weston_view(ivisurf->layout_surface);
+ if (view == NULL) {
+ return;
+ }
+
+ if (ivisurf->width != es->width || ivisurf->height != es->height) {
+
+ ivisurf->width = es->width;
+ ivisurf->height = es->height;
+
+ weston_view_to_global_float(view, 0, 0, &from_x, &from_y);
+ weston_view_to_global_float(view, sx, sy, &to_x, &to_y);
+
+ weston_view_set_position(view,
+ view->geometry.x + to_x - from_x,
+ view->geometry.y + to_y - from_y);
+ weston_view_update_transform(view);
+
+ weston_layout_surfaceConfigure(ivisurf->layout_surface, es->width, es->height);
+ }
+}
+
+static void
+surface_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource);
+
+ if (ivisurf != NULL) {
+ ivisurf->surface->configure = NULL;
+ ivisurf->surface->configure_private = NULL;
+ ivisurf->surface = NULL;
+ weston_layout_surfaceSetNativeContent(NULL, 0, 0, ivisurf->id_surface);
+ }
+
+ wl_resource_destroy(resource);
+}
+
+static const struct ivi_surface_interface surface_implementation = {
+ surface_destroy,
+};
+
+static struct ivi_shell_surface *
+is_surf_in_surfaces(struct wl_list *list_surf, uint32_t id_surface)
+{
+ struct ivi_shell_surface *ivisurf;
+
+ wl_list_for_each(ivisurf, list_surf, link) {
+ if (ivisurf->id_surface == id_surface) {
+ return ivisurf;
+ }
+ }
+
+ return NULL;
+}
+
+static const struct {
+ uint32_t warning_code; /* enum ivi_surface_warning_code */
+ const char *msg;
+} warning_strings[] = {
+ {IVI_SURFACE_WARNING_CODE_INVALID_WL_SURFACE, "wl_surface is invalid"},
+ {IVI_SURFACE_WARNING_CODE_SURFACE_ID_IN_USE, "surface_id is already assigned by another app"}
+};
+
+/**
+ * Implementation of ivi_application::surface_create.
+ * Creating new ivi_shell_surface with identification to identify the surface
+ * in the system.
+ */
+static void
+application_surface_create(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface,
+ struct wl_resource *surface_resource,
+ uint32_t id)
+{
+ struct ivi_shell *shell = wl_resource_get_user_data(resource);
+ struct ivi_shell_surface *ivisurf = NULL;
+ struct weston_layout_surface *layout_surface = NULL;
+ struct weston_surface *es = wl_resource_get_user_data(surface_resource);
+ struct wl_resource *res;
+ int32_t warn_idx = -1;
+
+ if (es != NULL) {
+ layout_surface = weston_layout_surfaceCreate(es, id_surface);
+ if (layout_surface == NULL)
+ warn_idx = 1;
+ } else {
+ warn_idx = 0;
+ }
+
+ res = wl_resource_create(client, &ivi_surface_interface, 1, id);
+ if (res == NULL) {
+ weston_log("couldn't get surface object");
+ return;
+ }
+
+ if (warn_idx >= 0) {
+ wl_resource_set_implementation(res, &surface_implementation,
+ NULL, NULL);
+ ivi_surface_send_warning(res,
+ warning_strings[warn_idx].warning_code,
+ warning_strings[warn_idx].msg);
+ return;
+ }
+
+ ivisurf = is_surf_in_surfaces(&shell->ivi_surface_list, id_surface);
+ if (ivisurf == NULL) {
+ ivisurf = calloc(1, sizeof *ivisurf);
+ if (ivisurf == NULL) {
+ weston_log("fails to allocate memory\n");
+ return;
+ }
+
+ wl_list_init(&ivisurf->link);
+ wl_list_insert(&shell->ivi_surface_list, &ivisurf->link);
+
+ ivisurf->shell = shell;
+ ivisurf->id_surface = id_surface;
+ }
+
+ ivisurf->width = 0;
+ ivisurf->height = 0;
+ ivisurf->layout_surface = layout_surface;
+ ivisurf->surface = es;
+
+ es->configure = ivi_shell_surface_configure;
+ es->configure_private = ivisurf;
+
+ wl_resource_set_implementation(res, &surface_implementation,
+ ivisurf, NULL);
+}
+
+static const struct ivi_application_interface application_implementation = {
+ application_surface_create
+};
+
+static void
+bind_ivi_application(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct ivi_shell *shell = data;
+ struct wl_resource *resource = NULL;
+
+ resource = wl_resource_create(client, &ivi_application_interface, 1, id);
+
+ wl_resource_set_implementation(resource,
+ &application_implementation,
+ shell, NULL);
+}
+
+/**
+ * Initialization/destruction method of ivi-shell
+ */
+static void
+shell_destroy(struct wl_listener *listener, void *data)
+{
+ struct ivi_shell *shell =
+ container_of(listener, struct ivi_shell, destroy_listener);
+ struct ivi_shell_surface *ivisurf, *next;
+
+ wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) {
+ wl_list_remove(&ivisurf->link);
+ free(ivisurf);
+ }
+
+ free(shell);
+}
+
+static void
+init_ivi_shell(struct weston_compositor *ec, struct ivi_shell *shell)
+{
+ shell->compositor = ec;
+
+ wl_list_init(&ec->layer_list);
+ wl_list_init(&shell->ivi_surface_list);
+}
+
+/**
+ * Initialization of ivi-shell. A library, weston_layout, is also initialized
+ * here by calling weston_layout_initWithCompositor.
+ *
+ */
+
+WL_EXPORT int
+module_init(struct weston_compositor *ec,
+ int *argc, char *argv[])
+{
+ struct ivi_shell *shell = NULL;
+
+ shell = calloc(1, sizeof *shell);
+ if (shell == NULL) {
+ return -1;
+ }
+
+ init_ivi_shell(ec, shell);
+ weston_layout_initWithCompositor(ec);
+
+ shell->destroy_listener.notify = shell_destroy;
+ wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
+
+ if (wl_global_create(ec->wl_display, &ivi_application_interface, 1,
+ shell, bind_ivi_application) == NULL) {
+ return -1;
+ }
+
+ return 0;
+}
--
1.8.3.1
Pekka Paalanen
2014-04-25 09:18:17 UTC
Permalink
Hi,

btw. pay attention to patch summaries (the email subject line). We use
a "component: description" format. Some examples:

"ivi application protocol:" ->
protocol: add ivi application extension

"The weston-layout library supports" ->
ivi-shell: add weston-layout library

"ivi-shell supports a type of shell for In-Vehicle Infotainment
system." ->
ivi-shell: add the shell plugin

etc.

Reading the weston git log should give an idea of how to write it.


On Mon, 17 Mar 2014 15:26:38 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> In-Vehicle Infotainment system traditionally manages surfaces with global
> identification. A protocol, ivi_application, supports such a feature by
> implementing a request, ivi_application::surface_creation defined in
> ivi_application.xml. Additionally, it initialize a library, weston-layout,
> to manage properties of surfaces and group surfaces in layer. In detail,
> refer library, weston_layout.
>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - apply review comments of mailing list.
> - squash update of Makefile into this patch.
> - move this patch after patch of weston-layout.
> - support inherit propoerties of id_surface when client attaches another
> wl_surface with id_surface after destroying ivi_surface once.
>
> Changes for v3:
> - squash internal method, configure, to ivi_shell_surface_configure.
>
> Changes for v4:
> - nothing. Version number aligned to the first patch
>
> ivi-shell/Makefile.am | 24 +++-
> ivi-shell/ivi-shell.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 337 insertions(+), 1 deletion(-)
> create mode 100644 ivi-shell/ivi-shell.c
>
> diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
> index 4d54c2d..d0c0d62 100644
> --- a/ivi-shell/Makefile.am
> +++ b/ivi-shell/Makefile.am
> @@ -1,7 +1,8 @@
> moduledir = $(libdir)/weston
>
> module_LTLIBRARIES = \
> - $(libweston_layout)
> + $(libweston_layout) \
> + $(ivi_shell)
>
> AM_CPPFLAGS = \
> -I$(top_srcdir)/shared \
> @@ -17,6 +18,7 @@ westoninclude_HEADERS =
>
> if ENABLE_IVI_SHELL
> westoninclude_HEADERS += \
> + ivi-application-client-protocol.h \

I'm not sure it makes sense to export the client protocol header,
because client programs do not get a library to link to for getting the
ivi-application-protocol.c part.

> weston-layout.h
>
> libweston_layout = libweston-layout.la
> @@ -27,4 +29,24 @@ libweston_layout_la_SOURCES = \
> weston-layout.c \
> weston-layout.h
>
> +ivi_shell = ivi-shell.la
> +ivi_shell_la_LDFLAGS = -module -avoid-version
> +ivi_shell_la_LIBADD = $(COMPOSITOR_LIBS) $(IVI_SHELL_LIBS) ./libweston-layout.la
> +ivi_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(IVI_SHELL_CFLAGS)
> +ivi_shell_la_SOURCES = \
> + ivi-shell.c \
> + weston-layout.h \

This is one more hint, that weston-layout.so should not be a library,
but a part of ivi-shell.so. You link the local build of
weston-layout.so into ivi-shell.so during the build.

Maybe you meant libweston-layout.la to be a convenience library instead?
Not sure that is needed either, nothing else will link to it I believe.
I think ivi-shell.so could export the weston-layout API just like the
weston executable exports the weston core API to plugins.

By all means do keep the code in weston-layout.c in a separate file if
you want, but weston-layout.h would be split into two files: one
private to ivi-shell.so, another the exported API for stuff like
ivi-controller.so. I think a sensible split between weston-layout.c and
ivi-shell.c would be based on ivi-shell.c handling mostly Weston core
callbacks, and weston-layout.c handling the public API.

There is the difference between static, non-static, and WL_EXPORT
symbols.

> + ivi-application-protocol.c \
> + ivi-application-server-protocol.h
> +
> endif
> +
> +BUILT_SOURCES = \
> + ivi-application-protocol.c \
> + ivi-application-server-protocol.h \
> + ivi-application-client-protocol.h
> +
> +CLEANFILES = $(BUILT_SOURCES)
> +
> +wayland_protocoldir = $(top_srcdir)/protocol
> +include $(top_srcdir)/wayland-scanner.mk
> diff --git a/ivi-shell/ivi-shell.c b/ivi-shell/ivi-shell.c
> new file mode 100644
> index 0000000..31d39cc
> --- /dev/null
> +++ b/ivi-shell/ivi-shell.c
> @@ -0,0 +1,314 @@
> +/*
> + * Copyright (C) 2013 DENSO CORPORATION
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission. The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose. It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +
> +/**
> + * ivi-shell supports a type of shell for In-Vehicle Infotainment system.
> + * In-Vehicle Infotainment system traditionally manages surfaces with global
> + * identification. A protocol, ivi_application, supports such a feature
> + * by implementing a request, ivi_application::surface_creation defined in
> + * ivi_application.xml.
> + *
> + * Additionally, it initialize a library, weston-layout, to manage properties of
> + * surfaces and group surfaces in layer. In detail, refer weston_layout.
> + */
> +
> +#include <sys/wait.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <linux/input.h>
> +
> +#include "compositor.h"
> +#include "ivi-application-server-protocol.h"
> +#include "weston-layout.h"
> +
> +struct ivi_shell;
> +
> +struct ivi_shell_surface
> +{
> + struct ivi_shell *shell;
> + struct weston_layout_surface *layout_surface;
> +
> + struct weston_surface *surface;
> + uint32_t id_surface;
> +
> + int32_t width;
> + int32_t height;
> +
> + struct wl_list link;
> +};
> +
> +struct ivi_shell
> +{
> + struct wl_resource *resource;
> + struct wl_listener destroy_listener;
> +
> + struct weston_compositor *compositor;
> +
> + struct wl_list ivi_surface_list; /* struct ivi_shell_surface::link */
> +};
> +
> +/* ------------------------------------------------------------------------- */
> +/* common functions */
> +/* ------------------------------------------------------------------------- */
> +
> +/**
> + * Implementation of ivi_surface
> + */
> +
> +static void
> +ivi_shell_surface_configure(struct weston_surface *, int32_t, int32_t);
> +
> +static struct ivi_shell_surface *
> +get_ivi_shell_surface(struct weston_surface *surface)
> +{
> + if (surface->configure == ivi_shell_surface_configure) {
> + return surface->configure_private;
> + } else {
> + return NULL;
> + }
> +}
> +
> +static void
> +ivi_shell_surface_configure(struct weston_surface *es,

Let's call it 'surface' or such in new code, 'es' is just cargo-cult.

> + int32_t sx, int32_t sy)
> +{
> + struct ivi_shell_surface *ivisurf = get_ivi_shell_surface(es);
> + struct weston_view *view = NULL;
> + float from_x = 0.0f;
> + float from_y = 0.0f;
> + float to_x = 0.0f;
> + float to_y = 0.0f;
> +
> + if ((es->width == 0) || (es->height == 0) || (ivisurf == NULL)) {
> + return;
> + }
> +
> + view = weston_layout_get_weston_view(ivisurf->layout_surface);
> + if (view == NULL) {
> + return;
> + }
> +
> + if (ivisurf->width != es->width || ivisurf->height != es->height) {
> +
> + ivisurf->width = es->width;
> + ivisurf->height = es->height;
> +
> + weston_view_to_global_float(view, 0, 0, &from_x, &from_y);
> + weston_view_to_global_float(view, sx, sy, &to_x, &to_y);
> +
> + weston_view_set_position(view,
> + view->geometry.x + to_x - from_x,
> + view->geometry.y + to_y - from_y);
> + weston_view_update_transform(view);
> +
> + weston_layout_surfaceConfigure(ivisurf->layout_surface, es->width, es->height);
> + }
> +}
> +
> +static void
> +surface_destroy(struct wl_client *client, struct wl_resource *resource)
> +{
> + struct ivi_shell_surface *ivisurf = wl_resource_get_user_data(resource);
> +
> + if (ivisurf != NULL) {
> + ivisurf->surface->configure = NULL;
> + ivisurf->surface->configure_private = NULL;
> + ivisurf->surface = NULL;
> + weston_layout_surfaceSetNativeContent(NULL, 0, 0, ivisurf->id_surface);
> + }
> +
> + wl_resource_destroy(resource);
> +}
> +
> +static const struct ivi_surface_interface surface_implementation = {
> + surface_destroy,
> +};
> +
> +static struct ivi_shell_surface *
> +is_surf_in_surfaces(struct wl_list *list_surf, uint32_t id_surface)
> +{
> + struct ivi_shell_surface *ivisurf;
> +
> + wl_list_for_each(ivisurf, list_surf, link) {
> + if (ivisurf->id_surface == id_surface) {
> + return ivisurf;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +static const struct {
> + uint32_t warning_code; /* enum ivi_surface_warning_code */
> + const char *msg;
> +} warning_strings[] = {
> + {IVI_SURFACE_WARNING_CODE_INVALID_WL_SURFACE, "wl_surface is invalid"},
> + {IVI_SURFACE_WARNING_CODE_SURFACE_ID_IN_USE, "surface_id is already assigned by another app"}
> +};
> +
> +/**
> + * Implementation of ivi_application::surface_create.
> + * Creating new ivi_shell_surface with identification to identify the surface
> + * in the system.
> + */
> +static void
> +application_surface_create(struct wl_client *client,
> + struct wl_resource *resource,
> + uint32_t id_surface,
> + struct wl_resource *surface_resource,
> + uint32_t id)
> +{
> + struct ivi_shell *shell = wl_resource_get_user_data(resource);
> + struct ivi_shell_surface *ivisurf = NULL;
> + struct weston_layout_surface *layout_surface = NULL;
> + struct weston_surface *es = wl_resource_get_user_data(surface_resource);
> + struct wl_resource *res;
> + int32_t warn_idx = -1;
> +
> + if (es != NULL) {
> + layout_surface = weston_layout_surfaceCreate(es, id_surface);
> + if (layout_surface == NULL)
> + warn_idx = 1;
> + } else {
> + warn_idx = 0;

I think this case would be a compositor internal error, not a client
error. Userdata of a surface resource should never be NULL. I.e.
assert() kind of thing would be more approriate.

> + }
> +
> + res = wl_resource_create(client, &ivi_surface_interface, 1, id);
> + if (res == NULL) {
> + weston_log("couldn't get surface object");

Use wl_resource_post_no_memory(ivi shell resource).

> + return;
> + }
> +
> + if (warn_idx >= 0) {
> + wl_resource_set_implementation(res, &surface_implementation,
> + NULL, NULL);
> + ivi_surface_send_warning(res,
> + warning_strings[warn_idx].warning_code,
> + warning_strings[warn_idx].msg);
> + return;
> + }
> +
> + ivisurf = is_surf_in_surfaces(&shell->ivi_surface_list, id_surface);
> + if (ivisurf == NULL) {
> + ivisurf = calloc(1, sizeof *ivisurf);

We now have zalloc() for this.

> + if (ivisurf == NULL) {
> + weston_log("fails to allocate memory\n");
> + return;
> + }
> +
> + wl_list_init(&ivisurf->link);
> + wl_list_insert(&shell->ivi_surface_list, &ivisurf->link);
> +
> + ivisurf->shell = shell;
> + ivisurf->id_surface = id_surface;
> + }
> +
> + ivisurf->width = 0;
> + ivisurf->height = 0;
> + ivisurf->layout_surface = layout_surface;

What is the benefit of having ivisurf and layout_surface separate?
Seem like you could just merge these, and simplify the code, on the
assumption that libweston-layout.so is specific to weston, no-one would
want to replace it without also replacing the ivi-shell.so, and hence
weston-layout is actually an implementation detail of ivi-shell.so for
exposing the API that ivi-controller.so expects.

> + ivisurf->surface = es;
> +
> + es->configure = ivi_shell_surface_configure;
> + es->configure_private = ivisurf;
> +
> + wl_resource_set_implementation(res, &surface_implementation,
> + ivisurf, NULL);
> +}
> +
> +static const struct ivi_application_interface application_implementation = {
> + application_surface_create
> +};
> +
> +static void
> +bind_ivi_application(struct wl_client *client,
> + void *data, uint32_t version, uint32_t id)
> +{
> + struct ivi_shell *shell = data;
> + struct wl_resource *resource = NULL;
> +
> + resource = wl_resource_create(client, &ivi_application_interface, 1, id);
> +
> + wl_resource_set_implementation(resource,
> + &application_implementation,
> + shell, NULL);
> +}
> +
> +/**
> + * Initialization/destruction method of ivi-shell
> + */
> +static void
> +shell_destroy(struct wl_listener *listener, void *data)
> +{
> + struct ivi_shell *shell =
> + container_of(listener, struct ivi_shell, destroy_listener);
> + struct ivi_shell_surface *ivisurf, *next;
> +
> + wl_list_for_each_safe(ivisurf, next, &shell->ivi_surface_list, link) {
> + wl_list_remove(&ivisurf->link);
> + free(ivisurf);
> + }
> +
> + free(shell);
> +}
> +
> +static void
> +init_ivi_shell(struct weston_compositor *ec, struct ivi_shell *shell)
> +{
> + shell->compositor = ec;
> +
> + wl_list_init(&ec->layer_list);
> + wl_list_init(&shell->ivi_surface_list);
> +}
> +
> +/**
> + * Initialization of ivi-shell. A library, weston_layout, is also initialized
> + * here by calling weston_layout_initWithCompositor.
> + *
> + */
> +
> +WL_EXPORT int
> +module_init(struct weston_compositor *ec,

'ec' is again cargo-cult, new code should prefer 'compositor'.

> + int *argc, char *argv[])
> +{
> + struct ivi_shell *shell = NULL;
> +
> + shell = calloc(1, sizeof *shell);
> + if (shell == NULL) {
> + return -1;
> + }
> +
> + init_ivi_shell(ec, shell);
> + weston_layout_initWithCompositor(ec);
> +
> + shell->destroy_listener.notify = shell_destroy;
> + wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
> +
> + if (wl_global_create(ec->wl_display, &ivi_application_interface, 1,
> + shell, bind_ivi_application) == NULL) {
> + return -1;
> + }

You are not setting compositor->shell_interface, but OTOH those are
only used for Xwayland, which probably doesn't make sense here.

> +
> + return 0;
> +}


Thanks,
pq
Nobuhiko Tanibata
2014-05-20 05:05:10 UTC
Permalink
Hi pq,

I applied your comments except for several ones,

>> + struct ivi_shell *shell = wl_resource_get_user_data(resource);
>> + struct ivi_shell_surface *ivisurf = NULL;
>> + struct weston_layout_surface *layout_surface = NULL;
>> + struct weston_surface *es =
>> wl_resource_get_user_data(surface_resource);
>> + struct wl_resource *res;
>> + int32_t warn_idx = -1;
>> +
>> + if (es != NULL) {
>> + layout_surface = weston_layout_surfaceCreate(es, id_surface);
>> + if (layout_surface == NULL)
>> + warn_idx = 1;
>> + } else {
>> + warn_idx = 0;
>
> I think this case would be a compositor internal error, not a client
> error. Userdata of a surface resource should never be NULL. I.e.
> assert() kind of thing would be more approriate.
>

I expect it would send warning to client. So I implement it like the
above.


>> + init_ivi_shell(ec, shell);
>> + weston_layout_initWithCompositor(ec);
>> +
>> + shell->destroy_listener.notify = shell_destroy;
>> + wl_signal_add(&ec->destroy_signal, &shell->destroy_listener);
>> +
>> + if (wl_global_create(ec->wl_display, &ivi_application_interface,
>> 1,
>> + shell, bind_ivi_application) == NULL) {
>> + return -1;
>> + }
>
> You are not setting compositor->shell_interface, but OTOH those are
> only used for Xwayland, which probably doesn't make sense here.

I was advised by kritian before it shall not support other shell in
ivi-shell at the same time.

BR,
Nobuhiko

>
>> +
>> + return 0;
>> +}
>
>
> Thanks,
> pq
Nobuhiko Tanibata
2014-03-17 06:27:46 UTC
Permalink
The reference protocol is used between hmi-controller and
hmi-controller-homescreen.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

protocol/Makefile.am | 3 +-
protocol/ivi-hmi-controller.xml | 105 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 107 insertions(+), 1 deletion(-)
create mode 100644 protocol/ivi-hmi-controller.xml

diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index 9913f16..140aef5 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -9,7 +9,8 @@ protocol_sources = \
wayland-test.xml \
xdg-shell.xml \
scaler.xml \
- ivi-application.xml
+ ivi-application.xml \
+ ivi-hmi-controller.xml

if HAVE_XMLLINT
.PHONY: validate
diff --git a/protocol/ivi-hmi-controller.xml b/protocol/ivi-hmi-controller.xml
new file mode 100644
index 0000000..04e22f4
--- /dev/null
+++ b/protocol/ivi-hmi-controller.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ivi_hmi_controller">
+
+ <copyright>
+ Copyright (C) 2013 DENSO CORPORATION
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ </copyright>
+
+ <interface name="ivi_hmi_controller" version="1">
+ <description summary="set up and control IVI style UI">
+ Currently it's possible to set up surface for background, panel,
+ buttons, and workspace.
+ </description>
+
+ <request name="set_background">
+ <description summary="set surface drawing background by surface ID"/>
+ <arg name="srf_id" type="uint"/>
+ </request>
+
+ <request name="set_panel">
+ <description summary="set surface drawing panel by surface ID"/>
+ <arg name="srf_id" type="uint"/>
+ </request>
+
+ <request name="set_button">
+ <description summary="set surface drawing button by surface ID">
+ Several buttons are regitered on panel by using arg; number.
+ </description>
+ <arg name="srf_id" type="uint"/>
+ <arg name="number" type="uint"/>
+ </request>
+
+ <request name="set_home_button">
+ <description summary="set surface drawing home button by surface ID"/>
+ <arg name="srf_id" type="uint"/>
+ </request>
+
+ <request name="set_workspacebackground">
+ <description summary="set surface drawing background of workspace by surface ID"/>
+ <arg name="srf_id" type="uint"/>
+ </request>
+
+ <request name="add_launchers">
+ <description summary="set a list of surface drawing launchers by a list of surface ID">
+ Per calling this request, a group of launchers are added.
+ </description>
+ <arg name="srf_ids" type="array"/>
+ <arg name="icon_size" type="uint"/>
+ </request>
+
+ <request name="workspace_control">
+ <description summary="start controlling workspace by server">
+ Give seat to the server to be controlled by server side.
+ </description>
+ <arg name="seat" type="object" interface="wl_seat"/>
+ <arg name="serial" type="uint"/>
+ </request>
+
+ <enum name="layout_mode">
+ <entry name="tiling" value="0"/>
+ <entry name="side_by_side" value="1"/>
+ <entry name="full_screen" value="2"/>
+ <entry name="random" value="3" />
+ </enum>
+
+ <request name="switch_mode">
+ <description summary="request mode switch of application layout"/>
+ <arg name="layout_mode" type="uint"/>
+ </request>
+
+ <enum name="home">
+ <entry name="off" value="0"/>
+ <entry name="on" value="1"/>
+ </enum>
+
+ <request name="home">
+ <description summary="request showing workspace or disable"/>
+ <arg name="home" type="uint"/>
+ </request>
+
+ <event name="workspace_end_control">
+ <description summary="notify controlling workspace end"/>
+ <arg name="is_controlled" type="int"/>
+ </event>
+
+ </interface>
+
+</protocol>
--
1.8.3.1
Pekka Paalanen
2014-04-25 09:46:57 UTC
Permalink
On Mon, 17 Mar 2014 15:27:46 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> The reference protocol is used between hmi-controller and
> hmi-controller-homescreen.

A one paragraph explanation on what hmi-controller and
hmi-controller-homescreen each are would be nice, maybe added to the
XML itself.

I'm a bit lost here now.

>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - squash Makefile to this patch
>
> Changes for v3 and v4
> - nothing. Version number aligned to the first patch
>
> protocol/Makefile.am | 3 +-
> protocol/ivi-hmi-controller.xml | 105 ++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 107 insertions(+), 1 deletion(-)
> create mode 100644 protocol/ivi-hmi-controller.xml
>
> diff --git a/protocol/Makefile.am b/protocol/Makefile.am
> index 9913f16..140aef5 100644
> --- a/protocol/Makefile.am
> +++ b/protocol/Makefile.am
> @@ -9,7 +9,8 @@ protocol_sources = \
> wayland-test.xml \
> xdg-shell.xml \
> scaler.xml \
> - ivi-application.xml
> + ivi-application.xml \
> + ivi-hmi-controller.xml
>
> if HAVE_XMLLINT
> .PHONY: validate
> diff --git a/protocol/ivi-hmi-controller.xml b/protocol/ivi-hmi-controller.xml
> new file mode 100644
> index 0000000..04e22f4
> --- /dev/null
> +++ b/protocol/ivi-hmi-controller.xml
> @@ -0,0 +1,105 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<protocol name="ivi_hmi_controller">
> +
> + <copyright>
> + Copyright (C) 2013 DENSO CORPORATION
> +
> + Permission is hereby granted, free of charge, to any person obtaining a copy
> + of this software and associated documentation files (the "Software"), to deal
> + in the Software without restriction, including without limitation the rights
> + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + copies of the Software, and to permit persons to whom the Software is
> + furnished to do so, subject to the following conditions:
> +
> + The above copyright notice and this permission notice shall be included in
> + all copies or substantial portions of the Software.
> +
> + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + THE SOFTWARE.
> + </copyright>
> +
> + <interface name="ivi_hmi_controller" version="1">
> + <description summary="set up and control IVI style UI">
> + Currently it's possible to set up surface for background, panel,
> + buttons, and workspace.
> + </description>
> +
> + <request name="set_background">
> + <description summary="set surface drawing background by surface ID"/>
> + <arg name="srf_id" type="uint"/>

It is highly unusual for a Wayland extension work by ids like this. Is
the intention that one client creates the surface with a known
surface_id, and then another client using this interface says, that
that surface_id is actually a background?

Weren't the surface_ids determined in advance during the system design
phase, and then hardcoded constants in the software? Wouldn't
ivi-shell.so just read these constants from a file, or even hardcode
them?

That is to say, I do not understand the purpose of this interface just
by looking at the protocol specification. I feel the specification
should explain it.

If this is an attempt to replicate some features of the desktop_shell
extension, why not just use wl_surface instead of uint?

> + </request>
> +
> + <request name="set_panel">
> + <description summary="set surface drawing panel by surface ID"/>
> + <arg name="srf_id" type="uint"/>

What happens, if several set_* requests are made with the same srf_id?
What if they are different set_* requests with the same srf_id?
Does srf_id need to have assigned a surface already, or can it be done
later?

> + </request>
> +
> + <request name="set_button">
> + <description summary="set surface drawing button by surface ID">
> + Several buttons are regitered on panel by using arg; number.
> + </description>
> + <arg name="srf_id" type="uint"/>
> + <arg name="number" type="uint"/>

What if the 'number' was already used?
What does 'number' mean, anyway?
What if a client uses an arbitrarily large or zero 'number'?

> + </request>
> +
> + <request name="set_home_button">
> + <description summary="set surface drawing home button by surface ID"/>
> + <arg name="srf_id" type="uint"/>
> + </request>
> +
> + <request name="set_workspacebackground">
> + <description summary="set surface drawing background of workspace by surface ID"/>
> + <arg name="srf_id" type="uint"/>

How do you know what size each surface should be?
Would you ever want to have output-specific assignments, like a
different background on each output?

> + </request>
> +
> + <request name="add_launchers">
> + <description summary="set a list of surface drawing launchers by a list of surface ID">
> + Per calling this request, a group of launchers are added.
> + </description>
> + <arg name="srf_ids" type="array"/>
> + <arg name="icon_size" type="uint"/>

What is icon_size doing here?
Is it a request for whatever is providing the surfaces associated to
srf_ids, that they should be of this size? Or is it a request for the
compositor to scale all these surfaces to that size?

> + </request>
> +
> + <request name="workspace_control">
> + <description summary="start controlling workspace by server">
> + Give seat to the server to be controlled by server side.
> + </description>
> + <arg name="seat" type="object" interface="wl_seat"/>
> + <arg name="serial" type="uint"/>

I cannot even guess what this does.

> + </request>
> +
> + <enum name="layout_mode">
> + <entry name="tiling" value="0"/>
> + <entry name="side_by_side" value="1"/>
> + <entry name="full_screen" value="2"/>
> + <entry name="random" value="3" />
> + </enum>
> +
> + <request name="switch_mode">
> + <description summary="request mode switch of application layout"/>
> + <arg name="layout_mode" type="uint"/>
> + </request>
> +
> + <enum name="home">
> + <entry name="off" value="0"/>
> + <entry name="on" value="1"/>
> + </enum>
> +
> + <request name="home">
> + <description summary="request showing workspace or disable"/>
> + <arg name="home" type="uint"/>

home? workspace? disable? ???

> + </request>
> +
> + <event name="workspace_end_control">
> + <description summary="notify controlling workspace end"/>
> + <arg name="is_controlled" type="int"/>

What?

> + </event>
> +
> + </interface>
> +
> +</protocol>

It seems I am missing the big picture here, the general idea of how
things should conceptually work. I think that could be part of the
extension's introduction documentation.


Thanks,
pq
Nobuhiko Tanibata
2014-05-20 05:10:38 UTC
Permalink
Hi pq,

I apply your comment in v5.

I remove several request because it can be handled without request by
identifying it by ivi_id.
I add description more as well.

BR,
Nobuhiko

2014-04-25 18:46 ? Pekka Paalanen ????????:
> On Mon, 17 Mar 2014 15:27:46 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> The reference protocol is used between hmi-controller and
>> hmi-controller-homescreen.
>
> A one paragraph explanation on what hmi-controller and
> hmi-controller-homescreen each are would be nice, maybe added to the
> XML itself.
>
> I'm a bit lost here now.
>
>>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2:
>> - squash Makefile to this patch
>>
>> Changes for v3 and v4
>> - nothing. Version number aligned to the first patch
>>
>> protocol/Makefile.am | 3 +-
>> protocol/ivi-hmi-controller.xml | 105
>> ++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 107 insertions(+), 1 deletion(-)
>> create mode 100644 protocol/ivi-hmi-controller.xml
>>
>> diff --git a/protocol/Makefile.am b/protocol/Makefile.am
>> index 9913f16..140aef5 100644
>> --- a/protocol/Makefile.am
>> +++ b/protocol/Makefile.am
>> @@ -9,7 +9,8 @@ protocol_sources = \
>> wayland-test.xml \
>> xdg-shell.xml \
>> scaler.xml \
>> - ivi-application.xml
>> + ivi-application.xml \
>> + ivi-hmi-controller.xml
>>
>> if HAVE_XMLLINT
>> .PHONY: validate
>> diff --git a/protocol/ivi-hmi-controller.xml
>> b/protocol/ivi-hmi-controller.xml
>> new file mode 100644
>> index 0000000..04e22f4
>> --- /dev/null
>> +++ b/protocol/ivi-hmi-controller.xml
>> @@ -0,0 +1,105 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<protocol name="ivi_hmi_controller">
>> +
>> + <copyright>
>> + Copyright (C) 2013 DENSO CORPORATION
>> +
>> + Permission is hereby granted, free of charge, to any person
>> obtaining a copy
>> + of this software and associated documentation files (the
>> "Software"), to deal
>> + in the Software without restriction, including without limitation
>> the rights
>> + to use, copy, modify, merge, publish, distribute, sublicense,
>> and/or sell
>> + copies of the Software, and to permit persons to whom the
>> Software is
>> + furnished to do so, subject to the following conditions:
>> +
>> + The above copyright notice and this permission notice shall be
>> included in
>> + all copies or substantial portions of the Software.
>> +
>> + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS OR
>> + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> MERCHANTABILITY,
>> + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
>> SHALL THE
>> + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> OTHER
>> + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> ARISING FROM,
>> + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> DEALINGS IN
>> + THE SOFTWARE.
>> + </copyright>
>> +
>> + <interface name="ivi_hmi_controller" version="1">
>> + <description summary="set up and control IVI style UI">
>> + Currently it's possible to set up surface for background,
>> panel,
>> + buttons, and workspace.
>> + </description>
>> +
>> + <request name="set_background">
>> + <description summary="set surface drawing background by
>> surface ID"/>
>> + <arg name="srf_id" type="uint"/>
>
> It is highly unusual for a Wayland extension work by ids like this. Is
> the intention that one client creates the surface with a known
> surface_id, and then another client using this interface says, that
> that surface_id is actually a background?
>
> Weren't the surface_ids determined in advance during the system design
> phase, and then hardcoded constants in the software? Wouldn't
> ivi-shell.so just read these constants from a file, or even hardcode
> them?
>
> That is to say, I do not understand the purpose of this interface just
> by looking at the protocol specification. I feel the specification
> should explain it.
>
> If this is an attempt to replicate some features of the desktop_shell
> extension, why not just use wl_surface instead of uint?
>
>> + </request>
>> +
>> + <request name="set_panel">
>> + <description summary="set surface drawing panel by
>> surface ID"/>
>> + <arg name="srf_id" type="uint"/>
>
> What happens, if several set_* requests are made with the same srf_id?
> What if they are different set_* requests with the same srf_id?
> Does srf_id need to have assigned a surface already, or can it be done
> later?
>
>> + </request>
>> +
>> + <request name="set_button">
>> + <description summary="set surface drawing button by
>> surface ID">
>> + Several buttons are regitered on panel by using arg;
>> number.
>> + </description>
>> + <arg name="srf_id" type="uint"/>
>> + <arg name="number" type="uint"/>
>
> What if the 'number' was already used?
> What does 'number' mean, anyway?
> What if a client uses an arbitrarily large or zero 'number'?
>
>> + </request>
>> +
>> + <request name="set_home_button">
>> + <description summary="set surface drawing home button by
>> surface ID"/>
>> + <arg name="srf_id" type="uint"/>
>> + </request>
>> +
>> + <request name="set_workspacebackground">
>> + <description summary="set surface drawing background of
>> workspace by surface ID"/>
>> + <arg name="srf_id" type="uint"/>
>
> How do you know what size each surface should be?
> Would you ever want to have output-specific assignments, like a
> different background on each output?
>
>> + </request>
>> +
>> + <request name="add_launchers">
>> + <description summary="set a list of surface drawing
>> launchers by a list of surface ID">
>> + Per calling this request, a group of launchers are
>> added.
>> + </description>
>> + <arg name="srf_ids" type="array"/>
>> + <arg name="icon_size" type="uint"/>
>
> What is icon_size doing here?
> Is it a request for whatever is providing the surfaces associated to
> srf_ids, that they should be of this size? Or is it a request for the
> compositor to scale all these surfaces to that size?
>
>> + </request>
>> +
>> + <request name="workspace_control">
>> + <description summary="start controlling workspace by
>> server">
>> + Give seat to the server to be controlled by server
>> side.
>> + </description>
>> + <arg name="seat" type="object" interface="wl_seat"/>
>> + <arg name="serial" type="uint"/>
>
> I cannot even guess what this does.
>
>> + </request>
>> +
>> + <enum name="layout_mode">
>> + <entry name="tiling" value="0"/>
>> + <entry name="side_by_side" value="1"/>
>> + <entry name="full_screen" value="2"/>
>> + <entry name="random" value="3" />
>> + </enum>
>> +
>> + <request name="switch_mode">
>> + <description summary="request mode switch of application
>> layout"/>
>> + <arg name="layout_mode" type="uint"/>
>> + </request>
>> +
>> + <enum name="home">
>> + <entry name="off" value="0"/>
>> + <entry name="on" value="1"/>
>> + </enum>
>> +
>> + <request name="home">
>> + <description summary="request showing workspace or
>> disable"/>
>> + <arg name="home" type="uint"/>
>
> home? workspace? disable? ???
>
>> + </request>
>> +
>> + <event name="workspace_end_control">
>> + <description summary="notify controlling workspace end"/>
>> + <arg name="is_controlled" type="int"/>
>
> What?
>
>> + </event>
>> +
>> + </interface>
>> +
>> +</protocol>
>
> It seems I am missing the big picture here, the general idea of how
> things should conceptually work. I think that could be part of the
> extension's introduction documentation.
>
>
> Thanks,
> pq
Nobuhiko Tanibata
2014-03-17 06:28:22 UTC
Permalink
The library is used to manage layout of surfaces/layers. Layout change is
triggered by ivi-hmi-controller protocol, ivi-hmi-controller.xml. A reference
how to use the protocol, see hmi-controller-homescreen.

In-Vehicle Infotainment system usually manage properties of surfaces/layers
by only a central component which decide where surfaces/layers shall be. This
reference show examples to implement the central component as a module of
weston.

Default Scene graph of UI is defined in hmi_controller_create. It consists of
- In the bottom, a base layer to group surfaces of background, panel,
and buttons
- Next, a application layer to show application surfaces.
- Workspace background layer to show a surface of background image.
- Workspace layer to show launcher to launch application with icons. Paths to
binary and icon are defined in weston.ini. The width of this layer is longer
than the size of screen because a workspace has several pages and is
controlled by motion of input.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

ivi-shell/.gitignore | 7 +
ivi-shell/Makefile.am | 19 +-
ivi-shell/hmi-controller.c | 1775 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1799 insertions(+), 2 deletions(-)
create mode 100644 ivi-shell/.gitignore
create mode 100644 ivi-shell/hmi-controller.c

diff --git a/ivi-shell/.gitignore b/ivi-shell/.gitignore
new file mode 100644
index 0000000..9f31bfd
--- /dev/null
+++ b/ivi-shell/.gitignore
@@ -0,0 +1,7 @@
+ivi-application-client-protocol.h
+ivi-application-protocol.c
+ivi-application-server-protocol.h
+ivi-hmi-controller-client-protocol.h
+ivi-hmi-controller-protocol.c
+ivi-hmi-controller-server-protocol.h
+weston.ini
diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
index d0c0d62..28589f8 100644
--- a/ivi-shell/Makefile.am
+++ b/ivi-shell/Makefile.am
@@ -2,7 +2,8 @@ moduledir = $(libdir)/weston

module_LTLIBRARIES = \
$(libweston_layout) \
- $(ivi_shell)
+ $(ivi_shell) \
+ $(hmi_controller)

AM_CPPFLAGS = \
-I$(top_srcdir)/shared \
@@ -39,12 +40,26 @@ ivi_shell_la_SOURCES = \
ivi-application-protocol.c \
ivi-application-server-protocol.h

+hmi_controller = hmi-controller.la
+hmi_controller_la_LDFLAGS = -module -avoid-version
+hmi_controller_la_LIBADD = $(CLIENT_LIBS) $(IVI_SHELL_LIBS) ./libweston-layout.la ../shared/libshared-cairo.la
+hmi_controller_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
+hmi_controller_la_SOURCES = \
+ hmi-controller.c \
+ ivi-application-protocol.c \
+ ivi-application-client-protocol.h \
+ ivi-hmi-controller-protocol.c \
+ ivi-hmi-controller-client-protocol.h \
+ ivi-hmi-controller-server-protocol.h
endif

BUILT_SOURCES = \
ivi-application-protocol.c \
ivi-application-server-protocol.h \
- ivi-application-client-protocol.h
+ ivi-application-client-protocol.h \
+ ivi-hmi-controller-protocol.c \
+ ivi-hmi-controller-client-protocol.h \
+ ivi-hmi-controller-server-protocol.h

CLEANFILES = $(BUILT_SOURCES)

diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
new file mode 100644
index 0000000..bd311ea
--- /dev/null
+++ b/ivi-shell/hmi-controller.c
@@ -0,0 +1,1775 @@
+/*
+ * Copyright (C) 2014 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * A reference implementation how to use weston-layout APIs in order to manage
+ * layout of surfaces/layers. Layout change is triggered by ivi-hmi-controller
+ * protocol, ivi-hmi-controller.xml. A reference how to use the protocol, see
+ * hmi-controller-homescreen.
+ *
+ * In-Vehicle Infotainment system usually manage properties of surfaces/layers
+ * by only a central component which decide where surfaces/layers shall be. This
+ * reference show examples to implement the central component as a module of weston.
+ *
+ * Default Scene graph of UI is defined in hmi_controller_create. It consists of
+ * - In the bottom, a base layer to group surfaces of background, panel,
+ * and buttons
+ * - Next, a application layer to show application surfaces.
+ * - Workspace background layer to show a surface of background image.
+ * - Workspace layer to show launcher to launch application with icons. Paths to
+ * binary and icon are defined in weston.ini. The width of this layer is longer
+ * than the size of screen because a workspace has several pages and is controlled
+ * by motion of input.
+ *
+ * TODO: animation method shall be refined
+ * TODO: support fade-in when UI is ready
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <assert.h>
+#include <time.h>
+
+#include "weston-layout.h"
+#include "ivi-hmi-controller-server-protocol.h"
+
+/*****************************************************************************
+ * structure, globals
+ ****************************************************************************/
+struct hmi_controller_layer {
+ struct weston_layout_layer *ivilayer;
+ uint32_t id_layer;
+ int32_t x;
+ int32_t y;
+ uint32_t width;
+ uint32_t height;
+};
+
+struct link_layer {
+ struct weston_layout_layer *layout_layer;
+ struct wl_list link;
+};
+
+struct link_animation {
+ struct hmi_controller_animation *animation;
+ struct wl_list link;
+};
+
+struct hmi_controller_animation;
+typedef void (*hmi_controller_animation_frame_func)(void *animation, uint32_t timestamp);
+typedef void (*hmi_controller_animation_frame_user_func)(void *animation);
+typedef void (*hmi_controller_animation_destroy_func)(struct hmi_controller_animation *animation);
+
+struct move_animation_user_data {
+ struct weston_layout_layer* layer;
+ struct animation_set *anima_set;
+ struct hmi_controller *hmi_ctrl;
+};
+
+struct hmi_controller_animation {
+ void *user_data;
+ uint32_t time_start;
+ uint32_t is_done;
+ hmi_controller_animation_frame_func frame_func;
+ hmi_controller_animation_frame_user_func frame_user_func;
+ hmi_controller_animation_destroy_func destroy_func;
+};
+
+struct hmi_controller_animation_fade {
+ struct hmi_controller_animation base;
+ double start;
+ double end;
+ struct weston_spring spring;
+};
+
+struct hmi_controller_animation_move {
+ struct hmi_controller_animation base;
+ double pos;
+ double pos_start;
+ double pos_end;
+ double v0;
+ double a;
+ double time_end;
+};
+
+struct hmi_controller_fade {
+ uint32_t isFadeIn;
+ struct hmi_controller_animation_fade *animation;
+ struct animation_set *anima_set;
+ struct wl_list layer_list;
+};
+
+struct animation_set {
+ struct wl_event_source *event_source;
+ struct wl_list animation_list;
+};
+
+struct
+hmi_server_setting {
+ uint32_t base_layer_id;
+ uint32_t application_layer_id;
+ uint32_t workspace_background_layer_id;
+ uint32_t workspace_layer_id;
+ uint32_t panel_height;
+};
+
+struct hmi_controller
+{
+ struct hmi_server_setting *hmi_setting;
+ struct hmi_controller_layer base_layer;
+ struct hmi_controller_layer application_layer;
+ struct hmi_controller_layer workspace_background_layer;
+ struct hmi_controller_layer workspace_layer;
+ enum ivi_hmi_controller_layout_mode layout_mode;
+
+ struct animation_set *anima_set;
+ struct hmi_controller_fade workspace_fade;
+ struct hmi_controller_animation_move *workspace_swipe_animation;
+ int32_t workspace_count;
+ struct wl_array ui_widgets;
+ int32_t is_initialized;
+};
+
+/*****************************************************************************
+ * local functions
+ ****************************************************************************/
+static void *
+fail_on_null(void *p, size_t size, char* file, int32_t line)
+{
+ if (size && !p) {
+ fprintf(stderr, "%s(%d) %zd: out of memory\n", file, line, size);
+ exit(EXIT_FAILURE);
+ }
+
+ return p;
+}
+
+static void *
+mem_alloc(size_t size, char* file, int32_t line)
+{
+ return fail_on_null(calloc(1, size), size, file, line);
+}
+
+#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
+
+static int32_t
+is_surf_in_uiWidget(struct hmi_controller *hmi_ctrl,
+ struct weston_layout_surface *ivisurf)
+{
+ uint32_t id = weston_layout_getIdOfSurface(ivisurf);
+
+ uint32_t *ui_widget_id = NULL;
+ wl_array_for_each (ui_widget_id, &hmi_ctrl->ui_widgets) {
+ if (*ui_widget_id == id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Internal methods called by mainly ivi_hmi_controller_switch_mode
+ * This reference shows 4 examples how to use weston_layout APIs.
+ */
+static void
+mode_divided_into_tiling(struct hmi_controller *hmi_ctrl,
+ weston_layout_surface_ptr *ppSurface,
+ uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const float surface_width = (float)layer->width * 0.25;
+ const float surface_height = (float)layer->height * 0.5;
+ int32_t surface_x = 0;
+ int32_t surface_y = 0;
+ struct weston_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ uint32_t num = 1;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ if (num <= 8) {
+ if (num < 5) {
+ surface_x = (int32_t)((num - 1) * (surface_width));
+ surface_y = 0;
+ }
+ else {
+ surface_x = (int32_t)((num - 5) * (surface_width));
+ surface_y = (int32_t)surface_height;
+ }
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf, surface_x, surface_y,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 0);
+ assert(!ret);
+ }
+}
+
+static void
+mode_divided_into_sidebyside(struct hmi_controller *hmi_ctrl,
+ weston_layout_surface_ptr *ppSurface,
+ uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ uint32_t surface_width = layer->width / 2;
+ uint32_t surface_height = layer->height;
+ struct weston_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ uint32_t num = 1;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ if (num == 1) {
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf, 0, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+ else if (num == 2) {
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf, surface_width, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ num++;
+ continue;
+ }
+
+ weston_layout_surfaceSetVisibility(ivisurf, 0);
+ assert(!ret);
+ }
+}
+
+static void
+mode_fullscreen_someone(struct hmi_controller *hmi_ctrl,
+ weston_layout_surface_ptr *ppSurface, uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const uint32_t surface_width = layer->width;
+ const uint32_t surface_height = layer->height;
+ struct weston_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf, 0, 0,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+ }
+}
+
+static void
+mode_random_replace(struct hmi_controller *hmi_ctrl,
+ weston_layout_surface_ptr *ppSurface, uint32_t surface_length,
+ struct hmi_controller_layer *layer)
+{
+ const uint32_t surface_width = (uint32_t)(layer->width * 0.25f);
+ const uint32_t surface_height = (uint32_t)(layer->height * 0.25f);
+ uint32_t surface_x = 0;
+ uint32_t surface_y = 0;
+ struct weston_layout_surface *ivisurf = NULL;
+ int32_t ret = 0;
+
+ uint32_t i = 0;
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ surface_x = rand() % (layer->width - surface_width);
+ surface_y = rand() % (layer->height - surface_height);
+
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf, surface_x, surface_y,
+ surface_width, surface_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+ }
+}
+
+static int32_t
+has_applicatipn_surface(struct hmi_controller *hmi_ctrl, weston_layout_surface_ptr *ppSurface,
+ uint32_t surface_length)
+{
+ struct weston_layout_surface *ivisurf = NULL;
+ uint32_t i = 0;
+
+ for (i = 0; i < surface_length; i++) {
+ ivisurf = ppSurface[i];
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ continue;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Supports 4 example to layout of application surfaces;
+ * tiling, side by side, fullscreen, and random.
+ */
+static void
+switch_mode(struct hmi_controller *hmi_ctrl,
+ enum ivi_hmi_controller_layout_mode layout_mode)
+{
+ if (!hmi_ctrl->is_initialized) {
+ return;
+ }
+
+ struct hmi_controller_layer *layer = &hmi_ctrl->application_layer;
+ weston_layout_surface_ptr *ppSurface = NULL;
+ uint32_t surface_length = 0;
+ int32_t ret = 0;
+
+ hmi_ctrl->layout_mode = layout_mode;
+
+ ret = weston_layout_getSurfaces(&surface_length, &ppSurface);
+ assert(!ret);
+
+ if (!has_applicatipn_surface(hmi_ctrl, ppSurface, surface_length)) {
+ free(ppSurface);
+ ppSurface = NULL;
+ return;
+ }
+
+ switch (layout_mode) {
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING:
+ mode_divided_into_tiling(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE:
+ mode_divided_into_sidebyside(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN:
+ mode_fullscreen_someone(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ case IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM:
+ mode_random_replace(hmi_ctrl, ppSurface, surface_length, layer);
+ break;
+ }
+
+ weston_layout_commitChanges();
+
+ free(ppSurface);
+ ppSurface = NULL;
+
+ return;
+}
+
+/**
+ * Internal method for animation
+ */
+static void
+hmi_controller_animation_frame(
+ struct hmi_controller_animation *animation, uint32_t timestamp)
+{
+ if (0 == animation->time_start) {
+ animation->time_start = timestamp;
+ }
+
+ animation->frame_func(animation, timestamp);
+ animation->frame_user_func(animation);
+}
+
+static int
+animation_set_do_anima(void* data)
+{
+ struct animation_set *anima_set = data;
+ uint32_t fps = 30;
+
+ if (wl_list_empty(&anima_set->animation_list)) {
+ wl_event_source_timer_update(anima_set->event_source, 0);
+ return 1;
+ }
+
+ wl_event_source_timer_update(anima_set->event_source, 1000 / fps);
+
+ struct timespec timestamp = {0};
+ clock_gettime(CLOCK_MONOTONIC, &timestamp);
+ uint32_t msec = (1e+3 * timestamp.tv_sec + 1e-6 * timestamp.tv_nsec);
+
+ struct link_animation *link_animation = NULL;
+ struct link_animation *next = NULL;
+
+ wl_list_for_each_safe(link_animation, next, &anima_set->animation_list, link) {
+ hmi_controller_animation_frame(link_animation->animation, msec);
+ }
+
+ weston_layout_commitChanges();
+ return 1;
+}
+
+static struct animation_set *
+animation_set_create(struct weston_compositor* ec)
+{
+ struct animation_set *anima_set = MEM_ALLOC(sizeof(*anima_set));
+
+ wl_list_init(&anima_set->animation_list);
+
+ struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
+ anima_set->event_source = wl_event_loop_add_timer(loop, animation_set_do_anima, anima_set);
+ wl_event_source_timer_update(anima_set->event_source, 0);
+
+ return anima_set;
+}
+
+static void
+animation_set_add_animation(struct animation_set *anima_set,
+ struct hmi_controller_animation *anima)
+{
+ struct link_animation *link_anima = NULL;
+
+ link_anima = MEM_ALLOC(sizeof(*link_anima));
+ if (NULL == link_anima) {
+ return;
+ }
+
+ link_anima->animation = anima;
+ wl_list_insert(&anima_set->animation_list, &link_anima->link);
+ wl_event_source_timer_update(anima_set->event_source, 1);
+}
+
+static void
+animation_set_remove_animation(struct animation_set *anima_set,
+ struct hmi_controller_animation *anima)
+{
+ struct link_animation *link_animation = NULL;
+ struct link_animation *next = NULL;
+
+ wl_list_for_each_safe(link_animation, next, &anima_set->animation_list, link) {
+ if (link_animation->animation == anima) {
+ wl_list_remove(&link_animation->link);
+ free(link_animation);
+ break;
+ }
+ }
+}
+
+static void
+hmi_controller_animation_spring_frame(
+ struct hmi_controller_animation_fade *animation, uint32_t timestamp)
+{
+ if (0 == animation->spring.timestamp) {
+ animation->spring.timestamp = timestamp;
+ }
+
+ weston_spring_update(&animation->spring, timestamp);
+ animation->base.is_done = weston_spring_done(&animation->spring);
+}
+
+static void
+hmi_controller_animation_move_frame(
+ struct hmi_controller_animation_move *animation, uint32_t timestamp)
+{
+ double s = animation->pos_start;
+ double t = timestamp - animation->base.time_start;
+ double v0 = animation->v0;
+ double a = animation->a;
+ double time_end = animation->time_end;
+
+ if (time_end <= t) {
+ animation->pos = animation->pos_end;
+ animation->base.is_done = 1;
+ } else {
+ animation->pos = v0 * t + 0.5 * a * t * t + s;
+ }
+}
+
+static void
+hmi_controller_animation_destroy(struct hmi_controller_animation *animation)
+{
+ if (animation->destroy_func) {
+ animation->destroy_func(animation);
+ }
+
+ free(animation);
+}
+
+static void
+hmi_controller_fade_animation_destroy(struct hmi_controller_animation *animation)
+{
+ struct hmi_controller_fade *fade = animation->user_data;
+ animation_set_remove_animation(fade->anima_set, animation);
+ fade->animation = NULL;
+ animation->user_data = NULL;
+}
+
+static struct hmi_controller_animation_fade *
+hmi_controller_animation_fade_create(double start, double end, double k,
+ hmi_controller_animation_frame_user_func frame_user_func, void* user_data,
+ hmi_controller_animation_destroy_func destroy_func)
+{
+ struct hmi_controller_animation_fade* animation = MEM_ALLOC(sizeof(*animation));
+
+ animation->base.frame_user_func = frame_user_func;
+ animation->base.user_data = user_data;
+ animation->base.frame_func =
+ (hmi_controller_animation_frame_func)hmi_controller_animation_spring_frame;
+ animation->base.destroy_func = destroy_func;
+
+ animation->start = start;
+ animation->end = end;
+ weston_spring_init(&animation->spring, k, start, end);
+ animation->spring.friction = 1400;
+ animation->spring.previous = -(end - start) * 0.03;
+
+ return animation;
+}
+
+static struct hmi_controller_animation_move *
+hmi_controller_animation_move_create(
+ double pos_start, double pos_end, double v_start, double v_end,
+ hmi_controller_animation_frame_user_func frame_user_func, void* user_data,
+ hmi_controller_animation_destroy_func destroy_func)
+{
+ struct hmi_controller_animation_move* animation = MEM_ALLOC(sizeof(*animation));
+
+ animation->base.frame_user_func = frame_user_func;
+ animation->base.user_data = user_data;
+ animation->base.frame_func =
+ (hmi_controller_animation_frame_func)hmi_controller_animation_move_frame;
+ animation->base.destroy_func = destroy_func;
+
+ animation->pos_start = pos_start;
+ animation->pos_end = pos_end;
+ animation->v0 = v_start;
+ animation->pos = pos_start;
+
+ double dx = (pos_end - pos_start);
+
+ if (1e-3 < fabs(dx)) {
+ animation->a = 0.5 * (v_end * v_end - v_start * v_start) / dx;
+ if (1e-6 < fabs(animation->a)) {
+ animation->time_end = (v_end - v_start) / animation->a;
+
+ } else {
+ animation->a = 0;
+ animation->time_end = fabs(dx / animation->v0);
+ }
+
+ } else {
+ animation->time_end = 0;
+ }
+
+ return animation;
+}
+
+static double
+hmi_controller_animation_fade_alpha_get(struct hmi_controller_animation_fade* animation)
+{
+ if (animation->spring.current > 0.999) {
+ return 1.0;
+ } else if (animation->spring.current < 0.001 ) {
+ return 0.0;
+ } else {
+ return animation->spring.current;
+ }
+}
+
+static uint32_t
+hmi_controller_animation_is_done(struct hmi_controller_animation *animation)
+{
+ return animation->is_done;
+}
+
+static void
+hmi_controller_fade_update(struct hmi_controller_animation_fade *animation, double end)
+{
+ animation->spring.target = end;
+}
+
+static void
+hmi_controller_anima_fade_user_frame(struct hmi_controller_animation_fade *animation)
+{
+ double alpha = hmi_controller_animation_fade_alpha_get(animation);
+ alpha = wl_fixed_from_double(alpha);
+ struct hmi_controller_fade *fade = animation->base.user_data;
+ struct link_layer *linklayer = NULL;
+ int32_t is_done = hmi_controller_animation_is_done(&animation->base);
+ int32_t is_visible = !is_done || fade->isFadeIn;
+
+ wl_list_for_each(linklayer, &fade->layer_list, link) {
+ weston_layout_layerSetOpacity(linklayer->layout_layer, alpha);
+ weston_layout_layerSetVisibility(linklayer->layout_layer, is_visible);
+ }
+
+ if (is_done) {
+ hmi_controller_animation_destroy(&animation->base);
+ }
+}
+
+static void
+hmi_controller_anima_move_user_frame(struct hmi_controller_animation_move *animation)
+{
+ struct move_animation_user_data* user_data = animation->base.user_data;
+ struct weston_layout_layer *layer = user_data->layer;
+ int32_t is_done = hmi_controller_animation_is_done(&animation->base);
+
+ int32_t pos[2] = {0};
+ weston_layout_layerGetPosition(layer, pos);
+
+ pos[0] = (int32_t)animation->pos;
+ weston_layout_layerSetPosition(layer, pos);
+
+ if (is_done) {
+ hmi_controller_animation_destroy(&animation->base);
+ }
+}
+
+static void
+hmi_controller_fade_run(uint32_t isFadeIn, struct hmi_controller_fade *fade)
+{
+ double tint = isFadeIn ? 1.0 : 0.0;
+ fade->isFadeIn = isFadeIn;
+
+ if (fade->animation) {
+ hmi_controller_fade_update(fade->animation, tint);
+ } else {
+ fade->animation = hmi_controller_animation_fade_create(
+ 1.0 - tint, tint, 300.0,
+ (hmi_controller_animation_frame_user_func)hmi_controller_anima_fade_user_frame,
+ fade, hmi_controller_fade_animation_destroy);
+
+ animation_set_add_animation(fade->anima_set, &fade->animation->base);
+ }
+}
+
+/**
+ * Internal method to create layer with hmi_controller_layer and add to a screen
+ */
+static void
+create_layer(struct weston_layout_screen *iviscrn,
+ struct hmi_controller_layer *layer)
+{
+ int32_t ret = 0;
+
+ layer->ivilayer = weston_layout_layerCreateWithDimension(layer->id_layer,
+ layer->width, layer->height);
+ assert(layer->ivilayer != NULL);
+
+ ret = weston_layout_screenAddLayer(iviscrn, layer->ivilayer);
+ assert(!ret);
+
+ ret = weston_layout_layerSetDestinationRectangle(layer->ivilayer, layer->x, layer->y,
+ layer->width, layer->height);
+ assert(!ret);
+
+ ret = weston_layout_layerSetVisibility(layer->ivilayer, 1);
+ assert(!ret);
+}
+
+/**
+ * Internal set notification
+ */
+static void
+set_notification_create_surface(struct weston_layout_surface *ivisurf,
+ void *userdata)
+{
+ struct hmi_controller* hmi_ctrl = userdata;
+ struct weston_layout_layer *application_layer = hmi_ctrl->application_layer.ivilayer;
+ int32_t ret = 0;
+
+ /* skip ui widgets */
+ if (is_surf_in_uiWidget(hmi_ctrl, ivisurf)) {
+ return;
+ }
+
+ ret = weston_layout_layerAddSurface(application_layer, ivisurf);
+ assert(!ret);
+}
+
+static void
+set_notification_remove_surface(struct weston_layout_surface *ivisurf,
+ void *userdata)
+{
+ (void)ivisurf;
+ struct hmi_controller* hmi_ctrl = userdata;
+ switch_mode(hmi_ctrl, hmi_ctrl->layout_mode);
+}
+
+static void
+set_notification_configure_surface(struct weston_layout_surface *ivisurf,
+ void *userdata)
+{
+ (void)ivisurf;
+ struct hmi_controller* hmi_ctrl = userdata;
+ switch_mode(hmi_ctrl, hmi_ctrl->layout_mode);
+}
+
+/**
+ * A hmi_controller used 4 layers to manage surfaces. The IDs of corresponding layer
+ * are defined in weston.ini. Default scene graph of layers are initialized in
+ * hmi_controller_create
+ */
+static struct hmi_server_setting *
+hmi_server_setting_create(void)
+{
+ struct hmi_server_setting* setting = MEM_ALLOC(sizeof(*setting));
+
+ struct weston_config *config = NULL;
+ config = weston_config_parse("weston.ini");
+
+ struct weston_config_section *shellSection = NULL;
+ shellSection = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ weston_config_section_get_uint(
+ shellSection, "base-layer-id", &setting->base_layer_id, 1000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-layer-id", &setting->workspace_background_layer_id, 2000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-layer-id", &setting->workspace_layer_id, 3000);
+
+ weston_config_section_get_uint(
+ shellSection, "application-layer-id", &setting->application_layer_id, 4000);
+
+ setting->panel_height = 70;
+
+ weston_config_destroy(config);
+
+ return setting;
+}
+
+/**
+ * This is a starting method called from module_init.
+ * This sets up scene graph of layers; base, application, workspace background,
+ * and workspace. These layers are created/added to screen in create_layer
+ *
+ * base: to group surfaces of panel and background
+ * application: to group surfaces of ivi_applications
+ * workspace background: to group a surface of background in workspace
+ * workspace: to group surfaces for launching ivi_applications
+ *
+ * Layers of workspace background and workspace is set to invisible at first.
+ * The properties of it is updated with animation when ivi_hmi_controller_home is
+ * requested.
+ */
+static struct hmi_controller *
+hmi_controller_create(struct weston_compositor *ec)
+{
+ weston_layout_screen_ptr *ppScreen = NULL;
+ struct weston_layout_screen *iviscrn = NULL;
+ uint32_t screen_length = 0;
+ uint32_t screen_width = 0;
+ uint32_t screen_height = 0;
+ int32_t ret = 0;
+ struct link_layer *tmp_link_layer = NULL;
+
+ struct hmi_controller *hmi_ctrl = MEM_ALLOC(sizeof(*hmi_ctrl));
+ wl_array_init(&hmi_ctrl->ui_widgets);
+ hmi_ctrl->layout_mode = IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING;
+ hmi_ctrl->hmi_setting = hmi_server_setting_create();
+
+ weston_layout_getScreens(&screen_length, &ppScreen);
+
+ iviscrn = ppScreen[0];
+
+ weston_layout_getScreenResolution(iviscrn, &screen_width, &screen_height);
+ assert(!ret);
+
+ /* init base layer*/
+ hmi_ctrl->base_layer.x = 0;
+ hmi_ctrl->base_layer.y = 0;
+ hmi_ctrl->base_layer.width = screen_width;
+ hmi_ctrl->base_layer.height = screen_height;
+ hmi_ctrl->base_layer.id_layer = hmi_ctrl->hmi_setting->base_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->base_layer);
+
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+
+
+ /* init application layer */
+ hmi_ctrl->application_layer.x = 0;
+ hmi_ctrl->application_layer.y = 0;
+ hmi_ctrl->application_layer.width = screen_width;
+ hmi_ctrl->application_layer.height = screen_height - panel_height;
+ hmi_ctrl->application_layer.id_layer = hmi_ctrl->hmi_setting->application_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->application_layer);
+
+ /* init workspace background layer */
+ hmi_ctrl->workspace_background_layer.x = 0;
+ hmi_ctrl->workspace_background_layer.y = 0;
+ hmi_ctrl->workspace_background_layer.width = screen_width;
+ hmi_ctrl->workspace_background_layer.height = screen_height - panel_height;
+
+ hmi_ctrl->workspace_background_layer.id_layer =
+ hmi_ctrl->hmi_setting->workspace_background_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->workspace_background_layer);
+ weston_layout_layerSetOpacity(hmi_ctrl->workspace_background_layer.ivilayer, 0);
+ weston_layout_layerSetVisibility(hmi_ctrl->workspace_background_layer.ivilayer, 0);
+
+ /* init workspace layer */
+ hmi_ctrl->workspace_layer.x = hmi_ctrl->workspace_background_layer.x;
+ hmi_ctrl->workspace_layer.y = hmi_ctrl->workspace_background_layer.y;
+ hmi_ctrl->workspace_layer.width = hmi_ctrl->workspace_background_layer.width;
+ hmi_ctrl->workspace_layer.height = hmi_ctrl->workspace_background_layer.height;
+ hmi_ctrl->workspace_layer.id_layer = hmi_ctrl->hmi_setting->workspace_layer_id;
+
+ create_layer(iviscrn, &hmi_ctrl->workspace_layer);
+ weston_layout_layerSetOpacity(hmi_ctrl->workspace_layer.ivilayer, 0);
+ weston_layout_layerSetVisibility(hmi_ctrl->workspace_layer.ivilayer, 0);
+
+ /* set up animation to workspace background and workspace */
+ hmi_ctrl->anima_set = animation_set_create(ec);
+
+ wl_list_init(&hmi_ctrl->workspace_fade.layer_list);
+ tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer));
+ tmp_link_layer->layout_layer = hmi_ctrl->workspace_layer.ivilayer;
+ wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, &tmp_link_layer->link);
+ tmp_link_layer = MEM_ALLOC(sizeof(*tmp_link_layer));
+ tmp_link_layer->layout_layer = hmi_ctrl->workspace_background_layer.ivilayer;
+ wl_list_insert(&hmi_ctrl->workspace_fade.layer_list, &tmp_link_layer->link);
+ hmi_ctrl->workspace_fade.anima_set = hmi_ctrl->anima_set;
+
+ weston_layout_setNotificationCreateSurface(set_notification_create_surface, hmi_ctrl);
+ weston_layout_setNotificationRemoveSurface(set_notification_remove_surface, hmi_ctrl);
+ weston_layout_setNotificationConfigureSurface(set_notification_configure_surface, hmi_ctrl);
+
+ free(ppScreen);
+ ppScreen = NULL;
+
+ return hmi_ctrl;
+}
+
+/**
+ * Implementations of ivi-hmi-controller.xml
+ */
+
+/**
+ * A surface drawing background is identified by id_surface.
+ * Properties of the surface is set by using weston_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_background(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface)
+
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const uint32_t dstx = hmi_ctrl->application_layer.x;
+ const uint32_t dsty = hmi_ctrl->application_layer.y;
+ const uint32_t width = hmi_ctrl->application_layer.width;
+ const uint32_t height = hmi_ctrl->application_layer.height;
+ uint32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = weston_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = weston_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf,
+ dstx, dsty, width, height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ weston_layout_commitChanges();
+}
+
+/**
+ * A surface drawing panel is identified by id_surface.
+ * Properties of the surface is set by using weston_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_panel(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const uint32_t width = hmi_ctrl->base_layer.width;
+ uint32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = weston_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = weston_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+ const uint32_t dstx = 0;
+ const uint32_t dsty = hmi_ctrl->base_layer.height - panel_height;
+
+ ret = weston_layout_surfaceSetDestinationRectangle(
+ ivisurf, dstx, dsty, width, panel_height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ weston_layout_commitChanges();
+}
+
+/**
+ * A surface drawing buttons in panel is identified by id_surface. It can set
+ * several buttons. Properties of the surface is set by using weston_layout
+ * APIs according to the scene graph of UI defined in hmi_controller_create.
+ * Additionally, the position of it is shifted to right when new one is requested.
+ *
+ * UI layer is used to add these surfaces.
+ */
+static void
+ivi_hmi_controller_set_button(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface, uint32_t number)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ const uint32_t width = 48;
+ const uint32_t height = 48;
+ uint32_t ret = 0;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = weston_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = weston_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+
+ const uint32_t dstx = (60 * number) + 15;
+ const uint32_t dsty = (hmi_ctrl->base_layer.height - panel_height) + 5;
+
+ ret = weston_layout_surfaceSetDestinationRectangle(
+ ivisurf,dstx, dsty, width, height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ weston_layout_commitChanges();
+}
+
+/**
+ * A surface drawing home button in panel is identified by id_surface.
+ * Properties of the surface is set by using weston_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * UI layer is used to add these surfaces.
+ */
+static void
+ivi_hmi_controller_set_home_button(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_layer *ivilayer = hmi_ctrl->base_layer.ivilayer;
+ uint32_t ret = 0;
+ uint32_t size = 48;
+ uint32_t panel_height = hmi_ctrl->hmi_setting->panel_height;
+ const uint32_t dstx = (hmi_ctrl->base_layer.width - size) / 2;
+ const uint32_t dsty = (hmi_ctrl->base_layer.height - panel_height) + 5;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ ivisurf = weston_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = weston_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetDestinationRectangle(
+ ivisurf, dstx, dsty, size, size);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ weston_layout_commitChanges();
+ hmi_ctrl->is_initialized = 1;
+}
+
+/**
+ * A surface drawing background of workspace is identified by id_surface.
+ * Properties of the surface is set by using weston_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * A layer of workspace_background is used to add this surface.
+ */
+static void
+ivi_hmi_controller_set_workspacebackground(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id_surface)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_surface *ivisurf = NULL;
+ struct weston_layout_layer *ivilayer = NULL;
+ ivilayer = hmi_ctrl->workspace_background_layer.ivilayer;
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = id_surface;
+
+ const uint32_t width = hmi_ctrl->workspace_background_layer.width;
+ const uint32_t height = hmi_ctrl->workspace_background_layer.height;
+ uint32_t ret = 0;
+
+ ivisurf = weston_layout_getSurfaceFromId(id_surface);
+ assert(ivisurf != NULL);
+
+ ret = weston_layout_layerAddSurface(ivilayer, ivisurf);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetDestinationRectangle(ivisurf,
+ 0, 0, width, height);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(ivisurf, 1);
+ assert(!ret);
+
+ weston_layout_commitChanges();
+}
+
+/**
+ * A list of surfaces drawing launchers in workspace is identified by id_surfaces.
+ * Properties of the surface is set by using weston_layout APIs according to
+ * the scene graph of UI defined in hmi_controller_create.
+ *
+ * The workspace can have several pages to group surfaces of launcher. Each call
+ * of this interface increments a number of page to add a group of surfaces
+ */
+static void
+ivi_hmi_controller_add_launchers(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_array *surface_ids,
+ uint32_t icon_size)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ uint32_t minspace_x = 10;
+ uint32_t minspace_y = minspace_x;
+
+ uint32_t width = hmi_ctrl->workspace_layer.width;
+ uint32_t height = hmi_ctrl->workspace_layer.height;
+
+ uint32_t x_count = (width - minspace_x) / (minspace_x + icon_size);
+ uint32_t space_x = (uint32_t)((width - x_count * icon_size) / (1.0 + x_count));
+ float fcell_size_x = icon_size + space_x;
+
+ uint32_t y_count = (height - minspace_y) / (minspace_y + icon_size);
+ uint32_t space_y = (uint32_t)((height - y_count * icon_size) / (1.0 + y_count));
+ float fcell_size_y = icon_size + space_y;
+
+ if (0 == x_count) {
+ x_count = 1;
+ }
+
+ if (0 == y_count) {
+ y_count = 1;
+ }
+
+ hmi_ctrl->workspace_count++;
+
+ uint32_t *surface_id = NULL;
+ uint32_t nx = 0;
+ uint32_t ny = 0;
+
+ wl_array_for_each(surface_id, surface_ids) {
+
+ uint32_t *add_surface_id = wl_array_add(&hmi_ctrl->ui_widgets,
+ sizeof(*add_surface_id));
+ *add_surface_id = *surface_id;
+
+ if (y_count == ny) {
+ ny = 0;
+ hmi_ctrl->workspace_count++;
+ }
+
+ uint32_t x = (uint32_t)(nx * fcell_size_x + (hmi_ctrl->workspace_count - 1) * width + space_x);
+ uint32_t y = (uint32_t)(ny * fcell_size_y + space_y) ;
+
+ struct weston_layout_surface* layout_surface = NULL;
+ layout_surface = weston_layout_getSurfaceFromId(*surface_id);
+ assert(layout_surface);
+
+ uint32_t ret = 0;
+ ret = weston_layout_layerAddSurface(layer, layout_surface);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetDestinationRectangle(
+ layout_surface, x, y, icon_size, icon_size);
+ assert(!ret);
+
+ ret = weston_layout_surfaceSetVisibility(layout_surface, 1);
+ assert(!ret);
+
+ nx++;
+
+ if (x_count == nx) {
+ ny++;
+ nx = 0;
+ }
+ }
+
+ weston_layout_commitChanges();
+}
+
+/**
+ * Implementation of request and event of ivi_hmi_controller_workspace_control
+ * and controlling workspace.
+ *
+ * When motion of input is detected in a surface of workspace background,
+ * ivi_hmi_controller_workspace_control shall be invoked and to start controlling of
+ * workspace. The workspace has several pages to show several groups of applications.
+ * The workspace is slid by using weston-layout to select a a page in layer_set_pos
+ * according to motion. When motion finished, e.g. touch up detected, control is
+ * terminated and event:ivi_hmi_controller_workspace_control is notified.
+ */
+struct pointer_grab {
+ struct weston_pointer_grab grab;
+ struct weston_layout_layer *layer;
+ struct wl_resource *resource;
+};
+
+struct touch_grab {
+ struct weston_touch_grab grab;
+ struct weston_layout_layer *layer;
+ struct wl_resource *resource;
+};
+
+struct move_grab {
+ wl_fixed_t dst[2];
+ wl_fixed_t rgn[2][2];
+ double v[2];
+ struct timespec start_time;
+ struct timespec pre_time;
+ wl_fixed_t start_pos[2];
+ wl_fixed_t pos[2];
+ int32_t is_moved;
+};
+
+struct pointer_move_grab {
+ struct pointer_grab base;
+ struct move_grab move;
+};
+
+struct touch_move_grab {
+ struct touch_grab base;
+ struct move_grab move;
+ int32_t is_active;
+};
+
+static void
+pointer_grab_start(struct pointer_grab *grab,
+ struct weston_layout_layer *layer,
+ const struct weston_pointer_grab_interface *interface,
+ struct weston_pointer *pointer)
+{
+ grab->grab.interface = interface;
+ grab->layer = layer;
+ weston_pointer_start_grab(pointer, &grab->grab);
+}
+
+static void
+touch_grab_start(struct touch_grab *grab,
+ struct weston_layout_layer *layer,
+ const struct weston_touch_grab_interface *interface,
+ struct weston_touch* touch)
+{
+ grab->grab.interface = interface;
+ grab->layer = layer;
+ weston_touch_start_grab(touch, &grab->grab);
+}
+
+static int32_t
+range_val(int32_t val, int32_t min, int32_t max)
+{
+ if (val < min) {
+ return min;
+ }
+
+ if (max < val) {
+ return max;
+ }
+
+ return val;
+}
+
+static void
+hmi_controller_move_animation_destroy(struct hmi_controller_animation *animation)
+{
+ struct move_animation_user_data *user_data = animation->user_data;
+ if (animation == &user_data->hmi_ctrl->workspace_swipe_animation->base) {
+ user_data->hmi_ctrl->workspace_swipe_animation = NULL;
+ }
+
+ animation_set_remove_animation(user_data->anima_set, animation);
+ free(animation->user_data);
+ animation->user_data = NULL;
+}
+
+static void
+move_workspace_grab_end(struct move_grab *move, struct wl_resource* resource,
+ wl_fixed_t grab_x, struct weston_layout_layer *layer)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ int32_t width = (int32_t)hmi_ctrl->workspace_background_layer.width;
+
+ struct timespec time = {0};
+ clock_gettime(CLOCK_MONOTONIC, &time);
+
+ double grab_time = 1e+3 * (time.tv_sec - move->start_time.tv_sec) +
+ 1e-6 * (time.tv_nsec - move->start_time.tv_nsec);
+
+ double from_motion_time = 1e+3 * (time.tv_sec - move->pre_time.tv_sec) +
+ 1e-6 * (time.tv_nsec - move->pre_time.tv_nsec);
+
+ double pointer_v = move->v[0];
+
+ if (200 < from_motion_time) {
+ pointer_v = 0.0;
+ }
+
+ int32_t is_flick = grab_time < 400 &&
+ 0.4 < fabs(pointer_v);
+
+ int32_t pos[2] = {0};
+ weston_layout_layerGetPosition(layer, pos);
+
+ int page_no = 0;
+
+ if (is_flick) {
+ int orgx = wl_fixed_to_int(move->dst[0] + grab_x);
+ page_no = (-orgx + width / 2) / width;
+
+ if (pointer_v < 0.0) {
+ page_no++;
+ }else {
+ page_no--;
+ }
+ }else {
+ page_no = (-pos[0] + width / 2) / width;
+ }
+
+ page_no = range_val(page_no, 0, hmi_ctrl->workspace_count - 1);
+ double end_pos = -page_no * width;
+
+ double dst = fabs(end_pos - pos[0]);
+ double max_time = 0.5 * 1e+3;
+ double v = dst / max_time;
+
+ double vmin = 1000 * 1e-3;
+ if (v < vmin ) {
+ v = vmin;
+ }
+
+ double v0 = 0.0;
+ if (pos[0] < end_pos) {
+ v0 = v;
+ } else {
+ v0 = -v;
+ }
+
+ struct move_animation_user_data *animation_user_data = NULL;
+ animation_user_data = MEM_ALLOC(sizeof(*animation_user_data));
+ animation_user_data->layer = layer;
+ animation_user_data->anima_set = hmi_ctrl->anima_set;
+ animation_user_data->hmi_ctrl = hmi_ctrl;
+
+ struct hmi_controller_animation_move* animation = NULL;
+ animation = hmi_controller_animation_move_create(
+ pos[0], end_pos, v0, v0,
+ (hmi_controller_animation_frame_user_func)hmi_controller_anima_move_user_frame,
+ animation_user_data, hmi_controller_move_animation_destroy);
+
+ hmi_ctrl->workspace_swipe_animation = animation;
+ animation_set_add_animation(hmi_ctrl->anima_set, &animation->base);
+
+ ivi_hmi_controller_send_workspace_end_control(resource, move->is_moved);
+}
+
+static void
+pointer_move_workspace_grab_end(struct pointer_grab *grab)
+{
+ struct pointer_move_grab *pnt_move_grab = (struct pointer_move_grab *) grab;
+ struct weston_layout_layer *layer = pnt_move_grab->base.layer;
+
+ move_workspace_grab_end(&pnt_move_grab->move, grab->resource,
+ grab->grab.pointer->grab_x, layer);
+
+ weston_pointer_end_grab(grab->grab.pointer);
+}
+
+static void
+touch_move_workspace_grab_end(struct touch_grab *grab)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *) grab;
+ struct weston_layout_layer *layer = tch_move_grab->base.layer;
+
+ move_workspace_grab_end(&tch_move_grab->move, grab->resource,
+ grab->grab.touch->grab_x, layer);
+
+ weston_touch_end_grab(grab->grab.touch);
+}
+
+static void
+pointer_noop_grab_focus(struct weston_pointer_grab *grab)
+{
+}
+
+static void
+move_grab_update(struct move_grab *move, wl_fixed_t pointer[2])
+{
+ struct timespec timestamp = {0};
+ clock_gettime(CLOCK_MONOTONIC, &timestamp);
+
+ double dt = (1e+3 * (timestamp.tv_sec - move->pre_time.tv_sec) +
+ 1e-6 * (timestamp.tv_nsec - move->pre_time.tv_nsec));
+
+ if (dt < 1e-6) {
+ dt = 1e-6;
+ }
+
+ move->pre_time = timestamp;
+
+ int32_t ii = 0;
+ for (ii = 0; ii < 2; ii++) {
+ wl_fixed_t prepos = move->pos[ii];
+ move->pos[ii] = pointer[ii] + move->dst[ii];
+
+ if (move->pos[ii] < move->rgn[0][ii]) {
+ move->pos[ii] = move->rgn[0][ii];
+ move->dst[ii] = move->pos[ii] - pointer[ii];
+ } else if (move->rgn[1][ii] < move->pos[ii]) {
+ move->pos[ii] = move->rgn[1][ii];
+ move->dst[ii] = move->pos[ii] - pointer[ii];
+ }
+
+ move->v[ii] = wl_fixed_to_double(move->pos[ii] - prepos) / dt;
+
+ if (!move->is_moved &&
+ 0 < wl_fixed_to_int(move->pos[ii] - move->start_pos[ii])) {
+ move->is_moved = 1;
+ }
+ }
+}
+
+static void
+layer_set_pos(struct weston_layout_layer *layer, wl_fixed_t pos[2])
+{
+ int32_t layout_pos[2] = {0};
+ layout_pos[0] = wl_fixed_to_int(pos[0]);
+ layout_pos[1] = wl_fixed_to_int(pos[1]);
+ weston_layout_layerSetPosition(layer, layout_pos);
+ weston_layout_commitChanges();
+}
+
+static void
+pointer_move_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ struct pointer_move_grab *pnt_move_grab = (struct pointer_move_grab *) grab;
+ wl_fixed_t pointer_pos[2] = {x, y};
+ move_grab_update(&pnt_move_grab->move, pointer_pos);
+ layer_set_pos(pnt_move_grab->base.layer, pnt_move_grab->move.pos);
+ weston_pointer_move(pnt_move_grab->base.grab.pointer, x, y);
+}
+
+static void
+touch_move_grab_motion(struct weston_touch_grab *grab, uint32_t time,
+ int touch_id, wl_fixed_t x, wl_fixed_t y)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *) grab;
+
+ if (!tch_move_grab->is_active) {
+ return;
+ }
+
+ wl_fixed_t pointer_pos[2] = {grab->touch->grab_x, grab->touch->grab_y};
+ move_grab_update(&tch_move_grab->move, pointer_pos);
+ layer_set_pos(tch_move_grab->base.layer, tch_move_grab->move.pos);
+}
+
+static void
+pointer_move_workspace_grab_button(struct weston_pointer_grab *grab,
+ uint32_t time, uint32_t button,
+ uint32_t state_w)
+{
+ if (BTN_LEFT == button &&
+ WL_POINTER_BUTTON_STATE_RELEASED == state_w) {
+ struct pointer_grab *pg = (struct pointer_grab *)grab;
+ pointer_move_workspace_grab_end(pg);
+ free(grab);
+ }
+}
+
+static void
+touch_nope_grab_down(struct weston_touch_grab *grab, uint32_t time,
+ int touch_id, wl_fixed_t sx, wl_fixed_t sy)
+{
+}
+
+static void
+touch_move_workspace_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id)
+{
+ struct touch_move_grab *tch_move_grab = (struct touch_move_grab *)grab;
+
+ if (0 == touch_id) {
+ tch_move_grab->is_active = 0;
+ }
+
+ if (0 == grab->touch->num_tp) {
+ touch_move_workspace_grab_end(&tch_move_grab->base);
+ free(grab);
+ }
+}
+
+static void
+pointer_move_workspace_grab_cancel(struct weston_pointer_grab *grab)
+{
+ struct pointer_grab *pg = (struct pointer_grab *)grab;
+ pointer_move_workspace_grab_end(pg);
+ free(grab);
+}
+
+static void
+touch_move_workspace_grab_cancel(struct weston_touch_grab *grab)
+{
+ struct touch_grab *tg = (struct touch_grab *)grab;
+ touch_move_workspace_grab_end(tg);
+ free(grab);
+}
+
+static const struct weston_pointer_grab_interface pointer_move_grab_workspace_interface = {
+ pointer_noop_grab_focus,
+ pointer_move_grab_motion,
+ pointer_move_workspace_grab_button,
+ pointer_move_workspace_grab_cancel
+};
+
+static const struct weston_touch_grab_interface touch_move_grab_workspace_interface = {
+ touch_nope_grab_down,
+ touch_move_workspace_grab_up,
+ touch_move_grab_motion,
+ touch_move_workspace_grab_cancel
+};
+
+enum HMI_GRAB_DEVICE
+{
+ HMI_GRAB_DEVICE_NONE,
+ HMI_GRAB_DEVICE_POINTER,
+ HMI_GRAB_DEVICE_TOUCH
+};
+
+static enum HMI_GRAB_DEVICE
+get_hmi_grab_device(struct weston_seat *seat, uint32_t serial)
+{
+ if (seat->pointer &&
+ seat->pointer->focus &&
+ seat->pointer->button_count &&
+ seat->pointer->grab_serial == serial) {
+ return HMI_GRAB_DEVICE_POINTER;
+ }
+
+ if (seat->touch &&
+ seat->touch->focus &&
+ seat->touch->grab_serial) {
+ return HMI_GRAB_DEVICE_TOUCH;
+ }
+
+ return HMI_GRAB_DEVICE_NONE;
+}
+
+static void
+move_grab_init(struct move_grab* move, wl_fixed_t start_pos[2],
+ wl_fixed_t grab_pos[2], wl_fixed_t rgn[2][2],
+ struct wl_resource* resource)
+{
+ clock_gettime(CLOCK_MONOTONIC, &move->start_time);
+ move->pre_time = move->start_time;
+ move->pos[0] = start_pos[0];
+ move->pos[1] = start_pos[1];
+ move->start_pos[0] = start_pos[0];
+ move->start_pos[1] = start_pos[1];
+ move->dst[0] = start_pos[0] - grab_pos[0];
+ move->dst[1] = start_pos[1] - grab_pos[1];
+ memcpy(move->rgn, rgn, sizeof(move->rgn));
+}
+
+static void
+move_grab_init_workspace(struct move_grab* move,
+ wl_fixed_t grab_x, wl_fixed_t grab_y,
+ struct wl_resource *resource)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ struct weston_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ int32_t workspace_count = hmi_ctrl->workspace_count;
+ int32_t workspace_width = hmi_ctrl->workspace_background_layer.width;
+ int32_t layer_pos[2] = {0};
+ weston_layout_layerGetPosition(layer, layer_pos);
+
+ wl_fixed_t start_pos[2] = {0};
+ start_pos[0] = wl_fixed_from_int(layer_pos[0]);
+ start_pos[1] = wl_fixed_from_int(layer_pos[1]);
+
+ wl_fixed_t rgn[2][2] = {{0}};
+ rgn[0][0] = wl_fixed_from_int(-workspace_width * (workspace_count - 1));
+
+ rgn[0][1] = wl_fixed_from_int(0);
+ rgn[1][0] = wl_fixed_from_int(0);
+ rgn[1][1] = wl_fixed_from_int(0);
+
+ wl_fixed_t grab_pos[2] = {grab_x, grab_y};
+
+ move_grab_init(move, start_pos, grab_pos, rgn, resource);
+}
+
+static struct pointer_move_grab *
+create_workspace_pointer_move(struct weston_pointer *pointer, struct wl_resource* resource)
+{
+ struct pointer_move_grab *pnt_move_grab = MEM_ALLOC(sizeof(*pnt_move_grab));
+ pnt_move_grab->base.resource = resource;
+ move_grab_init_workspace(&pnt_move_grab->move, pointer->grab_x, pointer->grab_y, resource);
+ return pnt_move_grab;
+}
+
+static struct touch_move_grab *
+create_workspace_touch_move(struct weston_touch *touch, struct wl_resource* resource)
+{
+ struct touch_move_grab *tch_move_grab = MEM_ALLOC(sizeof(*tch_move_grab));
+ tch_move_grab->base.resource = resource;
+ tch_move_grab->is_active = 1;
+ move_grab_init_workspace(&tch_move_grab->move, touch->grab_x,touch->grab_y, resource);
+ return tch_move_grab;
+}
+
+static void
+ivi_hmi_controller_workspace_control(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *seat_resource,
+ uint32_t serial)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+
+ if (hmi_ctrl->workspace_count < 2) {
+ return;
+ }
+
+ struct weston_seat* seat = wl_resource_get_user_data(seat_resource);
+ enum HMI_GRAB_DEVICE device = get_hmi_grab_device(seat, serial);
+
+ if (HMI_GRAB_DEVICE_POINTER != device &&
+ HMI_GRAB_DEVICE_TOUCH != device) {
+ return;
+ }
+
+ if (hmi_ctrl->workspace_swipe_animation) {
+ hmi_controller_animation_destroy(&hmi_ctrl->workspace_swipe_animation->base);
+ }
+
+ struct weston_layout_layer *layer = hmi_ctrl->workspace_layer.ivilayer;
+ struct pointer_move_grab *pnt_move_grab = NULL;
+ struct touch_move_grab *tch_move_grab = NULL;
+
+ switch (device) {
+ case HMI_GRAB_DEVICE_POINTER:
+ pnt_move_grab = create_workspace_pointer_move(seat->pointer, resource);
+
+ pointer_grab_start(
+ &pnt_move_grab->base, layer, &pointer_move_grab_workspace_interface,
+ seat->pointer);
+ break;
+
+ case HMI_GRAB_DEVICE_TOUCH:
+ tch_move_grab = create_workspace_touch_move(seat->touch, resource);
+
+ touch_grab_start(
+ &tch_move_grab->base, layer, &touch_move_grab_workspace_interface,
+ seat->touch);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * Implementation of switch_mode
+ */
+static void
+ivi_hmi_controller_switch_mode(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t layout_mode)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+ switch_mode(hmi_ctrl, layout_mode);
+}
+
+/**
+ * Implementation of on/off displaying workspace and workspace background layers.
+ */
+static void
+ivi_hmi_controller_home(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t home)
+{
+ struct hmi_controller *hmi_ctrl = wl_resource_get_user_data(resource);
+
+ if ((IVI_HMI_CONTROLLER_HOME_ON == home && !hmi_ctrl->workspace_fade.isFadeIn) ||
+ (IVI_HMI_CONTROLLER_HOME_OFF == home && hmi_ctrl->workspace_fade.isFadeIn)) {
+
+ uint32_t isFadeIn = !hmi_ctrl->workspace_fade.isFadeIn;
+ hmi_controller_fade_run(isFadeIn, &hmi_ctrl->workspace_fade);
+ }
+}
+
+/**
+ * binding ivi-hmi-controller implementation
+ */
+static const struct ivi_hmi_controller_interface ivi_hmi_controller_implementation = {
+ ivi_hmi_controller_set_background,
+ ivi_hmi_controller_set_panel,
+ ivi_hmi_controller_set_button,
+ ivi_hmi_controller_set_home_button,
+ ivi_hmi_controller_set_workspacebackground,
+ ivi_hmi_controller_add_launchers,
+ ivi_hmi_controller_workspace_control,
+ ivi_hmi_controller_switch_mode,
+ ivi_hmi_controller_home
+};
+
+static void
+unbind_hmi_controller(struct wl_resource *resource)
+{
+}
+
+static void
+bind_hmi_controller(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource = NULL;
+
+ resource = wl_resource_create(
+ client, &ivi_hmi_controller_interface, 1, id);
+
+ wl_resource_set_implementation(
+ resource, &ivi_hmi_controller_implementation,
+ data, unbind_hmi_controller);
+}
+
+static void
+launch_hmi_client(void *data)
+{
+ /*Nothing to do here*/
+}
+
+/*****************************************************************************
+ * exported functions
+ ****************************************************************************/
+
+WL_EXPORT int
+module_init(struct weston_compositor *ec,
+ int *argc, char *argv[])
+{
+ struct hmi_controller *hmi_ctrl = hmi_controller_create(ec);
+
+ if (wl_global_create(ec->wl_display,
+ &ivi_hmi_controller_interface, 1,
+ hmi_ctrl, bind_hmi_controller) == NULL) {
+ return -1;
+ }
+
+ struct wl_event_loop *loop = wl_display_get_event_loop(ec->wl_display);
+ wl_event_loop_add_idle(loop, launch_hmi_client, ec);
+
+ return 0;
+}
--
1.8.3.1
Pekka Paalanen
2014-04-25 11:38:23 UTC
Permalink
On Mon, 17 Mar 2014 15:28:22 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> The library is used to manage layout of surfaces/layers. Layout change is
> triggered by ivi-hmi-controller protocol, ivi-hmi-controller.xml. A reference
> how to use the protocol, see hmi-controller-homescreen.
>
> In-Vehicle Infotainment system usually manage properties of surfaces/layers
> by only a central component which decide where surfaces/layers shall be. This
> reference show examples to implement the central component as a module of
> weston.
>
> Default Scene graph of UI is defined in hmi_controller_create. It consists of
> - In the bottom, a base layer to group surfaces of background, panel,
> and buttons
> - Next, a application layer to show application surfaces.
> - Workspace background layer to show a surface of background image.
> - Workspace layer to show launcher to launch application with icons. Paths to
> binary and icon are defined in weston.ini. The width of this layer is longer
> than the size of screen because a workspace has several pages and is
> controlled by motion of input.
>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - squash Makefile to this patch
>
> Changes for v3 and v4
> - nothing. Version number aligned to the first patch
>
> ivi-shell/.gitignore | 7 +
> ivi-shell/Makefile.am | 19 +-
> ivi-shell/hmi-controller.c | 1775 ++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 1799 insertions(+), 2 deletions(-)
> create mode 100644 ivi-shell/.gitignore
> create mode 100644 ivi-shell/hmi-controller.c

Hi,

so this is the hmi-controller. This is the part that IVI vendors will
be customizing, is it? Or replacing, actually?

The picture in your PDF has both ivi-controller.so and
hmi-controller.so, where the ivi-controller.so is exposing the
ivi-controller Wayland extension. These will be exclusive, right? Never
used at the same time.

hmi-controller.so exposes the ivi_hmi_controller private Wayland
protocol extension, right? So this patch series does not yet have the
ivi-controller part at all, and ivi_hmi_controller is just a part of
the demo that is hmi-controller et al.? And all that would be replaced
by a "real" IVI thing?

Oh yeah, you said the ivi-controller stuff is at
http://git.projects.genivi.org/?p=wayland-ivi-extension.git;a=summary

Okay, I'm actually happy that part is not in this patch series, the
protocol extension looks huge. ;-)

I'm not going through this patch too carefully, just making some general
observations.

There are lots of stuff using the weston-layout API, but I see also a
lot stuff using Weston core API like the grab handlers and seat stuff.
Since this is the part that vendors replace, would it not be better to
have the Weston core related stuff back in ivi-shell.so?

Or is the stuff used here such, that a real ivi-controller will not
need it?

Or is it just a work in progress to establish an abstraction and that
part is still to do?

How independent of a particular compositor implementation is the so
called weston-layout abstraction supposed to be? Will it evolve into a
completely compositor-agnostic API?

I am just trying to understand what exactly the API surface is, that
external modules like ivi-controller.so will be using. Are they allowed
to use Weston core API, ivi-shell.so exported API, only weston-layout
API?

I said it before, that I think you should pay attention to proper
versioning of the weston-layout API, or tie that to Weston core
versioning.

Again, I would suggest:
- document what APIs the external modules can use
- write a header for the API that ivi-shell.so will export for the
external modules; this would replace the weston-layout.h and be
smaller
- let ivi-shell.so export the above mentioned API, so you get rid of
the library interfaces between libweston-layout and ivi-shell; just
merge the code and remove everything that falls out by refactoring

That would mean external modules used libwayland-server, weston core(?),
and the ivi-shell.so exported APIs, and not additionally depending on
yet another library libweston-layout.so.

I don't think you currently export any API from ivi-shell.so, but
external modules still depend on it anyway, by relying on it using
libweston-layout.so properly. I think it would be good to make this
dependency explicit.

What do you think?
I believe it should work.


Thanks,
pq
Nobuhiko Tanibata
2014-05-20 09:57:46 UTC
Permalink
2014-04-25 20:38 ? Pekka Paalanen ????????:
> On Mon, 17 Mar 2014 15:28:22 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> The library is used to manage layout of surfaces/layers. Layout change
>> is
>> triggered by ivi-hmi-controller protocol, ivi-hmi-controller.xml. A
>> reference
>> how to use the protocol, see hmi-controller-homescreen.
>>
>> In-Vehicle Infotainment system usually manage properties of
>> surfaces/layers
>> by only a central component which decide where surfaces/layers shall
>> be. This
>> reference show examples to implement the central component as a module
>> of
>> weston.
>>
>> Default Scene graph of UI is defined in hmi_controller_create. It
>> consists of
>> - In the bottom, a base layer to group surfaces of background, panel,
>> and buttons
>> - Next, a application layer to show application surfaces.
>> - Workspace background layer to show a surface of background image.
>> - Workspace layer to show launcher to launch application with icons.
>> Paths to
>> binary and icon are defined in weston.ini. The width of this layer
>> is longer
>> than the size of screen because a workspace has several pages and is
>> controlled by motion of input.
>>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2:
>> - squash Makefile to this patch
>>
>> Changes for v3 and v4
>> - nothing. Version number aligned to the first patch
>>
>> ivi-shell/.gitignore | 7 +
>> ivi-shell/Makefile.am | 19 +-
>> ivi-shell/hmi-controller.c | 1775
>> ++++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 1799 insertions(+), 2 deletions(-)
>> create mode 100644 ivi-shell/.gitignore
>> create mode 100644 ivi-shell/hmi-controller.c
>
> Hi,
>
> so this is the hmi-controller. This is the part that IVI vendors will
> be customizing, is it? Or replacing, actually?

Yes. You are right. hmi-controller is just a reference how to use
ivi-layout APIs. Each IVI vendors shall customize it or implement the
same part from scratch to realize its business logic.
>
> The picture in your PDF has both ivi-controller.so and
> hmi-controller.so, where the ivi-controller.so is exposing the
> ivi-controller Wayland extension. These will be exclusive, right? Never
> used at the same time.

It depends on vendor use case. If vendor want to use ivi-controller.so
for debugging to retrieve properties of surface. it can be used with it.
However basically, these will be exclusive.
>
> hmi-controller.so exposes the ivi_hmi_controller private Wayland
> protocol extension, right? So this patch series does not yet have the
> ivi-controller part at all, and ivi_hmi_controller is just a part of
> the demo that is hmi-controller et al.? And all that would be replaced
> by a "real" IVI thing?

Yes. it would be replaced.

>
> Oh yeah, you said the ivi-controller stuff is at
> http://git.projects.genivi.org/?p=wayland-ivi-extension.git;a=summary
>
> Okay, I'm actually happy that part is not in this patch series, the
> protocol extension looks huge. ;-)
>
> I'm not going through this patch too carefully, just making some
> general
> observations.

General observation is fine.

>
> There are lots of stuff using the weston-layout API, but I see also a
> lot stuff using Weston core API like the grab handlers and seat stuff.
> Since this is the part that vendors replace, would it not be better to
> have the Weston core related stuff back in ivi-shell.so?
>
> Or is the stuff used here such, that a real ivi-controller will not
> need it?
>
> Or is it just a work in progress to establish an abstraction and that
> part is still to do?

It is in progress. however grab handlers and seat stuff can be used as
Weston core API is.
The motivation of this parts is that,
view class is a little difficult for traditional IVI user who implement
its UI controll by using layout APIs. So I would like to abstract such a
APIs at first.

>
> How independent of a particular compositor implementation is the so
> called weston-layout abstraction supposed to be? Will it evolve into a
> completely compositor-agnostic API?

Compositor is independent from ivi-layout APIs. Because it is
implemented by using weston view. If weston view is independent on
compositor, e.g. drm or x11. ivi-layout API can works with any
compositor.
>
> I am just trying to understand what exactly the API surface is, that
> external modules like ivi-controller.so will be using. Are they allowed
> to use Weston core API, ivi-shell.so exported API, only weston-layout
> API?
>
> I said it before, that I think you should pay attention to proper
> versioning of the weston-layout API, or tie that to Weston core
> versioning.
>
> Again, I would suggest:
> - document what APIs the external modules can use
> - write a header for the API that ivi-shell.so will export for the
> external modules; this would replace the weston-layout.h and be
> smaller

Thank you for comments.

I prepare ivi-layout-export.h with description per API in v5.

> - let ivi-shell.so export the above mentioned API, so you get rid of
> the library interfaces between libweston-layout and ivi-shell; just
> merge the code and remove everything that falls out by refactoring

Basically, I tried to follow your comment. However according to current
implementation
of weston, ivi-shell is loaded by dlopen without RTLD_GLOBAL. So to add
ivi-layout APIs,
I prepare ivi-layout.so as module to be loaded with RTLD_GLOBAL on
ivi-shell.
The name of "ivi-layout.so" is fixed string in ivi-shell.

>
> That would mean external modules used libwayland-server, weston
> core(?),
> and the ivi-shell.so exported APIs, and not additionally depending on
> yet another library libweston-layout.so.
>
> I don't think you currently export any API from ivi-shell.so, but
> external modules still depend on it anyway, by relying on it using
> libweston-layout.so properly. I think it would be good to make this
> dependency explicit.

Thanks.
I added key: "ivi-module" in weston.ini.in to explicitly say that
modules depends on ivi-shell and ivi-layout APIs.

BR,
Nobohiko

>
> What do you think?
> I believe it should work.
>
>
> Thanks,
> pq
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Nobuhiko Tanibata
2014-03-17 06:28:55 UTC
Permalink
This is launched from hmi-controller by using hmi_client_start and create a
pthread.

The basic flow is as followed,
1/ create pthread
2/ read configuration from weston.ini.
3/ draw png file to surface according to configuration of weston.ini
4/ set up UI by using ivi-hmi-controller protocol
5/ Enter event loop
6/ If a surface receives touch/pointer event, followings are invoked according
to type of event and surface
6-1/ If a surface to launch ivi_application receive touch up, it execs
ivi-application configured in weston.ini.
6-2/ If a surface to switch layout mode receive touch up, it sends a request,
ivi_hmi_controller_switch_mode, to hmi-controller.
6-3/ If a surface to show workspace having launchers, it sends a request,
ivi_hmi_controller_home, to hmi-controller.
6-4/ If touch down events happens in workspace,
ivi_hmi_controller_workspace_control is sent to slide workspace.
When control finished, event: ivi_hmi_controller_workspace_end_control
is received.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

ivi-shell/Makefile.am | 2 +
ivi-shell/hmi-controller-homescreen.c | 1370 +++++++++++++++++++++++++++++++++
ivi-shell/hmi-controller-homescreen.h | 36 +
ivi-shell/hmi-controller.c | 3 +-
4 files changed, 1410 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/hmi-controller-homescreen.c
create mode 100644 ivi-shell/hmi-controller-homescreen.h

diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
index 28589f8..afaa5e3 100644
--- a/ivi-shell/Makefile.am
+++ b/ivi-shell/Makefile.am
@@ -46,6 +46,8 @@ hmi_controller_la_LIBADD = $(CLIENT_LIBS) $(IVI_SHELL_LIBS) ./libweston-layout.l
hmi_controller_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
hmi_controller_la_SOURCES = \
hmi-controller.c \
+ hmi-controller-homescreen.h \
+ hmi-controller-homescreen.c \
ivi-application-protocol.c \
ivi-application-client-protocol.h \
ivi-hmi-controller-protocol.c \
diff --git a/ivi-shell/hmi-controller-homescreen.c b/ivi-shell/hmi-controller-homescreen.c
new file mode 100644
index 0000000..51f6c75
--- /dev/null
+++ b/ivi-shell/hmi-controller-homescreen.c
@@ -0,0 +1,1370 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <wayland-cursor.h>
+#include "hmi-controller-homescreen.h"
+#include "../shared/cairo-util.h"
+#include "../shared/config-parser.h"
+#include "ivi-application-client-protocol.h"
+#include "ivi-hmi-controller-client-protocol.h"
+
+/**
+ * A reference implementation how to use ivi-hmi-controller interface to interact
+ * with hmi-controller. This is launched from hmi-controller by using
+ * hmi_client_start and create a pthread.
+ *
+ * The basic flow is as followed,
+ * 1/ create pthread
+ * 2/ read configuration from weston.ini.
+ * 3/ draw png file to surface according to configuration of weston.ini
+ * 4/ set up UI by using ivi-hmi-controller protocol
+ * 5/ Enter event loop
+ * 6/ If a surface receives touch/pointer event, followings are invoked according
+ * to type of event and surface
+ * 6-1/ If a surface to launch ivi_application receive touch up, it execs
+ * ivi-application configured in weston.ini.
+ * 6-2/ If a surface to switch layout mode receive touch up, it sends a request,
+ * ivi_hmi_controller_switch_mode, to hmi-controller.
+ * 6-3/ If a surface to show workspace having launchers, it sends a request,
+ * ivi_hmi_controller_home, to hmi-controller.
+ * 6-4/ If touch down events happens in workspace,
+ * ivi_hmi_controller_workspace_control is sent to slide workspace.
+ * When control finished, event: ivi_hmi_controller_workspace_end_control
+ * is received.
+ */
+
+/*****************************************************************************
+ * structure, globals
+ ****************************************************************************/
+enum cursor_type {
+ CURSOR_BOTTOM_LEFT,
+ CURSOR_BOTTOM_RIGHT,
+ CURSOR_BOTTOM,
+ CURSOR_DRAGGING,
+ CURSOR_LEFT_PTR,
+ CURSOR_LEFT,
+ CURSOR_RIGHT,
+ CURSOR_TOP_LEFT,
+ CURSOR_TOP_RIGHT,
+ CURSOR_TOP,
+ CURSOR_IBEAM,
+ CURSOR_HAND1,
+ CURSOR_WATCH,
+
+ CURSOR_BLANK
+};
+struct wlContextCommon {
+ struct wl_display *wlDisplay;
+ struct wl_registry *wlRegistry;
+ struct wl_compositor *wlCompositor;
+ struct wl_shm *wlShm;
+ struct wl_seat *wlSeat;
+ struct wl_pointer *wlPointer;
+ struct wl_touch *wlTouch;
+ struct ivi_application *iviApplication;
+ struct ivi_hmi_controller *hmiCtrl;
+ struct hmi_homescreen_setting *hmi_setting;
+ struct wl_list *list_wlContextStruct;
+ struct wl_surface *enterSurface;
+ int32_t is_home_on;
+ struct wl_cursor_theme *cursor_theme;
+ struct wl_cursor **cursors;
+ struct wl_surface *pointer_surface;
+ enum cursor_type current_cursor;
+ uint32_t enter_serial;
+};
+
+struct wlContextStruct {
+ struct wlContextCommon cmm;
+ struct wl_surface *wlSurface;
+ struct wl_buffer *wlBuffer;
+ uint32_t formats;
+ cairo_surface_t *ctx_image;
+ void *data;
+ uint32_t id_surface;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_srf {
+ uint32_t id;
+ char *filePath;
+ uint32_t color;
+};
+
+struct
+hmi_homescreen_workspace {
+ struct wl_array launcher_id_array;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_launcher {
+ uint32_t icon_surface_id;
+ uint32_t workspace_id;
+ char* icon;
+ char* path;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_setting {
+ struct hmi_homescreen_srf background;
+ struct hmi_homescreen_srf panel;
+ struct hmi_homescreen_srf tiling;
+ struct hmi_homescreen_srf sidebyside;
+ struct hmi_homescreen_srf fullscreen;
+ struct hmi_homescreen_srf random;
+ struct hmi_homescreen_srf home;
+ struct hmi_homescreen_srf workspace_background;
+
+ struct wl_list workspace_list;
+ struct wl_list launcher_list;
+
+ char *cursor_theme;
+ int32_t cursor_size;
+};
+
+volatile int gRun = 0;
+
+static void *
+fail_on_null(void *p, size_t size, char* file, int32_t line)
+{
+ if (size && !p) {
+ fprintf(stderr, "%s(%d) %zd: out of memory\n", file, line, size);
+ exit(EXIT_FAILURE);
+ }
+
+ return p;
+}
+
+static void *
+mem_alloc(size_t size, char* file, int32_t line)
+{
+ return fail_on_null(calloc(1, size), size, file, line);
+}
+
+#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+/*****************************************************************************
+ * Event Handler
+ ****************************************************************************/
+
+static void
+shm_format(void* data, struct wl_shm* pWlShm, uint32_t format)
+{
+ struct wlContextStruct* pDsp = data;
+ pDsp->formats |= (1 << format);
+}
+
+static struct wl_shm_listener shm_listenter = {
+ shm_format
+};
+
+static int32_t
+getIdOfWlSurface(struct wlContextCommon *pCtx, struct wl_surface *wlSurface)
+{
+ if (NULL == pCtx ||
+ NULL == wlSurface ) {
+ return 0;
+ }
+
+ struct wlContextStruct* pWlCtxSt = NULL;
+ wl_list_for_each(pWlCtxSt, pCtx->list_wlContextStruct, link) {
+ if (pWlCtxSt->wlSurface == wlSurface) {
+ return pWlCtxSt->id_surface;
+ }
+ continue;
+ }
+ return -1;
+}
+
+static void
+set_pointer_image(struct wlContextCommon *pCtx, uint32_t index)
+{
+ if (!pCtx->wlPointer ||
+ !pCtx->cursors) {
+ return;
+ }
+
+ if (CURSOR_BLANK == pCtx->current_cursor) {
+ wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
+ NULL, 0, 0);
+ return;
+ }
+
+ struct wl_cursor *cursor = pCtx->cursors[pCtx->current_cursor];
+ if (!cursor) {
+ return;
+ }
+
+ if (cursor->image_count <= index) {
+ fprintf(stderr, "cursor index out of range\n");
+ return;
+ }
+
+ struct wl_cursor_image *image = cursor->images[index];
+ struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
+
+ if (!buffer) {
+ return;
+ }
+
+ wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
+ pCtx->pointer_surface,
+ image->hotspot_x, image->hotspot_y);
+
+ wl_surface_attach(pCtx->pointer_surface, buffer, 0, 0);
+
+ wl_surface_damage(pCtx->pointer_surface, 0, 0,
+ image->width, image->height);
+
+ wl_surface_commit(pCtx->pointer_surface);
+}
+
+static void
+PointerHandleEnter(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ struct wl_surface* wlSurface, wl_fixed_t sx, wl_fixed_t sy)
+{
+ (void)wlPointer;
+ (void)serial;
+
+ struct wlContextCommon *pCtx = data;
+ pCtx->enter_serial = serial;
+ pCtx->enterSurface = wlSurface;
+ set_pointer_image(pCtx, 0);
+#ifdef _DEBUG
+ printf("ENTER PointerHandleEnter: x(%d), y(%d)\n", sx, sy);
+#endif
+}
+
+static void
+PointerHandleLeave(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ struct wl_surface* wlSurface)
+{
+ (void)wlPointer;
+ (void)wlSurface;
+
+ struct wlContextCommon *pCtx = data;
+ pCtx->enterSurface = NULL;
+
+#ifdef _DEBUG
+ printf("ENTER PointerHandleLeave: serial(%d)\n", serial);
+#endif
+}
+
+static void
+PointerHandleMotion(void* data, struct wl_pointer* wlPointer, uint32_t time,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ (void)data;
+ (void)wlPointer;
+ (void)time;
+
+#ifdef _DEBUG
+ printf("ENTER PointerHandleMotion: x(%d), y(%d)\n", gPointerX, gPointerY);
+#endif
+}
+
+/**
+ * if a surface assigned as launcher receives touch-off event, invoking
+ * ivi-application which configured in weston.ini with path to binary.
+ */
+extern char **environ; /*defied by libc */
+
+static pid_t execute_process(char* path, char *argv[])
+{
+ pid_t pid = fork();
+ if (pid < 0) {
+ fprintf(stderr, "Failed to fork\n");
+ }
+
+ if (pid) {
+ return pid;
+ }
+
+ if (-1 == execve(path, argv, environ)) {
+ fprintf(stderr, "Failed to execve %s\n", path);
+ exit(1);
+ }
+
+ return pid;
+}
+
+static int32_t
+launcher_button(uint32_t surfaceId, struct wl_list *launcher_list)
+{
+ struct hmi_homescreen_launcher *launcher = NULL;
+
+ wl_list_for_each(launcher, launcher_list, link) {
+ if (surfaceId != launcher->icon_surface_id) {
+ continue;
+ }
+
+ char *argv[] = {NULL};
+ execute_process(launcher->path, argv);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * is-method to identify a surface set as launcher in workspace or workspace
+ * itself. This is-method is used to decide whether request;
+ * ivi_hmi_controller_workspace_control is sent or not.
+ */
+static int32_t
+isWorkspaceSurface(uint32_t id, struct hmi_homescreen_setting *hmi_setting)
+{
+ if (id == hmi_setting->workspace_background.id) {
+ return 1;
+ }
+
+ struct hmi_homescreen_launcher *launcher = NULL;
+ wl_list_for_each(launcher, &hmi_setting->launcher_list, link) {
+ if (id == launcher->icon_surface_id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Decide which request is sent to hmi-controller
+ */
+static void
+touch_up(struct ivi_hmi_controller *hmi_ctrl, uint32_t id_surface,
+ int32_t *is_home_on, struct hmi_homescreen_setting* hmi_setting)
+{
+ if (launcher_button(id_surface, &hmi_setting->launcher_list)) {
+ *is_home_on = 0;
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ } else if (id_surface == hmi_setting->tiling.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING);
+ } else if (id_surface == hmi_setting->sidebyside.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE);
+ } else if (id_surface == hmi_setting->fullscreen.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN);
+ } else if (id_surface == hmi_setting->random.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM);
+ } else if (id_surface == hmi_setting->home.id) {
+ *is_home_on = !(*is_home_on);
+ if (*is_home_on) {
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_ON);
+ } else {
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ }
+ }
+}
+
+/**
+ * Even handler of Pointer event. IVI system is usually manipulated by touch
+ * screen. However, some systems also have pointer device.
+ * Release is the same behavior as touch off
+ * Pressed is the same behavior as touch on
+ */
+static void
+PointerHandleButton(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ uint32_t time, uint32_t button, uint32_t state)
+{
+ (void)wlPointer;
+ (void)serial;
+ (void)time;
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ if (BTN_RIGHT == button) {
+ return;
+ }
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ switch (state) {
+ case WL_POINTER_BUTTON_STATE_RELEASED:
+ touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, pCtx->hmi_setting);
+ break;
+
+ case WL_POINTER_BUTTON_STATE_PRESSED:
+
+ if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
+ ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, serial);
+ }
+
+ break;
+ }
+#ifdef _DEBUG
+ printf("ENTER PointerHandleButton: button(%d), state(%d)\n", button, state);
+#endif
+}
+
+static void
+PointerHandleAxis(void* data, struct wl_pointer* wlPointer, uint32_t time,
+ uint32_t axis, wl_fixed_t value)
+{
+ (void)data;
+ (void)wlPointer;
+ (void)time;
+#ifdef _DEBUG
+ printf("ENTER PointerHandleAxis: axis(%d), value(%d)\n", axis, value);
+#endif
+}
+
+static struct wl_pointer_listener pointer_listener = {
+ PointerHandleEnter,
+ PointerHandleLeave,
+ PointerHandleMotion,
+ PointerHandleButton,
+ PointerHandleAxis
+};
+
+/**
+ * Even handler of touch event
+ */
+static void
+TouchHandleDown(void *data, struct wl_touch *wlTouch, uint32_t serial, uint32_t time,
+ struct wl_surface *surface, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ if (0 == id){
+ pCtx->enterSurface = surface;
+ }
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * When touch down happens on surfaces of workspace, ask hmi-controller to start
+ * control workspace to select page of workspace.
+ * After sending seat to hmi-controller by ivi_hmi_controller_workspace_control,
+ * hmi-controller-homescreen doesn't receive any event till hmi-controller sends
+ * back it.
+ */
+ if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
+ ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, serial);
+ }
+}
+
+static void
+TouchHandleUp(void *data, struct wl_touch *wlTouch, uint32_t serial, uint32_t time,
+ int32_t id)
+{
+ (void)serial;
+ (void)time;
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * triggering event according to touch-up happening on which surface.
+ */
+ if (id == 0){
+ touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, pCtx->hmi_setting);
+ }
+}
+
+static void
+TouchHandleMotion(void *data, struct wl_touch *wlTouch, uint32_t time,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+}
+
+static void
+TouchHandleFrame(void *data, struct wl_touch *wlTouch)
+{
+}
+
+static void
+TouchHandleCancel(void *data, struct wl_touch *wlTouch)
+{
+}
+
+static struct wl_touch_listener touch_listener = {
+ TouchHandleDown,
+ TouchHandleUp,
+ TouchHandleMotion,
+ TouchHandleFrame,
+ TouchHandleCancel,
+};
+
+/**
+ * Handler of capabilities
+ */
+static void
+seat_handle_capabilities(void* data, struct wl_seat* seat, uint32_t caps)
+{
+ (void)seat;
+ struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
+ struct wl_seat* wlSeat = p_wlCtx->wlSeat;
+ struct wl_pointer* wlPointer = p_wlCtx->wlPointer;
+ struct wl_touch* wlTouch = p_wlCtx->wlTouch;
+
+ if (p_wlCtx->hmi_setting->cursor_theme) {
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wlPointer){
+ wlPointer = wl_seat_get_pointer(wlSeat);
+ wl_pointer_set_user_data(wlPointer, data);
+ wl_pointer_add_listener(wlPointer, &pointer_listener, data);
+ } else
+ if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wlPointer){
+ wl_pointer_destroy(wlPointer);
+ wlPointer = NULL;
+ }
+ p_wlCtx->wlPointer = wlPointer;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wlTouch){
+ wlTouch = wl_seat_get_touch(wlSeat);
+ wl_touch_set_user_data(wlTouch, data);
+ wl_touch_add_listener(wlTouch, &touch_listener, data);
+ } else
+ if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wlTouch){
+ wl_touch_destroy(wlTouch);
+ wlTouch = NULL;
+ }
+ p_wlCtx->wlTouch = wlTouch;
+}
+
+static struct wl_seat_listener seat_Listener = {
+ seat_handle_capabilities,
+};
+
+/**
+ * Registration of event
+ * This event is received when hmi-controller server finished controlling
+ * workspace.
+ */
+static void
+ivi_hmi_controller_workspace_end_control(void *data,
+ struct ivi_hmi_controller *hmi_ctrl,
+ int32_t is_controlled)
+{
+ if (is_controlled) {
+ return;
+ }
+
+ struct wlContextCommon *pCtx = data;
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * During being controlled by hmi-controller, any input event is not
+ * notified. So when control ends with touch up, it invokes launcher
+ * if up event happens on a launcher surface.
+ *
+ */
+ if (launcher_button(id_surface, &pCtx->hmi_setting->launcher_list)) {
+ pCtx->is_home_on = 0;
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ }
+}
+
+static const struct ivi_hmi_controller_listener hmi_controller_listener = {
+ ivi_hmi_controller_workspace_end_control
+};
+
+/**
+ * Registration of interfaces
+ */
+static void
+registry_handle_global(void* data, struct wl_registry* registry, uint32_t name,
+ const char *interface, uint32_t version)
+{
+ (void)version;
+ struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
+
+ do {
+ if (!strcmp(interface, "wl_compositor")) {
+ p_wlCtx->wlCompositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+ break;
+ }
+ if (!strcmp(interface, "wl_shm")) {
+ p_wlCtx->wlShm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
+ wl_shm_add_listener(p_wlCtx->wlShm, &shm_listenter, p_wlCtx);
+ break;
+ }
+ if (!strcmp(interface, "wl_seat")) {
+ p_wlCtx->wlSeat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
+ wl_seat_add_listener(p_wlCtx->wlSeat, &seat_Listener, data);
+ break;
+ }
+ if (!strcmp(interface, "ivi_application")) {
+ p_wlCtx->iviApplication = wl_registry_bind(registry, name, &ivi_application_interface, 1);
+ break;
+ }
+ if (!strcmp(interface, "ivi_hmi_controller")) {
+ p_wlCtx->hmiCtrl = wl_registry_bind(registry, name, &ivi_hmi_controller_interface, 1);
+
+ if (p_wlCtx->hmiCtrl) {
+ ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl, &hmi_controller_listener, p_wlCtx);
+ }
+ break;
+ }
+
+ } while(0);
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ NULL
+};
+
+static void
+frame_listener_func(void *data, struct wl_callback *callback, uint32_t time)
+{
+ if (callback) {
+ wl_callback_destroy(callback);
+ }
+}
+
+static const struct wl_callback_listener frame_listener = {
+ frame_listener_func
+};
+
+/*
+ * The following correspondences between file names and cursors was copied
+ * from: https://bugs.kde.org/attachment.cgi?id=67313
+ */
+static const char *bottom_left_corners[] = {
+ "bottom_left_corner",
+ "sw-resize",
+ "size_bdiag"
+};
+
+static const char *bottom_right_corners[] = {
+ "bottom_right_corner",
+ "se-resize",
+ "size_fdiag"
+};
+
+static const char *bottom_sides[] = {
+ "bottom_side",
+ "s-resize",
+ "size_ver"
+};
+
+static const char *grabbings[] = {
+ "grabbing",
+ "closedhand",
+ "208530c400c041818281048008011002"
+};
+
+static const char *left_ptrs[] = {
+ "left_ptr",
+ "default",
+ "top_left_arrow",
+ "left-arrow"
+};
+
+static const char *left_sides[] = {
+ "left_side",
+ "w-resize",
+ "size_hor"
+};
+
+static const char *right_sides[] = {
+ "right_side",
+ "e-resize",
+ "size_hor"
+};
+
+static const char *top_left_corners[] = {
+ "top_left_corner",
+ "nw-resize",
+ "size_fdiag"
+};
+
+static const char *top_right_corners[] = {
+ "top_right_corner",
+ "ne-resize",
+ "size_bdiag"
+};
+
+static const char *top_sides[] = {
+ "top_side",
+ "n-resize",
+ "size_ver"
+};
+
+static const char *xterms[] = {
+ "xterm",
+ "ibeam",
+ "text"
+};
+
+static const char *hand1s[] = {
+ "hand1",
+ "pointer",
+ "pointing_hand",
+ "e29285e634086352946a0e7090d73106"
+};
+
+static const char *watches[] = {
+ "watch",
+ "wait",
+ "0426c94ea35c87780ff01dc239897213"
+};
+
+struct cursor_alternatives {
+ const char **names;
+ size_t count;
+};
+
+static const struct cursor_alternatives cursors[] = {
+ {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
+ {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
+ {bottom_sides, ARRAY_LENGTH(bottom_sides)},
+ {grabbings, ARRAY_LENGTH(grabbings)},
+ {left_ptrs, ARRAY_LENGTH(left_ptrs)},
+ {left_sides, ARRAY_LENGTH(left_sides)},
+ {right_sides, ARRAY_LENGTH(right_sides)},
+ {top_left_corners, ARRAY_LENGTH(top_left_corners)},
+ {top_right_corners, ARRAY_LENGTH(top_right_corners)},
+ {top_sides, ARRAY_LENGTH(top_sides)},
+ {xterms, ARRAY_LENGTH(xterms)},
+ {hand1s, ARRAY_LENGTH(hand1s)},
+ {watches, ARRAY_LENGTH(watches)},
+};
+
+static void
+create_cursors(struct wlContextCommon *cmm)
+{
+ uint32_t i = 0;
+ uint32_t j = 0;
+ struct wl_cursor *cursor = NULL;
+ char* cursor_theme = cmm->hmi_setting->cursor_theme;
+ int32_t cursor_size = cmm->hmi_setting->cursor_size;
+
+ cmm->cursor_theme = wl_cursor_theme_load(cursor_theme, cursor_size, cmm->wlShm);
+
+ cmm->cursors = MEM_ALLOC(ARRAY_LENGTH(cursors) * sizeof(cmm->cursors[0]));
+
+ for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
+ cursor = NULL;
+
+ for (j = 0; !cursor && j < cursors[i].count; ++j) {
+ cursor = wl_cursor_theme_get_cursor(
+ cmm->cursor_theme, cursors[i].names[j]);
+ }
+
+ if (!cursor) {
+ fprintf(stderr, "could not load cursor '%s'\n",
+ cursors[i].names[0]);
+ }
+
+ cmm->cursors[i] = cursor;
+ }
+}
+
+static void
+destroy_cursors(struct wlContextCommon *cmm)
+{
+ if (cmm->cursor_theme) {
+ wl_cursor_theme_destroy(cmm->cursor_theme);
+ }
+
+ free(cmm->cursors);
+}
+
+/**
+ * Internal method to prepare parts of UI
+ */
+static void
+createShmBuffer(struct wlContextStruct *p_wlCtx)
+{
+ struct wl_shm_pool *pool;
+
+ char filename[] = "/tmp/wayland-shm-XXXXXX";
+ int fd = -1;
+ int size = 0;
+ int width = 0;
+ int height = 0;
+ int stride = 0;
+
+ fd = mkstemp(filename);
+ if (fd < 0) {
+ fprintf(stderr, "open %s failed: %m\n", filename);
+ return;
+ }
+
+ width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
+ height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
+ stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
+
+ size = stride * height;
+ if (ftruncate(fd, size) < 0) {
+ fprintf(stderr, "ftruncate failed: %m\n");
+ close(fd);
+ return;
+ }
+
+ p_wlCtx->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ if (MAP_FAILED == p_wlCtx->data) {
+ fprintf(stderr, "mmap failed: %m\n");
+ close(fd);
+ return;
+ }
+
+ pool = wl_shm_create_pool(p_wlCtx->cmm.wlShm, fd, size);
+ p_wlCtx->wlBuffer = wl_shm_pool_create_buffer(pool, 0,
+ width,
+ height,
+ stride,
+ WL_SHM_FORMAT_ARGB8888);
+
+ if (NULL == p_wlCtx->wlBuffer) {
+ fprintf(stderr, "wl_shm_create_buffer failed: %m\n");
+ close(fd);
+ return;
+ }
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ return;
+}
+
+static void
+destroyWLContextCommon(struct wlContextCommon *p_wlCtx)
+{
+ destroy_cursors(p_wlCtx);
+
+ if (p_wlCtx->pointer_surface) {
+ wl_surface_destroy(p_wlCtx->pointer_surface);
+ }
+
+ if (p_wlCtx->wlCompositor) {
+ wl_compositor_destroy(p_wlCtx->wlCompositor);
+ }
+}
+
+static void
+destroyWLContextStruct(struct wlContextStruct *p_wlCtx)
+{
+ if (p_wlCtx->wlSurface) {
+ wl_surface_destroy(p_wlCtx->wlSurface);
+ }
+
+ if (p_wlCtx->ctx_image) {
+ cairo_surface_destroy(p_wlCtx->ctx_image);
+ p_wlCtx->ctx_image = NULL;
+ }
+}
+
+static int
+createWLContext(struct wlContextStruct *p_wlCtx)
+{
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+
+ p_wlCtx->wlSurface = wl_compositor_create_surface(p_wlCtx->cmm.wlCompositor);
+ if (NULL == p_wlCtx->wlSurface) {
+ printf("Error: wl_compositor_create_surface failed.\n");
+ destroyWLContextCommon(&p_wlCtx->cmm);
+ abort();
+ }
+
+
+ createShmBuffer(p_wlCtx);
+
+ wl_display_flush(p_wlCtx->cmm.wlDisplay);
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+
+ return 0;
+}
+
+static void
+drawImage(struct wlContextStruct *p_wlCtx)
+{
+ struct wl_callback *callback;
+
+ int width = 0;
+ int height = 0;
+ int stride = 0;
+ void *data = NULL;
+
+ width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
+ height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
+ stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
+ data = cairo_image_surface_get_data(p_wlCtx->ctx_image);
+
+ memcpy(p_wlCtx->data, data, stride * height);
+
+ wl_surface_attach(p_wlCtx->wlSurface, p_wlCtx->wlBuffer, 0, 0);
+ wl_surface_damage(p_wlCtx->wlSurface, 0, 0, width, height);
+
+ callback = wl_surface_frame(p_wlCtx->wlSurface);
+ wl_callback_add_listener(callback, &frame_listener, NULL);
+
+ wl_surface_commit(p_wlCtx->wlSurface);
+
+ wl_display_flush(p_wlCtx->cmm.wlDisplay);
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+}
+
+static void
+create_ivisurface(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ cairo_surface_t* surface)
+{
+ struct ivi_surface *ivisurf = NULL;
+
+ p_wlCtx->ctx_image = surface;
+
+ p_wlCtx->id_surface = id_surface;
+ wl_list_init(&p_wlCtx->link);
+ wl_list_insert(p_wlCtx->cmm.list_wlContextStruct, &p_wlCtx->link);
+
+ createWLContext(p_wlCtx);
+
+ ivisurf = ivi_application_surface_create(p_wlCtx->cmm.iviApplication,
+ id_surface, p_wlCtx->wlSurface);
+ if (ivisurf == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ return;
+ }
+
+ drawImage(p_wlCtx);
+
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+}
+
+static void
+create_ivisurfaceFromFile(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ const char* imageFile)
+{
+ cairo_surface_t* surface = load_cairo_surface(imageFile);
+
+ if (NULL == surface) {
+ fprintf(stderr, "Failed to load_cairo_surface %s\n", imageFile);
+ return;
+ }
+
+ create_ivisurface(p_wlCtx, id_surface, surface);
+}
+
+static void
+set_hex_color(cairo_t *cr, uint32_t color)
+{
+ cairo_set_source_rgba(cr,
+ ((color >> 16) & 0xff) / 255.0,
+ ((color >> 8) & 0xff) / 255.0,
+ ((color >> 0) & 0xff) / 255.0,
+ ((color >> 24) & 0xff) / 255.0);
+}
+
+static void
+create_ivisurfaceFromColor(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ uint32_t width, uint32_t height,
+ uint32_t color)
+{
+ cairo_surface_t *surface = NULL;
+ cairo_t *cr = NULL;
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+
+ cr = cairo_create(surface);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle(cr, 0, 0, width, height);
+ set_hex_color(cr, color);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+
+ create_ivisurface(p_wlCtx, id_surface, surface);
+}
+
+/**
+ * Internal method to set up UI by using ivi-hmi-controller
+ */
+static void
+create_background(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_background(p_wlCtx->cmm.hmiCtrl, id_surface);
+}
+
+static void
+create_panel(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_panel(p_wlCtx->cmm.hmiCtrl, id_surface);
+}
+
+static void
+create_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile, uint32_t number)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_button(p_wlCtx->cmm.hmiCtrl, id_surface, number);
+}
+
+static void
+create_home_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_home_button(p_wlCtx->cmm.hmiCtrl, id_surface);
+}
+
+static void
+create_workspace_background(
+ struct wlContextStruct *p_wlCtx, struct hmi_homescreen_srf *srf)
+{
+ create_ivisurfaceFromColor(p_wlCtx, srf->id, 1, 1, srf->color);
+ ivi_hmi_controller_set_workspacebackground(p_wlCtx->cmm.hmiCtrl, srf->id);
+}
+
+static int compare_launcher(const void* data1, const void* data2)
+{
+ struct hmi_homescreen_launcher *launcher1 = *(struct hmi_homescreen_launcher**)data1;
+ struct hmi_homescreen_launcher *launcher2 = *(struct hmi_homescreen_launcher**)data2;
+ return launcher1->workspace_id - launcher2->workspace_id;
+}
+
+static void
+create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list)
+{
+ int launcher_count = wl_list_length(launcher_list);
+
+ if (0 == launcher_count) {
+ return;
+ }
+
+ struct hmi_homescreen_launcher** launchers;
+ launchers = MEM_ALLOC(launcher_count * sizeof(*launchers));
+
+ int ii = 0;
+ struct hmi_homescreen_launcher *launcher = NULL;
+
+ wl_list_for_each(launcher, launcher_list, link) {
+ launchers[ii] = launcher;
+ ii++;
+ }
+
+ qsort(launchers, launcher_count, sizeof(*launchers), compare_launcher);
+
+ int start = 0;
+
+ for (ii = 0; ii < launcher_count; ii++) {
+
+ if (ii != launcher_count -1 &&
+ launchers[ii]->workspace_id == launchers[ii + 1]->workspace_id) {
+ continue;
+ }
+
+ struct wl_array surface_ids;
+ wl_array_init(&surface_ids);
+
+ int jj = 0;
+ for (jj = start; jj <= ii; jj++) {
+ uint32_t *id = wl_array_add(&surface_ids, sizeof(*id));
+ *id = launchers[jj]->icon_surface_id;
+
+ struct wlContextStruct *p_wlCtx = MEM_ALLOC(sizeof(*p_wlCtx));
+ p_wlCtx->cmm = *cmm;
+
+ create_ivisurfaceFromFile(p_wlCtx, *id, launchers[jj]->icon);
+ }
+
+ ivi_hmi_controller_add_launchers(cmm->hmiCtrl, &surface_ids, 256);
+ wl_array_release(&surface_ids);
+ start = ii + 1;
+ }
+
+ free(launchers);
+}
+
+static void sigFunc(int signum)
+{
+ gRun = 0;
+}
+
+/**
+ * Internal method to read out weston.ini to get configuration
+ */
+static struct hmi_homescreen_setting*
+hmi_homescreen_setting_create(void)
+{
+ struct hmi_homescreen_setting* setting = MEM_ALLOC(sizeof(*setting));
+
+ wl_list_init(&setting->workspace_list);
+ wl_list_init(&setting->launcher_list);
+
+ struct weston_config *config = NULL;
+ config = weston_config_parse("weston.ini");
+
+ struct weston_config_section *shellSection = NULL;
+ shellSection = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ weston_config_section_get_string(
+ shellSection, "cursor-theme", &setting->cursor_theme, NULL);
+
+ weston_config_section_get_int(shellSection, "cursor-size", &setting->cursor_size, 32);
+
+ uint32_t workspace_layer_id;
+ weston_config_section_get_uint(
+ shellSection, "workspace-layer-id", &workspace_layer_id, 3000);
+
+ weston_config_section_get_string(
+ shellSection, "background-image", &setting->background.filePath,
+ DATADIR "/weston/background.png");
+
+ weston_config_section_get_uint(
+ shellSection, "background-id", &setting->background.id, 1001);
+
+ weston_config_section_get_string(
+ shellSection, "panel-image", &setting->panel.filePath,
+ DATADIR "/weston/panel.png");
+
+ weston_config_section_get_uint(
+ shellSection, "panel-id", &setting->panel.id, 1002);
+
+ weston_config_section_get_string(
+ shellSection, "tiling-image", &setting->tiling.filePath,
+ DATADIR "/weston/tiling.png");
+
+ weston_config_section_get_uint(
+ shellSection, "tiling-id", &setting->tiling.id, 1003);
+
+ weston_config_section_get_string(
+ shellSection, "sidebyside-image", &setting->sidebyside.filePath,
+ DATADIR "/weston/sidebyside.png");
+
+ weston_config_section_get_uint(
+ shellSection, "sidebyside-id", &setting->sidebyside.id, 1004);
+
+ weston_config_section_get_string(
+ shellSection, "fullscreen-image", &setting->fullscreen.filePath,
+ DATADIR "/weston/fullscreen.png");
+
+ weston_config_section_get_uint(
+ shellSection, "fullscreen-id", &setting->fullscreen.id, 1005);
+
+ weston_config_section_get_string(
+ shellSection, "random-image", &setting->random.filePath,
+ DATADIR "/weston/random.png");
+
+ weston_config_section_get_uint(
+ shellSection, "random-id", &setting->random.id, 1006);
+
+ weston_config_section_get_string(
+ shellSection, "home-image", &setting->home.filePath,
+ DATADIR "/weston/home.png");
+
+ weston_config_section_get_uint(
+ shellSection, "home-id", &setting->home.id, 1007);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-color",
+ &setting->workspace_background.color, 0x99000000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-id",
+ &setting->workspace_background.id, 2001);
+
+ struct weston_config_section *section = NULL;
+ const char *name = NULL;
+
+ uint32_t icon_surface_id = workspace_layer_id + 1;
+
+ while (weston_config_next_section(config, &section, &name)) {
+
+ if (0 == strcmp(name, "ivi-launcher")) {
+
+ struct hmi_homescreen_launcher *launcher = NULL;
+ launcher = MEM_ALLOC(sizeof(*launcher));
+ wl_list_init(&launcher->link);
+ launcher->icon_surface_id = icon_surface_id;
+ icon_surface_id++;
+
+ weston_config_section_get_string(section, "icon", &launcher->icon, NULL);
+ weston_config_section_get_string(section, "path", &launcher->path, NULL);
+ weston_config_section_get_uint(section, "workspace-id", &launcher->workspace_id, 0);
+
+ wl_list_insert(setting->launcher_list.prev, &launcher->link);
+ }
+ }
+
+ weston_config_destroy(config);
+ return setting;
+}
+
+/**
+ * Main thread
+ *
+ * The basic flow are as followed,
+ * 1/ read configuration from weston.ini by hmi_homescreen_setting_create
+ * 2/ draw png file to surface according to configuration of weston.ini and
+ * set up UI by using ivi-hmi-controller protocol by each create_* method
+ */
+static void*
+client_thread(void *p_ret)
+{
+ struct wlContextCommon wlCtxCommon;
+ struct wlContextStruct wlCtx_BackGround;
+ struct wlContextStruct wlCtx_Panel;
+ struct wlContextStruct wlCtx_Button_1;
+ struct wlContextStruct wlCtx_Button_2;
+ struct wlContextStruct wlCtx_Button_3;
+ struct wlContextStruct wlCtx_Button_4;
+ struct wlContextStruct wlCtx_HomeButton;
+ struct wlContextStruct wlCtx_WorkSpaceBackGround;
+ struct wl_list launcher_wlCtxList;
+
+ memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon));
+ memset(&wlCtx_BackGround, 0x00, sizeof(wlCtx_BackGround));
+ memset(&wlCtx_Panel, 0x00, sizeof(wlCtx_Panel));
+ memset(&wlCtx_Button_1, 0x00, sizeof(wlCtx_Button_1));
+ memset(&wlCtx_Button_2, 0x00, sizeof(wlCtx_Button_2));
+ memset(&wlCtx_Button_3, 0x00, sizeof(wlCtx_Button_3));
+ memset(&wlCtx_Button_4, 0x00, sizeof(wlCtx_Button_4));
+ memset(&wlCtx_HomeButton, 0x00, sizeof(wlCtx_HomeButton));
+ memset(&wlCtx_WorkSpaceBackGround, 0x00, sizeof(wlCtx_WorkSpaceBackGround));
+ wl_list_init(&launcher_wlCtxList);
+ wlCtxCommon.list_wlContextStruct = MEM_ALLOC(sizeof(struct wl_list));
+ assert(wlCtxCommon.list_wlContextStruct);
+ wl_list_init(wlCtxCommon.list_wlContextStruct);
+
+ struct hmi_homescreen_setting *hmi_setting = hmi_homescreen_setting_create();
+ wlCtxCommon.hmi_setting = hmi_setting;
+
+ gRun = 1;
+
+ wlCtxCommon.wlDisplay = wl_display_connect(NULL);
+ if (NULL == wlCtxCommon.wlDisplay) {
+ printf("Error: wl_display_connect failed.\n");
+ return NULL;
+ }
+
+ /* get wl_registry */
+ wlCtxCommon.wlRegistry = wl_display_get_registry(wlCtxCommon.wlDisplay);
+ wl_registry_add_listener(wlCtxCommon.wlRegistry,
+ &registry_listener, &wlCtxCommon);
+ wl_display_dispatch(wlCtxCommon.wlDisplay);
+ wl_display_roundtrip(wlCtxCommon.wlDisplay);
+
+ if (wlCtxCommon.hmi_setting->cursor_theme) {
+ create_cursors(&wlCtxCommon);
+
+ wlCtxCommon.pointer_surface =
+ wl_compositor_create_surface(wlCtxCommon.wlCompositor);
+
+ wlCtxCommon.current_cursor = CURSOR_LEFT_PTR;
+ }
+
+ wlCtx_BackGround.cmm = wlCtxCommon;
+ wlCtx_Panel.cmm = wlCtxCommon;
+ wlCtx_Button_1.cmm = wlCtxCommon;
+ wlCtx_Button_2.cmm = wlCtxCommon;
+ wlCtx_Button_3.cmm = wlCtxCommon;
+ wlCtx_Button_4.cmm = wlCtxCommon;
+ wlCtx_HomeButton.cmm = wlCtxCommon;
+ wlCtx_WorkSpaceBackGround.cmm = wlCtxCommon;
+
+ /* create desktop widgets */
+ create_background(&wlCtx_BackGround, hmi_setting->background.id,
+ hmi_setting->background.filePath);
+
+ create_panel(&wlCtx_Panel, hmi_setting->panel.id,
+ hmi_setting->panel.filePath);
+
+ create_button(&wlCtx_Button_1, hmi_setting->tiling.id,
+ hmi_setting->tiling.filePath, 0);
+
+ create_button(&wlCtx_Button_2, hmi_setting->sidebyside.id,
+ hmi_setting->sidebyside.filePath, 1);
+
+ create_button(&wlCtx_Button_3, hmi_setting->fullscreen.id,
+ hmi_setting->fullscreen.filePath, 2);
+
+ create_button(&wlCtx_Button_4, hmi_setting->random.id,
+ hmi_setting->random.filePath, 3);
+
+ create_workspace_background(&wlCtx_WorkSpaceBackGround,
+ &hmi_setting->workspace_background);
+
+ create_launchers(&wlCtxCommon, &hmi_setting->launcher_list);
+
+ create_home_button(&wlCtx_HomeButton, hmi_setting->home.id,
+ hmi_setting->home.filePath);
+ /* signal handling */
+ signal(SIGINT, sigFunc);
+ signal(SIGKILL, sigFunc);
+
+ while(gRun) {
+ wl_display_roundtrip(wlCtxCommon.wlDisplay);
+ usleep(5000);
+ }
+
+ struct wlContextStruct* pWlCtxSt = NULL;
+ wl_list_for_each(pWlCtxSt, wlCtxCommon.list_wlContextStruct, link) {
+ destroyWLContextStruct(pWlCtxSt);
+ }
+
+ destroyWLContextCommon(&wlCtxCommon);
+ free(wlCtxCommon.list_wlContextStruct);
+
+ return NULL;
+}
+
+/*****************************************************************************
+ * exported functions
+ ****************************************************************************/
+int
+hmi_client_start(void)
+{
+ pthread_attr_t thread_attrs;
+ uint32_t ret = 0;
+ pthread_t thread;
+
+ pthread_attr_init(&thread_attrs);
+ pthread_attr_setdetachstate(&thread_attrs, PTHREAD_CREATE_JOINABLE);
+ ret = pthread_create(&thread, &thread_attrs, client_thread, NULL);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to start internal receive \
+ thread. returned %d\n", ret);
+ }
+
+ return 0;
+}
diff --git a/ivi-shell/hmi-controller-homescreen.h b/ivi-shell/hmi-controller-homescreen.h
new file mode 100644
index 0000000..31416de
--- /dev/null
+++ b/ivi-shell/hmi-controller-homescreen.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _HMI_CONTROLLER_HOMESCREEN_H_
+#define _HMI_CONTROLLER_HOMESCREEN_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+int hmi_client_start(void);
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _HMI_CONTROLLER_HOMESCREEN_H_ */
diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
index bd311ea..3cfb19b 100644
--- a/ivi-shell/hmi-controller.c
+++ b/ivi-shell/hmi-controller.c
@@ -54,6 +54,7 @@
#include <time.h>

#include "weston-layout.h"
+#include "hmi-controller-homescreen.h"
#include "ivi-hmi-controller-server-protocol.h"

/*****************************************************************************
@@ -1749,7 +1750,7 @@ bind_hmi_controller(struct wl_client *client,
static void
launch_hmi_client(void *data)
{
- /*Nothing to do here*/
+ hmi_client_start();
}

/*****************************************************************************
--
1.8.3.1
Nobuhiko Tanibata
2014-03-20 07:00:57 UTC
Permalink
This is launched from hmi-controller by using hmi_client_start and create a
pthread.

The basic flow is as followed,
1/ create pthread
2/ read configuration from weston.ini.
3/ draw png file to surface according to configuration of weston.ini
4/ set up UI by using ivi-hmi-controller protocol
5/ Enter event loop
6/ If a surface receives touch/pointer event, followings are invoked according
to type of event and surface
6-1/ If a surface to launch ivi_application receive touch up, it execs
ivi-application configured in weston.ini.
6-2/ If a surface to switch layout mode receive touch up, it sends a request,
ivi_hmi_controller_switch_mode, to hmi-controller.
6-3/ If a surface to show workspace having launchers, it sends a request,
ivi_hmi_controller_home, to hmi-controller.
6-4/ If touch down events happens in workspace,
ivi_hmi_controller_workspace_control is sent to slide workspace.
When control finished, event: ivi_hmi_controller_workspace_end_control
is received.

Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4:
- nothing. Version number aligned to the first patch

Changes for v5:
- usleep with roundtrip uses CPU. replace them with wl_display_dispatch

ivi-shell/Makefile.am | 2 +
ivi-shell/hmi-controller-homescreen.c | 1369 +++++++++++++++++++++++++++++++++
ivi-shell/hmi-controller-homescreen.h | 36 +
ivi-shell/hmi-controller.c | 3 +-
4 files changed, 1409 insertions(+), 1 deletion(-)
create mode 100644 ivi-shell/hmi-controller-homescreen.c
create mode 100644 ivi-shell/hmi-controller-homescreen.h

diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
index 28589f8..afaa5e3 100644
--- a/ivi-shell/Makefile.am
+++ b/ivi-shell/Makefile.am
@@ -46,6 +46,8 @@ hmi_controller_la_LIBADD = $(CLIENT_LIBS) $(IVI_SHELL_LIBS) ./libweston-layout.l
hmi_controller_la_CFLAGS = $(GCC_CFLAGS) $(IVI_SHELL_CFLAGS)
hmi_controller_la_SOURCES = \
hmi-controller.c \
+ hmi-controller-homescreen.h \
+ hmi-controller-homescreen.c \
ivi-application-protocol.c \
ivi-application-client-protocol.h \
ivi-hmi-controller-protocol.c \
diff --git a/ivi-shell/hmi-controller-homescreen.c b/ivi-shell/hmi-controller-homescreen.c
new file mode 100644
index 0000000..6dc3b11
--- /dev/null
+++ b/ivi-shell/hmi-controller-homescreen.c
@@ -0,0 +1,1369 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <wayland-cursor.h>
+#include "hmi-controller-homescreen.h"
+#include "../shared/cairo-util.h"
+#include "../shared/config-parser.h"
+#include "ivi-application-client-protocol.h"
+#include "ivi-hmi-controller-client-protocol.h"
+
+/**
+ * A reference implementation how to use ivi-hmi-controller interface to interact
+ * with hmi-controller. This is launched from hmi-controller by using
+ * hmi_client_start and create a pthread.
+ *
+ * The basic flow is as followed,
+ * 1/ create pthread
+ * 2/ read configuration from weston.ini.
+ * 3/ draw png file to surface according to configuration of weston.ini
+ * 4/ set up UI by using ivi-hmi-controller protocol
+ * 5/ Enter event loop
+ * 6/ If a surface receives touch/pointer event, followings are invoked according
+ * to type of event and surface
+ * 6-1/ If a surface to launch ivi_application receive touch up, it execs
+ * ivi-application configured in weston.ini.
+ * 6-2/ If a surface to switch layout mode receive touch up, it sends a request,
+ * ivi_hmi_controller_switch_mode, to hmi-controller.
+ * 6-3/ If a surface to show workspace having launchers, it sends a request,
+ * ivi_hmi_controller_home, to hmi-controller.
+ * 6-4/ If touch down events happens in workspace,
+ * ivi_hmi_controller_workspace_control is sent to slide workspace.
+ * When control finished, event: ivi_hmi_controller_workspace_end_control
+ * is received.
+ */
+
+/*****************************************************************************
+ * structure, globals
+ ****************************************************************************/
+enum cursor_type {
+ CURSOR_BOTTOM_LEFT,
+ CURSOR_BOTTOM_RIGHT,
+ CURSOR_BOTTOM,
+ CURSOR_DRAGGING,
+ CURSOR_LEFT_PTR,
+ CURSOR_LEFT,
+ CURSOR_RIGHT,
+ CURSOR_TOP_LEFT,
+ CURSOR_TOP_RIGHT,
+ CURSOR_TOP,
+ CURSOR_IBEAM,
+ CURSOR_HAND1,
+ CURSOR_WATCH,
+
+ CURSOR_BLANK
+};
+struct wlContextCommon {
+ struct wl_display *wlDisplay;
+ struct wl_registry *wlRegistry;
+ struct wl_compositor *wlCompositor;
+ struct wl_shm *wlShm;
+ struct wl_seat *wlSeat;
+ struct wl_pointer *wlPointer;
+ struct wl_touch *wlTouch;
+ struct ivi_application *iviApplication;
+ struct ivi_hmi_controller *hmiCtrl;
+ struct hmi_homescreen_setting *hmi_setting;
+ struct wl_list *list_wlContextStruct;
+ struct wl_surface *enterSurface;
+ int32_t is_home_on;
+ struct wl_cursor_theme *cursor_theme;
+ struct wl_cursor **cursors;
+ struct wl_surface *pointer_surface;
+ enum cursor_type current_cursor;
+ uint32_t enter_serial;
+};
+
+struct wlContextStruct {
+ struct wlContextCommon cmm;
+ struct wl_surface *wlSurface;
+ struct wl_buffer *wlBuffer;
+ uint32_t formats;
+ cairo_surface_t *ctx_image;
+ void *data;
+ uint32_t id_surface;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_srf {
+ uint32_t id;
+ char *filePath;
+ uint32_t color;
+};
+
+struct
+hmi_homescreen_workspace {
+ struct wl_array launcher_id_array;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_launcher {
+ uint32_t icon_surface_id;
+ uint32_t workspace_id;
+ char* icon;
+ char* path;
+ struct wl_list link;
+};
+
+struct
+hmi_homescreen_setting {
+ struct hmi_homescreen_srf background;
+ struct hmi_homescreen_srf panel;
+ struct hmi_homescreen_srf tiling;
+ struct hmi_homescreen_srf sidebyside;
+ struct hmi_homescreen_srf fullscreen;
+ struct hmi_homescreen_srf random;
+ struct hmi_homescreen_srf home;
+ struct hmi_homescreen_srf workspace_background;
+
+ struct wl_list workspace_list;
+ struct wl_list launcher_list;
+
+ char *cursor_theme;
+ int32_t cursor_size;
+};
+
+volatile int gRun = 0;
+
+static void *
+fail_on_null(void *p, size_t size, char* file, int32_t line)
+{
+ if (size && !p) {
+ fprintf(stderr, "%s(%d) %zd: out of memory\n", file, line, size);
+ exit(EXIT_FAILURE);
+ }
+
+ return p;
+}
+
+static void *
+mem_alloc(size_t size, char* file, int32_t line)
+{
+ return fail_on_null(calloc(1, size), size, file, line);
+}
+
+#define MEM_ALLOC(s) mem_alloc((s),__FILE__,__LINE__)
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+/*****************************************************************************
+ * Event Handler
+ ****************************************************************************/
+
+static void
+shm_format(void* data, struct wl_shm* pWlShm, uint32_t format)
+{
+ struct wlContextStruct* pDsp = data;
+ pDsp->formats |= (1 << format);
+}
+
+static struct wl_shm_listener shm_listenter = {
+ shm_format
+};
+
+static int32_t
+getIdOfWlSurface(struct wlContextCommon *pCtx, struct wl_surface *wlSurface)
+{
+ if (NULL == pCtx ||
+ NULL == wlSurface ) {
+ return 0;
+ }
+
+ struct wlContextStruct* pWlCtxSt = NULL;
+ wl_list_for_each(pWlCtxSt, pCtx->list_wlContextStruct, link) {
+ if (pWlCtxSt->wlSurface == wlSurface) {
+ return pWlCtxSt->id_surface;
+ }
+ continue;
+ }
+ return -1;
+}
+
+static void
+set_pointer_image(struct wlContextCommon *pCtx, uint32_t index)
+{
+ if (!pCtx->wlPointer ||
+ !pCtx->cursors) {
+ return;
+ }
+
+ if (CURSOR_BLANK == pCtx->current_cursor) {
+ wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
+ NULL, 0, 0);
+ return;
+ }
+
+ struct wl_cursor *cursor = pCtx->cursors[pCtx->current_cursor];
+ if (!cursor) {
+ return;
+ }
+
+ if (cursor->image_count <= index) {
+ fprintf(stderr, "cursor index out of range\n");
+ return;
+ }
+
+ struct wl_cursor_image *image = cursor->images[index];
+ struct wl_buffer *buffer = wl_cursor_image_get_buffer(image);
+
+ if (!buffer) {
+ return;
+ }
+
+ wl_pointer_set_cursor(pCtx->wlPointer, pCtx->enter_serial,
+ pCtx->pointer_surface,
+ image->hotspot_x, image->hotspot_y);
+
+ wl_surface_attach(pCtx->pointer_surface, buffer, 0, 0);
+
+ wl_surface_damage(pCtx->pointer_surface, 0, 0,
+ image->width, image->height);
+
+ wl_surface_commit(pCtx->pointer_surface);
+}
+
+static void
+PointerHandleEnter(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ struct wl_surface* wlSurface, wl_fixed_t sx, wl_fixed_t sy)
+{
+ (void)wlPointer;
+ (void)serial;
+
+ struct wlContextCommon *pCtx = data;
+ pCtx->enter_serial = serial;
+ pCtx->enterSurface = wlSurface;
+ set_pointer_image(pCtx, 0);
+#ifdef _DEBUG
+ printf("ENTER PointerHandleEnter: x(%d), y(%d)\n", sx, sy);
+#endif
+}
+
+static void
+PointerHandleLeave(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ struct wl_surface* wlSurface)
+{
+ (void)wlPointer;
+ (void)wlSurface;
+
+ struct wlContextCommon *pCtx = data;
+ pCtx->enterSurface = NULL;
+
+#ifdef _DEBUG
+ printf("ENTER PointerHandleLeave: serial(%d)\n", serial);
+#endif
+}
+
+static void
+PointerHandleMotion(void* data, struct wl_pointer* wlPointer, uint32_t time,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ (void)data;
+ (void)wlPointer;
+ (void)time;
+
+#ifdef _DEBUG
+ printf("ENTER PointerHandleMotion: x(%d), y(%d)\n", gPointerX, gPointerY);
+#endif
+}
+
+/**
+ * if a surface assigned as launcher receives touch-off event, invoking
+ * ivi-application which configured in weston.ini with path to binary.
+ */
+extern char **environ; /*defied by libc */
+
+static pid_t execute_process(char* path, char *argv[])
+{
+ pid_t pid = fork();
+ if (pid < 0) {
+ fprintf(stderr, "Failed to fork\n");
+ }
+
+ if (pid) {
+ return pid;
+ }
+
+ if (-1 == execve(path, argv, environ)) {
+ fprintf(stderr, "Failed to execve %s\n", path);
+ exit(1);
+ }
+
+ return pid;
+}
+
+static int32_t
+launcher_button(uint32_t surfaceId, struct wl_list *launcher_list)
+{
+ struct hmi_homescreen_launcher *launcher = NULL;
+
+ wl_list_for_each(launcher, launcher_list, link) {
+ if (surfaceId != launcher->icon_surface_id) {
+ continue;
+ }
+
+ char *argv[] = {NULL};
+ execute_process(launcher->path, argv);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * is-method to identify a surface set as launcher in workspace or workspace
+ * itself. This is-method is used to decide whether request;
+ * ivi_hmi_controller_workspace_control is sent or not.
+ */
+static int32_t
+isWorkspaceSurface(uint32_t id, struct hmi_homescreen_setting *hmi_setting)
+{
+ if (id == hmi_setting->workspace_background.id) {
+ return 1;
+ }
+
+ struct hmi_homescreen_launcher *launcher = NULL;
+ wl_list_for_each(launcher, &hmi_setting->launcher_list, link) {
+ if (id == launcher->icon_surface_id) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Decide which request is sent to hmi-controller
+ */
+static void
+touch_up(struct ivi_hmi_controller *hmi_ctrl, uint32_t id_surface,
+ int32_t *is_home_on, struct hmi_homescreen_setting* hmi_setting)
+{
+ if (launcher_button(id_surface, &hmi_setting->launcher_list)) {
+ *is_home_on = 0;
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ } else if (id_surface == hmi_setting->tiling.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_TILING);
+ } else if (id_surface == hmi_setting->sidebyside.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_SIDE_BY_SIDE);
+ } else if (id_surface == hmi_setting->fullscreen.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_FULL_SCREEN);
+ } else if (id_surface == hmi_setting->random.id) {
+ ivi_hmi_controller_switch_mode(
+ hmi_ctrl, IVI_HMI_CONTROLLER_LAYOUT_MODE_RANDOM);
+ } else if (id_surface == hmi_setting->home.id) {
+ *is_home_on = !(*is_home_on);
+ if (*is_home_on) {
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_ON);
+ } else {
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ }
+ }
+}
+
+/**
+ * Even handler of Pointer event. IVI system is usually manipulated by touch
+ * screen. However, some systems also have pointer device.
+ * Release is the same behavior as touch off
+ * Pressed is the same behavior as touch on
+ */
+static void
+PointerHandleButton(void* data, struct wl_pointer* wlPointer, uint32_t serial,
+ uint32_t time, uint32_t button, uint32_t state)
+{
+ (void)wlPointer;
+ (void)serial;
+ (void)time;
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ if (BTN_RIGHT == button) {
+ return;
+ }
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ switch (state) {
+ case WL_POINTER_BUTTON_STATE_RELEASED:
+ touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, pCtx->hmi_setting);
+ break;
+
+ case WL_POINTER_BUTTON_STATE_PRESSED:
+
+ if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
+ ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, serial);
+ }
+
+ break;
+ }
+#ifdef _DEBUG
+ printf("ENTER PointerHandleButton: button(%d), state(%d)\n", button, state);
+#endif
+}
+
+static void
+PointerHandleAxis(void* data, struct wl_pointer* wlPointer, uint32_t time,
+ uint32_t axis, wl_fixed_t value)
+{
+ (void)data;
+ (void)wlPointer;
+ (void)time;
+#ifdef _DEBUG
+ printf("ENTER PointerHandleAxis: axis(%d), value(%d)\n", axis, value);
+#endif
+}
+
+static struct wl_pointer_listener pointer_listener = {
+ PointerHandleEnter,
+ PointerHandleLeave,
+ PointerHandleMotion,
+ PointerHandleButton,
+ PointerHandleAxis
+};
+
+/**
+ * Even handler of touch event
+ */
+static void
+TouchHandleDown(void *data, struct wl_touch *wlTouch, uint32_t serial, uint32_t time,
+ struct wl_surface *surface, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ if (0 == id){
+ pCtx->enterSurface = surface;
+ }
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * When touch down happens on surfaces of workspace, ask hmi-controller to start
+ * control workspace to select page of workspace.
+ * After sending seat to hmi-controller by ivi_hmi_controller_workspace_control,
+ * hmi-controller-homescreen doesn't receive any event till hmi-controller sends
+ * back it.
+ */
+ if (isWorkspaceSurface(id_surface, pCtx->hmi_setting)) {
+ ivi_hmi_controller_workspace_control(hmi_ctrl, pCtx->wlSeat, serial);
+ }
+}
+
+static void
+TouchHandleUp(void *data, struct wl_touch *wlTouch, uint32_t serial, uint32_t time,
+ int32_t id)
+{
+ (void)serial;
+ (void)time;
+ struct wlContextCommon *pCtx = data;
+ struct ivi_hmi_controller *hmi_ctrl = pCtx->hmiCtrl;
+
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * triggering event according to touch-up happening on which surface.
+ */
+ if (id == 0){
+ touch_up(hmi_ctrl, id_surface, &pCtx->is_home_on, pCtx->hmi_setting);
+ }
+}
+
+static void
+TouchHandleMotion(void *data, struct wl_touch *wlTouch, uint32_t time,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+}
+
+static void
+TouchHandleFrame(void *data, struct wl_touch *wlTouch)
+{
+}
+
+static void
+TouchHandleCancel(void *data, struct wl_touch *wlTouch)
+{
+}
+
+static struct wl_touch_listener touch_listener = {
+ TouchHandleDown,
+ TouchHandleUp,
+ TouchHandleMotion,
+ TouchHandleFrame,
+ TouchHandleCancel,
+};
+
+/**
+ * Handler of capabilities
+ */
+static void
+seat_handle_capabilities(void* data, struct wl_seat* seat, uint32_t caps)
+{
+ (void)seat;
+ struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
+ struct wl_seat* wlSeat = p_wlCtx->wlSeat;
+ struct wl_pointer* wlPointer = p_wlCtx->wlPointer;
+ struct wl_touch* wlTouch = p_wlCtx->wlTouch;
+
+ if (p_wlCtx->hmi_setting->cursor_theme) {
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wlPointer){
+ wlPointer = wl_seat_get_pointer(wlSeat);
+ wl_pointer_set_user_data(wlPointer, data);
+ wl_pointer_add_listener(wlPointer, &pointer_listener, data);
+ } else
+ if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wlPointer){
+ wl_pointer_destroy(wlPointer);
+ wlPointer = NULL;
+ }
+ p_wlCtx->wlPointer = wlPointer;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wlTouch){
+ wlTouch = wl_seat_get_touch(wlSeat);
+ wl_touch_set_user_data(wlTouch, data);
+ wl_touch_add_listener(wlTouch, &touch_listener, data);
+ } else
+ if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wlTouch){
+ wl_touch_destroy(wlTouch);
+ wlTouch = NULL;
+ }
+ p_wlCtx->wlTouch = wlTouch;
+}
+
+static struct wl_seat_listener seat_Listener = {
+ seat_handle_capabilities,
+};
+
+/**
+ * Registration of event
+ * This event is received when hmi-controller server finished controlling
+ * workspace.
+ */
+static void
+ivi_hmi_controller_workspace_end_control(void *data,
+ struct ivi_hmi_controller *hmi_ctrl,
+ int32_t is_controlled)
+{
+ if (is_controlled) {
+ return;
+ }
+
+ struct wlContextCommon *pCtx = data;
+ const uint32_t id_surface = getIdOfWlSurface(pCtx, pCtx->enterSurface);
+
+ /**
+ * During being controlled by hmi-controller, any input event is not
+ * notified. So when control ends with touch up, it invokes launcher
+ * if up event happens on a launcher surface.
+ *
+ */
+ if (launcher_button(id_surface, &pCtx->hmi_setting->launcher_list)) {
+ pCtx->is_home_on = 0;
+ ivi_hmi_controller_home(hmi_ctrl, IVI_HMI_CONTROLLER_HOME_OFF);
+ }
+}
+
+static const struct ivi_hmi_controller_listener hmi_controller_listener = {
+ ivi_hmi_controller_workspace_end_control
+};
+
+/**
+ * Registration of interfaces
+ */
+static void
+registry_handle_global(void* data, struct wl_registry* registry, uint32_t name,
+ const char *interface, uint32_t version)
+{
+ (void)version;
+ struct wlContextCommon* p_wlCtx = (struct wlContextCommon*)data;
+
+ do {
+ if (!strcmp(interface, "wl_compositor")) {
+ p_wlCtx->wlCompositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
+ break;
+ }
+ if (!strcmp(interface, "wl_shm")) {
+ p_wlCtx->wlShm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
+ wl_shm_add_listener(p_wlCtx->wlShm, &shm_listenter, p_wlCtx);
+ break;
+ }
+ if (!strcmp(interface, "wl_seat")) {
+ p_wlCtx->wlSeat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
+ wl_seat_add_listener(p_wlCtx->wlSeat, &seat_Listener, data);
+ break;
+ }
+ if (!strcmp(interface, "ivi_application")) {
+ p_wlCtx->iviApplication = wl_registry_bind(registry, name, &ivi_application_interface, 1);
+ break;
+ }
+ if (!strcmp(interface, "ivi_hmi_controller")) {
+ p_wlCtx->hmiCtrl = wl_registry_bind(registry, name, &ivi_hmi_controller_interface, 1);
+
+ if (p_wlCtx->hmiCtrl) {
+ ivi_hmi_controller_add_listener(p_wlCtx->hmiCtrl, &hmi_controller_listener, p_wlCtx);
+ }
+ break;
+ }
+
+ } while(0);
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ NULL
+};
+
+static void
+frame_listener_func(void *data, struct wl_callback *callback, uint32_t time)
+{
+ if (callback) {
+ wl_callback_destroy(callback);
+ }
+}
+
+static const struct wl_callback_listener frame_listener = {
+ frame_listener_func
+};
+
+/*
+ * The following correspondences between file names and cursors was copied
+ * from: https://bugs.kde.org/attachment.cgi?id=67313
+ */
+static const char *bottom_left_corners[] = {
+ "bottom_left_corner",
+ "sw-resize",
+ "size_bdiag"
+};
+
+static const char *bottom_right_corners[] = {
+ "bottom_right_corner",
+ "se-resize",
+ "size_fdiag"
+};
+
+static const char *bottom_sides[] = {
+ "bottom_side",
+ "s-resize",
+ "size_ver"
+};
+
+static const char *grabbings[] = {
+ "grabbing",
+ "closedhand",
+ "208530c400c041818281048008011002"
+};
+
+static const char *left_ptrs[] = {
+ "left_ptr",
+ "default",
+ "top_left_arrow",
+ "left-arrow"
+};
+
+static const char *left_sides[] = {
+ "left_side",
+ "w-resize",
+ "size_hor"
+};
+
+static const char *right_sides[] = {
+ "right_side",
+ "e-resize",
+ "size_hor"
+};
+
+static const char *top_left_corners[] = {
+ "top_left_corner",
+ "nw-resize",
+ "size_fdiag"
+};
+
+static const char *top_right_corners[] = {
+ "top_right_corner",
+ "ne-resize",
+ "size_bdiag"
+};
+
+static const char *top_sides[] = {
+ "top_side",
+ "n-resize",
+ "size_ver"
+};
+
+static const char *xterms[] = {
+ "xterm",
+ "ibeam",
+ "text"
+};
+
+static const char *hand1s[] = {
+ "hand1",
+ "pointer",
+ "pointing_hand",
+ "e29285e634086352946a0e7090d73106"
+};
+
+static const char *watches[] = {
+ "watch",
+ "wait",
+ "0426c94ea35c87780ff01dc239897213"
+};
+
+struct cursor_alternatives {
+ const char **names;
+ size_t count;
+};
+
+static const struct cursor_alternatives cursors[] = {
+ {bottom_left_corners, ARRAY_LENGTH(bottom_left_corners)},
+ {bottom_right_corners, ARRAY_LENGTH(bottom_right_corners)},
+ {bottom_sides, ARRAY_LENGTH(bottom_sides)},
+ {grabbings, ARRAY_LENGTH(grabbings)},
+ {left_ptrs, ARRAY_LENGTH(left_ptrs)},
+ {left_sides, ARRAY_LENGTH(left_sides)},
+ {right_sides, ARRAY_LENGTH(right_sides)},
+ {top_left_corners, ARRAY_LENGTH(top_left_corners)},
+ {top_right_corners, ARRAY_LENGTH(top_right_corners)},
+ {top_sides, ARRAY_LENGTH(top_sides)},
+ {xterms, ARRAY_LENGTH(xterms)},
+ {hand1s, ARRAY_LENGTH(hand1s)},
+ {watches, ARRAY_LENGTH(watches)},
+};
+
+static void
+create_cursors(struct wlContextCommon *cmm)
+{
+ uint32_t i = 0;
+ uint32_t j = 0;
+ struct wl_cursor *cursor = NULL;
+ char* cursor_theme = cmm->hmi_setting->cursor_theme;
+ int32_t cursor_size = cmm->hmi_setting->cursor_size;
+
+ cmm->cursor_theme = wl_cursor_theme_load(cursor_theme, cursor_size, cmm->wlShm);
+
+ cmm->cursors = MEM_ALLOC(ARRAY_LENGTH(cursors) * sizeof(cmm->cursors[0]));
+
+ for (i = 0; i < ARRAY_LENGTH(cursors); i++) {
+ cursor = NULL;
+
+ for (j = 0; !cursor && j < cursors[i].count; ++j) {
+ cursor = wl_cursor_theme_get_cursor(
+ cmm->cursor_theme, cursors[i].names[j]);
+ }
+
+ if (!cursor) {
+ fprintf(stderr, "could not load cursor '%s'\n",
+ cursors[i].names[0]);
+ }
+
+ cmm->cursors[i] = cursor;
+ }
+}
+
+static void
+destroy_cursors(struct wlContextCommon *cmm)
+{
+ if (cmm->cursor_theme) {
+ wl_cursor_theme_destroy(cmm->cursor_theme);
+ }
+
+ free(cmm->cursors);
+}
+
+/**
+ * Internal method to prepare parts of UI
+ */
+static void
+createShmBuffer(struct wlContextStruct *p_wlCtx)
+{
+ struct wl_shm_pool *pool;
+
+ char filename[] = "/tmp/wayland-shm-XXXXXX";
+ int fd = -1;
+ int size = 0;
+ int width = 0;
+ int height = 0;
+ int stride = 0;
+
+ fd = mkstemp(filename);
+ if (fd < 0) {
+ fprintf(stderr, "open %s failed: %m\n", filename);
+ return;
+ }
+
+ width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
+ height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
+ stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
+
+ size = stride * height;
+ if (ftruncate(fd, size) < 0) {
+ fprintf(stderr, "ftruncate failed: %m\n");
+ close(fd);
+ return;
+ }
+
+ p_wlCtx->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ if (MAP_FAILED == p_wlCtx->data) {
+ fprintf(stderr, "mmap failed: %m\n");
+ close(fd);
+ return;
+ }
+
+ pool = wl_shm_create_pool(p_wlCtx->cmm.wlShm, fd, size);
+ p_wlCtx->wlBuffer = wl_shm_pool_create_buffer(pool, 0,
+ width,
+ height,
+ stride,
+ WL_SHM_FORMAT_ARGB8888);
+
+ if (NULL == p_wlCtx->wlBuffer) {
+ fprintf(stderr, "wl_shm_create_buffer failed: %m\n");
+ close(fd);
+ return;
+ }
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ return;
+}
+
+static void
+destroyWLContextCommon(struct wlContextCommon *p_wlCtx)
+{
+ destroy_cursors(p_wlCtx);
+
+ if (p_wlCtx->pointer_surface) {
+ wl_surface_destroy(p_wlCtx->pointer_surface);
+ }
+
+ if (p_wlCtx->wlCompositor) {
+ wl_compositor_destroy(p_wlCtx->wlCompositor);
+ }
+}
+
+static void
+destroyWLContextStruct(struct wlContextStruct *p_wlCtx)
+{
+ if (p_wlCtx->wlSurface) {
+ wl_surface_destroy(p_wlCtx->wlSurface);
+ }
+
+ if (p_wlCtx->ctx_image) {
+ cairo_surface_destroy(p_wlCtx->ctx_image);
+ p_wlCtx->ctx_image = NULL;
+ }
+}
+
+static int
+createWLContext(struct wlContextStruct *p_wlCtx)
+{
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+
+ p_wlCtx->wlSurface = wl_compositor_create_surface(p_wlCtx->cmm.wlCompositor);
+ if (NULL == p_wlCtx->wlSurface) {
+ printf("Error: wl_compositor_create_surface failed.\n");
+ destroyWLContextCommon(&p_wlCtx->cmm);
+ abort();
+ }
+
+
+ createShmBuffer(p_wlCtx);
+
+ wl_display_flush(p_wlCtx->cmm.wlDisplay);
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+
+ return 0;
+}
+
+static void
+drawImage(struct wlContextStruct *p_wlCtx)
+{
+ struct wl_callback *callback;
+
+ int width = 0;
+ int height = 0;
+ int stride = 0;
+ void *data = NULL;
+
+ width = cairo_image_surface_get_width(p_wlCtx->ctx_image);
+ height = cairo_image_surface_get_height(p_wlCtx->ctx_image);
+ stride = cairo_image_surface_get_stride(p_wlCtx->ctx_image);
+ data = cairo_image_surface_get_data(p_wlCtx->ctx_image);
+
+ memcpy(p_wlCtx->data, data, stride * height);
+
+ wl_surface_attach(p_wlCtx->wlSurface, p_wlCtx->wlBuffer, 0, 0);
+ wl_surface_damage(p_wlCtx->wlSurface, 0, 0, width, height);
+
+ callback = wl_surface_frame(p_wlCtx->wlSurface);
+ wl_callback_add_listener(callback, &frame_listener, NULL);
+
+ wl_surface_commit(p_wlCtx->wlSurface);
+
+ wl_display_flush(p_wlCtx->cmm.wlDisplay);
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+}
+
+static void
+create_ivisurface(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ cairo_surface_t* surface)
+{
+ struct ivi_surface *ivisurf = NULL;
+
+ p_wlCtx->ctx_image = surface;
+
+ p_wlCtx->id_surface = id_surface;
+ wl_list_init(&p_wlCtx->link);
+ wl_list_insert(p_wlCtx->cmm.list_wlContextStruct, &p_wlCtx->link);
+
+ createWLContext(p_wlCtx);
+
+ ivisurf = ivi_application_surface_create(p_wlCtx->cmm.iviApplication,
+ id_surface, p_wlCtx->wlSurface);
+ if (ivisurf == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ return;
+ }
+
+ drawImage(p_wlCtx);
+
+ wl_display_roundtrip(p_wlCtx->cmm.wlDisplay);
+}
+
+static void
+create_ivisurfaceFromFile(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ const char* imageFile)
+{
+ cairo_surface_t* surface = load_cairo_surface(imageFile);
+
+ if (NULL == surface) {
+ fprintf(stderr, "Failed to load_cairo_surface %s\n", imageFile);
+ return;
+ }
+
+ create_ivisurface(p_wlCtx, id_surface, surface);
+}
+
+static void
+set_hex_color(cairo_t *cr, uint32_t color)
+{
+ cairo_set_source_rgba(cr,
+ ((color >> 16) & 0xff) / 255.0,
+ ((color >> 8) & 0xff) / 255.0,
+ ((color >> 0) & 0xff) / 255.0,
+ ((color >> 24) & 0xff) / 255.0);
+}
+
+static void
+create_ivisurfaceFromColor(struct wlContextStruct *p_wlCtx,
+ uint32_t id_surface,
+ uint32_t width, uint32_t height,
+ uint32_t color)
+{
+ cairo_surface_t *surface = NULL;
+ cairo_t *cr = NULL;
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+
+ cr = cairo_create(surface);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_rectangle(cr, 0, 0, width, height);
+ set_hex_color(cr, color);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+
+ create_ivisurface(p_wlCtx, id_surface, surface);
+}
+
+/**
+ * Internal method to set up UI by using ivi-hmi-controller
+ */
+static void
+create_background(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_background(p_wlCtx->cmm.hmiCtrl, id_surface);
+}
+
+static void
+create_panel(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_panel(p_wlCtx->cmm.hmiCtrl, id_surface);
+}
+
+static void
+create_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile, uint32_t number)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_button(p_wlCtx->cmm.hmiCtrl, id_surface, number);
+}
+
+static void
+create_home_button(struct wlContextStruct *p_wlCtx, const uint32_t id_surface,
+ const char* imageFile)
+{
+ create_ivisurfaceFromFile(p_wlCtx, id_surface, imageFile);
+ ivi_hmi_controller_set_home_button(p_wlCtx->cmm.hmiCtrl, id_surface);
+}
+
+static void
+create_workspace_background(
+ struct wlContextStruct *p_wlCtx, struct hmi_homescreen_srf *srf)
+{
+ create_ivisurfaceFromColor(p_wlCtx, srf->id, 1, 1, srf->color);
+ ivi_hmi_controller_set_workspacebackground(p_wlCtx->cmm.hmiCtrl, srf->id);
+}
+
+static int compare_launcher(const void* data1, const void* data2)
+{
+ struct hmi_homescreen_launcher *launcher1 = *(struct hmi_homescreen_launcher**)data1;
+ struct hmi_homescreen_launcher *launcher2 = *(struct hmi_homescreen_launcher**)data2;
+ return launcher1->workspace_id - launcher2->workspace_id;
+}
+
+static void
+create_launchers(struct wlContextCommon *cmm, struct wl_list *launcher_list)
+{
+ int launcher_count = wl_list_length(launcher_list);
+
+ if (0 == launcher_count) {
+ return;
+ }
+
+ struct hmi_homescreen_launcher** launchers;
+ launchers = MEM_ALLOC(launcher_count * sizeof(*launchers));
+
+ int ii = 0;
+ struct hmi_homescreen_launcher *launcher = NULL;
+
+ wl_list_for_each(launcher, launcher_list, link) {
+ launchers[ii] = launcher;
+ ii++;
+ }
+
+ qsort(launchers, launcher_count, sizeof(*launchers), compare_launcher);
+
+ int start = 0;
+
+ for (ii = 0; ii < launcher_count; ii++) {
+
+ if (ii != launcher_count -1 &&
+ launchers[ii]->workspace_id == launchers[ii + 1]->workspace_id) {
+ continue;
+ }
+
+ struct wl_array surface_ids;
+ wl_array_init(&surface_ids);
+
+ int jj = 0;
+ for (jj = start; jj <= ii; jj++) {
+ uint32_t *id = wl_array_add(&surface_ids, sizeof(*id));
+ *id = launchers[jj]->icon_surface_id;
+
+ struct wlContextStruct *p_wlCtx = MEM_ALLOC(sizeof(*p_wlCtx));
+ p_wlCtx->cmm = *cmm;
+
+ create_ivisurfaceFromFile(p_wlCtx, *id, launchers[jj]->icon);
+ }
+
+ ivi_hmi_controller_add_launchers(cmm->hmiCtrl, &surface_ids, 256);
+ wl_array_release(&surface_ids);
+ start = ii + 1;
+ }
+
+ free(launchers);
+}
+
+static void sigFunc(int signum)
+{
+ gRun = 0;
+}
+
+/**
+ * Internal method to read out weston.ini to get configuration
+ */
+static struct hmi_homescreen_setting*
+hmi_homescreen_setting_create(void)
+{
+ struct hmi_homescreen_setting* setting = MEM_ALLOC(sizeof(*setting));
+
+ wl_list_init(&setting->workspace_list);
+ wl_list_init(&setting->launcher_list);
+
+ struct weston_config *config = NULL;
+ config = weston_config_parse("weston.ini");
+
+ struct weston_config_section *shellSection = NULL;
+ shellSection = weston_config_get_section(config, "ivi-shell", NULL, NULL);
+
+ weston_config_section_get_string(
+ shellSection, "cursor-theme", &setting->cursor_theme, NULL);
+
+ weston_config_section_get_int(shellSection, "cursor-size", &setting->cursor_size, 32);
+
+ uint32_t workspace_layer_id;
+ weston_config_section_get_uint(
+ shellSection, "workspace-layer-id", &workspace_layer_id, 3000);
+
+ weston_config_section_get_string(
+ shellSection, "background-image", &setting->background.filePath,
+ DATADIR "/weston/background.png");
+
+ weston_config_section_get_uint(
+ shellSection, "background-id", &setting->background.id, 1001);
+
+ weston_config_section_get_string(
+ shellSection, "panel-image", &setting->panel.filePath,
+ DATADIR "/weston/panel.png");
+
+ weston_config_section_get_uint(
+ shellSection, "panel-id", &setting->panel.id, 1002);
+
+ weston_config_section_get_string(
+ shellSection, "tiling-image", &setting->tiling.filePath,
+ DATADIR "/weston/tiling.png");
+
+ weston_config_section_get_uint(
+ shellSection, "tiling-id", &setting->tiling.id, 1003);
+
+ weston_config_section_get_string(
+ shellSection, "sidebyside-image", &setting->sidebyside.filePath,
+ DATADIR "/weston/sidebyside.png");
+
+ weston_config_section_get_uint(
+ shellSection, "sidebyside-id", &setting->sidebyside.id, 1004);
+
+ weston_config_section_get_string(
+ shellSection, "fullscreen-image", &setting->fullscreen.filePath,
+ DATADIR "/weston/fullscreen.png");
+
+ weston_config_section_get_uint(
+ shellSection, "fullscreen-id", &setting->fullscreen.id, 1005);
+
+ weston_config_section_get_string(
+ shellSection, "random-image", &setting->random.filePath,
+ DATADIR "/weston/random.png");
+
+ weston_config_section_get_uint(
+ shellSection, "random-id", &setting->random.id, 1006);
+
+ weston_config_section_get_string(
+ shellSection, "home-image", &setting->home.filePath,
+ DATADIR "/weston/home.png");
+
+ weston_config_section_get_uint(
+ shellSection, "home-id", &setting->home.id, 1007);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-color",
+ &setting->workspace_background.color, 0x99000000);
+
+ weston_config_section_get_uint(
+ shellSection, "workspace-background-id",
+ &setting->workspace_background.id, 2001);
+
+ struct weston_config_section *section = NULL;
+ const char *name = NULL;
+
+ uint32_t icon_surface_id = workspace_layer_id + 1;
+
+ while (weston_config_next_section(config, &section, &name)) {
+
+ if (0 == strcmp(name, "ivi-launcher")) {
+
+ struct hmi_homescreen_launcher *launcher = NULL;
+ launcher = MEM_ALLOC(sizeof(*launcher));
+ wl_list_init(&launcher->link);
+ launcher->icon_surface_id = icon_surface_id;
+ icon_surface_id++;
+
+ weston_config_section_get_string(section, "icon", &launcher->icon, NULL);
+ weston_config_section_get_string(section, "path", &launcher->path, NULL);
+ weston_config_section_get_uint(section, "workspace-id", &launcher->workspace_id, 0);
+
+ wl_list_insert(setting->launcher_list.prev, &launcher->link);
+ }
+ }
+
+ weston_config_destroy(config);
+ return setting;
+}
+
+/**
+ * Main thread
+ *
+ * The basic flow are as followed,
+ * 1/ read configuration from weston.ini by hmi_homescreen_setting_create
+ * 2/ draw png file to surface according to configuration of weston.ini and
+ * set up UI by using ivi-hmi-controller protocol by each create_* method
+ */
+static void*
+client_thread(void *p_ret)
+{
+ struct wlContextCommon wlCtxCommon;
+ struct wlContextStruct wlCtx_BackGround;
+ struct wlContextStruct wlCtx_Panel;
+ struct wlContextStruct wlCtx_Button_1;
+ struct wlContextStruct wlCtx_Button_2;
+ struct wlContextStruct wlCtx_Button_3;
+ struct wlContextStruct wlCtx_Button_4;
+ struct wlContextStruct wlCtx_HomeButton;
+ struct wlContextStruct wlCtx_WorkSpaceBackGround;
+ struct wl_list launcher_wlCtxList;
+
+ memset(&wlCtxCommon, 0x00, sizeof(wlCtxCommon));
+ memset(&wlCtx_BackGround, 0x00, sizeof(wlCtx_BackGround));
+ memset(&wlCtx_Panel, 0x00, sizeof(wlCtx_Panel));
+ memset(&wlCtx_Button_1, 0x00, sizeof(wlCtx_Button_1));
+ memset(&wlCtx_Button_2, 0x00, sizeof(wlCtx_Button_2));
+ memset(&wlCtx_Button_3, 0x00, sizeof(wlCtx_Button_3));
+ memset(&wlCtx_Button_4, 0x00, sizeof(wlCtx_Button_4));
+ memset(&wlCtx_HomeButton, 0x00, sizeof(wlCtx_HomeButton));
+ memset(&wlCtx_WorkSpaceBackGround, 0x00, sizeof(wlCtx_WorkSpaceBackGround));
+ wl_list_init(&launcher_wlCtxList);
+ wlCtxCommon.list_wlContextStruct = MEM_ALLOC(sizeof(struct wl_list));
+ assert(wlCtxCommon.list_wlContextStruct);
+ wl_list_init(wlCtxCommon.list_wlContextStruct);
+
+ struct hmi_homescreen_setting *hmi_setting = hmi_homescreen_setting_create();
+ wlCtxCommon.hmi_setting = hmi_setting;
+
+ gRun = 1;
+
+ wlCtxCommon.wlDisplay = wl_display_connect(NULL);
+ if (NULL == wlCtxCommon.wlDisplay) {
+ printf("Error: wl_display_connect failed.\n");
+ return NULL;
+ }
+
+ /* get wl_registry */
+ wlCtxCommon.wlRegistry = wl_display_get_registry(wlCtxCommon.wlDisplay);
+ wl_registry_add_listener(wlCtxCommon.wlRegistry,
+ &registry_listener, &wlCtxCommon);
+ wl_display_dispatch(wlCtxCommon.wlDisplay);
+ wl_display_roundtrip(wlCtxCommon.wlDisplay);
+
+ if (wlCtxCommon.hmi_setting->cursor_theme) {
+ create_cursors(&wlCtxCommon);
+
+ wlCtxCommon.pointer_surface =
+ wl_compositor_create_surface(wlCtxCommon.wlCompositor);
+
+ wlCtxCommon.current_cursor = CURSOR_LEFT_PTR;
+ }
+
+ wlCtx_BackGround.cmm = wlCtxCommon;
+ wlCtx_Panel.cmm = wlCtxCommon;
+ wlCtx_Button_1.cmm = wlCtxCommon;
+ wlCtx_Button_2.cmm = wlCtxCommon;
+ wlCtx_Button_3.cmm = wlCtxCommon;
+ wlCtx_Button_4.cmm = wlCtxCommon;
+ wlCtx_HomeButton.cmm = wlCtxCommon;
+ wlCtx_WorkSpaceBackGround.cmm = wlCtxCommon;
+
+ /* create desktop widgets */
+ create_background(&wlCtx_BackGround, hmi_setting->background.id,
+ hmi_setting->background.filePath);
+
+ create_panel(&wlCtx_Panel, hmi_setting->panel.id,
+ hmi_setting->panel.filePath);
+
+ create_button(&wlCtx_Button_1, hmi_setting->tiling.id,
+ hmi_setting->tiling.filePath, 0);
+
+ create_button(&wlCtx_Button_2, hmi_setting->sidebyside.id,
+ hmi_setting->sidebyside.filePath, 1);
+
+ create_button(&wlCtx_Button_3, hmi_setting->fullscreen.id,
+ hmi_setting->fullscreen.filePath, 2);
+
+ create_button(&wlCtx_Button_4, hmi_setting->random.id,
+ hmi_setting->random.filePath, 3);
+
+ create_workspace_background(&wlCtx_WorkSpaceBackGround,
+ &hmi_setting->workspace_background);
+
+ create_launchers(&wlCtxCommon, &hmi_setting->launcher_list);
+
+ create_home_button(&wlCtx_HomeButton, hmi_setting->home.id,
+ hmi_setting->home.filePath);
+ /* signal handling */
+ signal(SIGINT, sigFunc);
+ signal(SIGKILL, sigFunc);
+
+ while(gRun) {
+ wl_display_dispatch(wlCtxCommon.wlDisplay);
+ }
+
+ struct wlContextStruct* pWlCtxSt = NULL;
+ wl_list_for_each(pWlCtxSt, wlCtxCommon.list_wlContextStruct, link) {
+ destroyWLContextStruct(pWlCtxSt);
+ }
+
+ destroyWLContextCommon(&wlCtxCommon);
+ free(wlCtxCommon.list_wlContextStruct);
+
+ return NULL;
+}
+
+/*****************************************************************************
+ * exported functions
+ ****************************************************************************/
+int
+hmi_client_start(void)
+{
+ pthread_attr_t thread_attrs;
+ uint32_t ret = 0;
+ pthread_t thread;
+
+ pthread_attr_init(&thread_attrs);
+ pthread_attr_setdetachstate(&thread_attrs, PTHREAD_CREATE_JOINABLE);
+ ret = pthread_create(&thread, &thread_attrs, client_thread, NULL);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to start internal receive \
+ thread. returned %d\n", ret);
+ }
+
+ return 0;
+}
diff --git a/ivi-shell/hmi-controller-homescreen.h b/ivi-shell/hmi-controller-homescreen.h
new file mode 100644
index 0000000..31416de
--- /dev/null
+++ b/ivi-shell/hmi-controller-homescreen.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2013 DENSO CORPORATION
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _HMI_CONTROLLER_HOMESCREEN_H_
+#define _HMI_CONTROLLER_HOMESCREEN_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+int hmi_client_start(void);
+
+#ifdef __cplusplus
+} /**/
+#endif /* __cplusplus */
+
+#endif /* _HMI_CONTROLLER_HOMESCREEN_H_ */
diff --git a/ivi-shell/hmi-controller.c b/ivi-shell/hmi-controller.c
index bd311ea..3cfb19b 100644
--- a/ivi-shell/hmi-controller.c
+++ b/ivi-shell/hmi-controller.c
@@ -54,6 +54,7 @@
#include <time.h>

#include "weston-layout.h"
+#include "hmi-controller-homescreen.h"
#include "ivi-hmi-controller-server-protocol.h"

/*****************************************************************************
@@ -1749,7 +1750,7 @@ bind_hmi_controller(struct wl_client *client,
static void
launch_hmi_client(void *data)
{
- /*Nothing to do here*/
+ hmi_client_start();
}

/*****************************************************************************
--
1.8.3.1
Pekka Paalanen
2014-04-25 11:55:54 UTC
Permalink
On Thu, 20 Mar 2014 16:00:57 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> This is launched from hmi-controller by using hmi_client_start and create a
> pthread.
>
> The basic flow is as followed,
> 1/ create pthread
> 2/ read configuration from weston.ini.
> 3/ draw png file to surface according to configuration of weston.ini
> 4/ set up UI by using ivi-hmi-controller protocol
> 5/ Enter event loop
> 6/ If a surface receives touch/pointer event, followings are invoked according
> to type of event and surface
> 6-1/ If a surface to launch ivi_application receive touch up, it execs
> ivi-application configured in weston.ini.
> 6-2/ If a surface to switch layout mode receive touch up, it sends a request,
> ivi_hmi_controller_switch_mode, to hmi-controller.
> 6-3/ If a surface to show workspace having launchers, it sends a request,
> ivi_hmi_controller_home, to hmi-controller.
> 6-4/ If touch down events happens in workspace,
> ivi_hmi_controller_workspace_control is sent to slide workspace.
> When control finished, event: ivi_hmi_controller_workspace_end_control
> is received.
>
> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - squash Makefile to this patch
>
> Changes for v3 and v4:
> - nothing. Version number aligned to the first patch
>
> Changes for v5:
> - usleep with roundtrip uses CPU. replace them with wl_display_dispatch
>
> ivi-shell/Makefile.am | 2 +
> ivi-shell/hmi-controller-homescreen.c | 1369 +++++++++++++++++++++++++++++++++
> ivi-shell/hmi-controller-homescreen.h | 36 +
> ivi-shell/hmi-controller.c | 3 +-
> 4 files changed, 1409 insertions(+), 1 deletion(-)
> create mode 100644 ivi-shell/hmi-controller-homescreen.c
> create mode 100644 ivi-shell/hmi-controller-homescreen.h

Would it not be simpler and more robust to make this an independent
program like e.g. clients/desktop-shell.c is, rather than running it in
a thread in the compositor?

I would certainly prefer it to be. We would avoid threads in the
compositor, and pulling in client side stuff. Now there is a huge risk
you might be calling compositor functions from client code, and a crash
in the client code would bring the whole compositor down.

If we look at weston-desktop-shell, if it crashes, Weston will respawn
it so fast that a user often does not even notice anything happened. ;-)

And when you attach gdb, it won't stop also the compositor.


Thanks,
pq
Nobuhiko Tanibata
2014-05-20 10:02:56 UTC
Permalink
2014-04-25 20:55 ? Pekka Paalanen ????????:
> On Thu, 20 Mar 2014 16:00:57 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> This is launched from hmi-controller by using hmi_client_start and
>> create a
>> pthread.
>>
>> The basic flow is as followed,
>> 1/ create pthread
>> 2/ read configuration from weston.ini.
>> 3/ draw png file to surface according to configuration of weston.ini
>> 4/ set up UI by using ivi-hmi-controller protocol
>> 5/ Enter event loop
>> 6/ If a surface receives touch/pointer event, followings are invoked
>> according
>> to type of event and surface
>> 6-1/ If a surface to launch ivi_application receive touch up, it execs
>> ivi-application configured in weston.ini.
>> 6-2/ If a surface to switch layout mode receive touch up, it sends a
>> request,
>> ivi_hmi_controller_switch_mode, to hmi-controller.
>> 6-3/ If a surface to show workspace having launchers, it sends a
>> request,
>> ivi_hmi_controller_home, to hmi-controller.
>> 6-4/ If touch down events happens in workspace,
>> ivi_hmi_controller_workspace_control is sent to slide workspace.
>> When control finished, event:
>> ivi_hmi_controller_workspace_end_control
>> is received.
>>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2:
>> - squash Makefile to this patch
>>
>> Changes for v3 and v4:
>> - nothing. Version number aligned to the first patch
>>
>> Changes for v5:
>> - usleep with roundtrip uses CPU. replace them with
>> wl_display_dispatch
>>
>> ivi-shell/Makefile.am | 2 +
>> ivi-shell/hmi-controller-homescreen.c | 1369
>> +++++++++++++++++++++++++++++++++
>> ivi-shell/hmi-controller-homescreen.h | 36 +
>> ivi-shell/hmi-controller.c | 3 +-
>> 4 files changed, 1409 insertions(+), 1 deletion(-)
>> create mode 100644 ivi-shell/hmi-controller-homescreen.c
>> create mode 100644 ivi-shell/hmi-controller-homescreen.h
>
> Would it not be simpler and more robust to make this an independent
> program like e.g. clients/desktop-shell.c is, rather than running it in
> a thread in the compositor?
>
> I would certainly prefer it to be. We would avoid threads in the
> compositor, and pulling in client side stuff. Now there is a huge risk
> you might be calling compositor functions from client code, and a crash
> in the client code would bring the whole compositor down.
>
> If we look at weston-desktop-shell, if it crashes, Weston will respawn
> it so fast that a user often does not even notice anything happened.
> ;-)

I agree. I apply your comments in v5. it is now process.
Before, I implemented it as a thread to reduce overhead of process
dispatch.
I experienced such a overhead before. However at first, I shall follow
wayland current sample like desktop-shell, invoke it as process.
If ivi vendor want to it as a thread with the same concerning, it can
easily do it by itself.

BR,
Nobohiko

>
> And when you attach gdb, it won't stop also the compositor.
>
>
> Thanks,
> pq
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Nobuhiko Tanibata
2014-03-17 06:29:56 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

data/Makefile.am | 14 +++++++++++++-
data/background.png | Bin 0 -> 245579 bytes
data/fullscreen.png | Bin 0 -> 3406 bytes
data/home.png | Bin 0 -> 4629 bytes
data/icon_ivi_clickdot.png | Bin 0 -> 39523 bytes
data/icon_ivi_flower.png | Bin 0 -> 24475 bytes
data/icon_ivi_simple-egl.png | Bin 0 -> 29316 bytes
data/icon_ivi_simple-shm.png | Bin 0 -> 71120 bytes
data/icon_ivi_smoke.png | Bin 0 -> 46577 bytes
data/panel.png | Bin 0 -> 41955 bytes
data/random.png | Bin 0 -> 4891 bytes
data/sidebyside.png | Bin 0 -> 3929 bytes
data/tiling.png | Bin 0 -> 5620 bytes
13 files changed, 13 insertions(+), 1 deletion(-)
create mode 100644 data/background.png
create mode 100644 data/fullscreen.png
create mode 100644 data/home.png
create mode 100644 data/icon_ivi_clickdot.png
create mode 100644 data/icon_ivi_flower.png
create mode 100644 data/icon_ivi_simple-egl.png
create mode 100644 data/icon_ivi_simple-shm.png
create mode 100644 data/icon_ivi_smoke.png
create mode 100644 data/panel.png
create mode 100644 data/random.png
create mode 100644 data/sidebyside.png
create mode 100644 data/tiling.png

diff --git a/data/Makefile.am b/data/Makefile.am
index a7cc944..2aa6e5c 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -9,7 +9,19 @@ dist_westondata_DATA = \
icon_window.png \
sign_close.png \
sign_maximize.png \
- sign_minimize.png
+ sign_minimize.png \
+ background.png \
+ tiling.png \
+ fullscreen.png \
+ panel.png \
+ random.png \
+ sidebyside.png \
+ home.png \
+ icon_ivi_clickdot.png \
+ icon_ivi_flower.png \
+ icon_ivi_simple-egl.png \
+ icon_ivi_simple-shm.png \
+ icon_ivi_smoke.png

if HAVE_RSVG_CONVERT
wayland_icon_png = wayland.png
diff --git a/data/background.png b/data/background.png
new file mode 100644
index 0000000000000000000000000000000000000000..60c317c945ae3a8c9f0875cc59a80fd248692fac
GIT binary patch
literal 245579
zcmZ^~30RWp`af<tX){@#PSc_(&KzfIX54a1QPG+votZ4BDK$y4#s!ng1x*3Ba?&Xm
z#uirui^>Io5=~KY$rK9(O#xT1NKimf*;GV-%=h;_zjNk)UH|KP+1~es_j(`h=f3aH
z^4$65jNi`B%s(?QFxdIik3alsVDO3lt)anoBmGNj>)xIEmo4yL{k}IKF)ilxA3lK|
zKYiT5;01ce`sHo<&!5Ks7y>si*wypbV+%d5CepxQ^XX4N96z55k?Q6jf5Iq!V2ssd
z-n%|bEdFHcSB|H?IQGw~PaRpV`%ea*4g7o&?-3k%;mPgWb}8sDb7`8jCCd~yO4F2e
z;#e6%4$_o#uD~{B0UH&WinzST-`xG*ZROePl+EzpmN(Z*I>SCcdG>#|UbnA1v|Lkz
z|GT5tZ7c4Y#QFN!&$q#sObx<kPphRsJoYS_8(tu7&G;vO!O at O{$L<i-qE?dspo?ul
z5VDtK7^T=NpC4Cbyi!F&TRyDa{csqrR5>qCXbZ`MAg;1qQetKBTja}arla!NGEm6Z
z1j_|PblhwRH%*;ytttYxvGyvNi?yPwm9-B+aJ!Ieb2JcB>iIo+lcM3Dz-)8h{ERe5
z1Yr at p;8z*|oTH9^#z}}GS8*K_Eu=vH_mV<2^;Qv$g>i^Qsi5S|tF)fV3NA|1zMM~l
zyzlNzWbJE5Pg0T#7a_?^TBPWmvyWsQcOzWc8vdqwddK2VBBUl{aeWM4SS00PL50e;
z#7%FdVOG!Hs0<sQ$6L6;S5~FpTAM{b!I3mdR*Whh>uF53EHWd)L+0wXj7BzL5+FxD
zKwA}s%B^#68l9{?yuzR%InMT`1(*5nW4D%Uv!)h#zx{ErsAG$`kb_>#=b^OkO=Pxq
zr<0AL7p1j<0g@~vZ5<G56+;9SratlvP}O6H{W-x+0FpcgSI<$!m*XFLPQX9s;<$cY
zW at akH^wtnrZ_CxbKUnF>m5(|IH#zT|(XJ||&fb^;i7D}^C(apEa8vFi1>)vc{cYN+
zO}kc+7Q_Yik_V%Pu1q9?|725S>-+2{#UpRgv30oHTEKj#TjnPqE5Y(jBrPp#U^{7p
zsWj}uoyj!V{;xTu^`el;KS4H@&o<Npt>V!^yIQUWRhQZB?>fPZx~O9P&iW*jbdp?1
zv#mDEf#Wf?I~(`u)apU8(@q6|l<}bc8Fz=bI?83oOjASMk~utB^oPa$`Kn<0F;UTb
zOg1R;5f!mR`DS^-nNe^HKnh?)gu8~pb}9T>GhV`W;nf@=IC%=ktyiRd9&C6TG`R3J
zA#T2F6`wyUpT<8-!N#`p+ER}Ey2osWV;vbHyX_w!Sj(ra0)myp0HkjiypRihpZ)+6
zls at z}pCg`NyB8!h)xYq5RW{MZuAFb)FLi9-_aj1cT%{wDhpOQT+iLTX<zcHDy2OOp
z6dP*qyR8g>Qru)fK|`5xfSruCp(MXHHE7OU?~Ka>Omz`~bXec4-!V&kE93hJC!Z1i
z at f-W9H5`1EJs}FG524GXn4QqdzUQn)uPV^<pcY?>msPha<`Dwo*$BuN`kE~~1%@>@
z1V7SE0fr8!Q7z!G at Lpa=e}W|*@w6n$$}9}s<r-RTPOcPk%rFt)jTk#9=IFh^mY`u1
z?h9GFb>mtTK(Z^CAc1yk=Q7T~^MwbPi6Ccjcv(V=d9(`|IOyS%<#uly=GyyM%W at IG
z&eWVj7v+!m0)K6*&Y_suGeExY*Gz)x(!uQdoaEbZTKx%FBY%4+?!EYytt81;`%Or}
zNMlYDmhK_E%dz-ULT`On2XC>3?IM{zvohEinE7`qIhmaq)%aKLS@}nY#?*kkZf$`I
zd%=GQ^?nC?5*@&|A&c^s!w)Q6X_UFOTcbba0%|u&b0GGTnZ<lMVO;Cgu0*tn2J9yZ
zajT1JOn1UdKt4uQwx~NWF5e6N%vUo%3mK<J`D!*lyw>)d+I(60NL6Z)+MYv3HKu&b
zQfQpsN$P0G_E_BEc=0M|`M@`LgsgG_J|bNWdr2=Uw at DRtyaDAcG1|$MUv+3Ftqhb#
zwlM1Pk+IZ2-Hk7#l-2SJHgBoHNsu-m`!@gp8oX*i1roH0Rxzat_XNgi6sxr%@_dEr
zs#Wxx9nt`3>2X#RAMtUb_E4$9E4)3V2Lt={8_(G|bKxmk$O%F64wA at YP8>ms&+*#^
zG9V?xJO3Hf<l+$yQkAIESiu5mKv_sdR`dnZ*TM^XrXm9AivD-VTd~C*3XH0^1jret
zvv2)`(|m7azU*PIpcc9^{U_Qt6Rif2!!=ksJB|5$#EjjzS^Y(i><!H20{wSXu^85q
zkgS2m!m9&Ud`7Q}MJA|IIqg?KtY8gjB<`v>8AKU<ZC(~42u%$oBrpCpYN0%72)E3V
zGh08_L<<Iw;r at V}bw=CBbBJFaa;Oa)^7D&Y5`?xtJL~KSEgncaS`u=Zi3W at S;HEOl
zN+U#F4olknse-cWBQ;~`&mER<eDC%o+8kVdg{Zp at 8z}J_1TrS>QvC)>EYuYuX?AZe
zN4&>+9Wg5X)tObD966lbex)#@u;xoE+6>*?7Evz(mxL{ENp!=Ysj&<Xam|h8+QZy`
zWxMuxh|c4d8^Z5mceIu%1U(4a%b#-hxhkgE- at _$)8=HGnaW62ioTe-G{>cxZVWM;U
z20+0ZQ-**fbulOvBRYk<#3|XmHgLWoCQl at ezBca0am?v6d-vemky85hv5Pl19GTh|
zK35uiGlsw3bICzkK?Js~z<sbVQd6JV_(ex;H*WPIpSo%Aj}N%=!2_G;uckSk3y>aH
zoc0yEmsopNk4$43fG3Vuta_E(Li)lo^PUD1u0vV3&seH&Kz~8g at A$?=A{H92w5t*}
zDE-VAL#@#FcW_t~lStaxB>l;!+0VCCQ{kS7y<X6^-|bp!it|CAQps4jOcmNW_etZ~
zqpnH3FwjL&FSu{tIbU(`bMD)1?=?=JChVF~kHUtN1E9}YKNcU)2y7N0r!($91Koo~
z2i&P2<o74dFrO<Wp;pl6rhPj at 94Kz&i_i-V_VAHcxGG>8w)r{rqkpS$;}xcUIA_mI
zVHL@>-n7F%0)QyMZ;EE$8Rs_I&A~^_g}ato_^%3)bYYqqvUsvJn6h$~04?LTk#f!Y
ziAaG-s2jPBn_*aXAO&ZpRVTWoTB!;jL%E>y0q+%zCV!P1anibKB8ktTm4iqNwCL<d
zl-=bx^+9T%)YcFhnZuf#3`m<I&@}kor0^Kr={WBbk>eFj?DCk(`?SGOreT$xkHPcR
zUCOLNf|GT=`uG`o at GF!!lyyJqVX@{;3v6MD1pAoI!fa^@4x_ip=z*_SHK9FhO`L<Z
zHdZ(gf*x%(kFg{77Qv4|B`B}9%sgw9ymmf{pS&>E+|-G*KL{q!gMTMOKTeQ3Hd53m
zjtY`~y4yxR!lQZHWxA5bd?p2A8b94Z^UlMey~y9Rr0ubTJF<|b{U#WaZ7tcowr<!Z
zUw^X+-RJn*uB1UELvU8*pGPGmw0>Bx-({{Xbq>8BwKdhgr>T^{VSHP(rEcEqqN2Yw
z`eKVMIhlmOw&jx^QQL3j8+wZ_z`X at d^-;j)KCh9iXajBQ4G&a%^w`BEa&yQbC$E(J
z$Ury{(!<Tqh7--1?&$QAEsG^nX{PK`3Ma0GP&{86m0D<#ozJM{zJ;2p5tXwT5&&IS
ziz_Hql)KKg1HP0L6?`Tsf74#tEY=s5gdd(gglijPF=!y#z6Tc5&Wxx2)JD4zcrIvl
zOQXGF<AHSNzRXKZM5O}kcgUr>r>7szd49b+<Rsjyj_$#!yUYaJWV?z&v94+tLL{}m
zFRHZ2-yp6LEo9R}-z*c&{fbj)4XzTRxvFZ5YQ_^3!*)0Iz?Ye%^ZUht0#~6u{yCQ2
z0wlZQf%+y()o6vPvz$L@&2l!4 at pUyotF8_nWA$B98Fn>)y^3Fbk=CSu^aixZc&;0x
z^o{D>XgH0T_d&bN#)*99laWfWgeIk|FwyifSl$GZgcX at -;u{YqdSI(`h6ZsDt{DZS
zL!j_n$+j?8g8=8bZDa5+ at ***@SUVRMESJDdHXZzJS0#u&4mWo$AM|1)Dz6Of6*a{+
zc##9)-r3mx`5GX5>>Mtk>5RbDr6kbjB8Ai;OdSMn!#*yvWdZwUT{`Jp6W_t(=Nv}#
zBao~L6nLoIdm<6lOEu<(owqp#CBsxkWJ^7#X)T`is)MtI2`?5|$Ag^jZRw9h%$X#W
z^wxO0a6-<pqA-Q4H7Q0)Ht!4_Gi)JYid<cY!%YlW at s+5iT`=~eEf5%K8~3;K?yQh%
zXmXuo;(Z$FTtGT|6uNVKpM7=uff#$7{+~)G2D&pE+p{E&!5FuD=-uw&&RLX at UFE{6
zwyQZDYq<+)IJr0~JXu|ewdxXFJtgq)BiL7Xj`}%NnM3z7zht=9d4eHbph~y9>KSUH
z0^nm1lf92P at MHS1+zTA3#zl0q*x3F4Y at pRVp%Hm0<7M1{M(uu&f9`&iMpp5nd9#M+
z$>({+Q-^84S&aKR6U&P-F1ethWM-lr$Z-(O0xEe}9}dIOpz*7CZg=vy7rq3De1 at OP
zKxzCo>fp_5Ei|OI5G$$k_8*N*CT5_Rw-EWDN}YA23aT|iA%9T!V~Gm1a>PRDQTSLl
z3P(PNT1AGPjzfdAjYHlce42LQjbE_>+?FEmVlR68Apud5WRPeAeq&J0v6e2pPmA%3
zy%^IGXa!-Vtes^lC6$54gJ4Kl%rP21-l06e$6&pA-SF7I;glXm at e5aEn+%+ey|$&Q
zr8Lu7(EfPk2k|QS^WNPZ%P2pZd~fhMR_)`J)D5ZF*q}WIr}{8Gq7ggit4F3NvXkhP
z1<$)}0l~P{A3O1SG$n;1f4D~8sK+G;rwR#L%P*N-q9N5cp>%5r%KcaP=gq-!nJaiv
z{#4A32OKjJ5B7VCbljS$tcO2pR at 2u)w6~y|%)P;3ejHJtX1?E>KkGQvV?#DW^=@}j
zys-evJxRM!(I_17+-S#gd7(^I2Un|8XKArZ--==!Q~Un+W-?P8+;_OeUHJ^E{^%4M
z<SHXX0y*Q{<l>!b<*&a?o`9ti8)Gf)-M~BkwEB{e;t|6JvgWVT_LD^3t=HK#e0(4S
za34_zcj%qHaE|qU`IxTWXbr&R*r3)DI7LyYCSq%GwIt}M!d;*Qgz$G)zBd_BJhaX8
zra`RB0PWmwNUZIo;6I}<O!K5LXYmqv7#tmNbZ9-Wg{DVW_9O2~i{)ONF@}<sjs)Pn
z$z~<VAm6cz3<UA4LpF^0Va<lLOSzt3w1G(&KU<LO>%1#?f1?xgTmiR?^Uh2<{5G-g
zeM7yYooOV<FV-2Xn&LkSfk5?`OQPDoX-jgzmkmz at O&cstZ<hF^uuTo1?(r*MHp(e#
z>OC9g%3Vnks$H>>ahtxcT~bd=?|cWc1)#YP(UWY}mIb=x>V^q++DfTLuz^Smss_s9
z)n#(i&BomrUXlTF%YGUNl9016cv_JXZtR at 6kBI?ki`G*3<P<qs3PeXo>|EGGmJEzD
zLs`|+c~(ECX*!k0S)1fxU*Ne(Yb09jlUP`9q?IiI?}_xlvUzOMhG8{th+)OwXv~?P
zMXRHH#pF4kcY?d=7_Pv7fznmx%j_M86flhJC%=b<;;hrnlv5+sfdZwi=d0n?d`RbR
zT!LBOtgpD#7R~Egt#c%if(;9$qW(3DdDqX at tfnIZKv1*6MURmzNjG*xa|`r&$>3Op
z{E at B@^HTzdsh(o+bW>%xJCpK<TI1`R_;_5twd<~6)XDH6akutJ`Eb*#479bYS+F|M
zi;_~MO8{ko2Bk}d%3uG25$j}K+tZqVa~CXY?{-hxH+O$~;1lj+ at L$}8=5U9WoMEuy
zaOHLA8zn6s2bHUKsj;ACatjZH%8yh{mCC29ALe#eiykVOLgl581J-6yPpU`uG7GQ~
zjhel45Y~h?P<!Ns-^+lw&0tKNDT<k0Uq}{;({bYt!imhJ!B$3o4C|v5!t#jYoKx|T
z51^qvhlg9eQ at vt40yn>H7w4zpMk5+f2O`L7n}m<x6-Z4=aS=9Hc8~_vIpLBA!mhvW
zEaw0*GItcmhNQU)no|KASj&b6_Kp9(K|M^8`{@jR`OmHSWa+cVe-39DsQx?0tQ!RB
z^UmfcI|-&^^4Zka7VfM9yU;_8!vM at +dyuK>d9)?SAn9cKz#|I1V<gmDk$nCF%jxHj
z$nhdb|6I-QyHXbt%bvN`5y;fyoTkFhB=!V&7XX?S8*-FWR^1^k>vJuQAVvbXKo@!c
zGR+m{QHMj==}TMt4Wy00i#RAYBVI<k4gxEO+ZDfEWm9sKi%p$aY;pP7FiGmJsu$Je
zkIRb6v)~>npuOt7gOSOt(HQPq8~k{G!qLfK_}w*P6Vh)6QnnAzXo?4Nt%V^0sb!|_
z)rf&)=`iEA>2pp#{^8`L%^$W0*i{M(7+~+9zUu7c#u~*N!PJ2)UpHtKg$y>*3=OZ^
z;{h-)kI-jNn}q&z1~3jVm- at J=uGx!ylVJHK8aY6j+Fp~A9vU8lVI^X2a^6OUFz3pX
zePLjvL-V>p)g#J!uy5N|WqQzNz-)C`+}Y22tCubLXi1zuPM(Nvkkp8}py$x&Y8fND
zbw59s7lBZ}fMggP!yn*(x=Yw@(+$AI51O&OFOoN%H9ixl0Luoy*oNeQOgEMXH-?|W
zE8+2iF$*D at _m!FgGa$Vh!yfjyD4&wj*ToXAcXF|_^rWWqgO at c3f|$m2a05kck6AWy
zHf27Hv3t{V+KL{~+5v^Y$eP1bB958&`!w>0xu%X~faNsoZ&C3%|Ngu_E08h_{u4NN
z<4*s7;%Y_q_c`PyTF}Q5*O_T^H>E*?2w at 4}qdIL_+Cw at Gi<9GJx`YqBc^!(btEWF-
z`9$qy>Z1c*B-hG&JOPZqF1MjZkFB5kBO9pu4m-VRi(=+V$6+7Vf&$n~nf5a<bp10C
z>i{B6{YoWob$by9lS8qR7`b(F$W94LTR8d>DVvtZl6Y1+lGJm;CNV_)R$;M4s{oQb
zMr_D~VRT9h(m at 7)DQc7OyKR_L6N3A)5X@|yB3}(`4G&6TucDV_I?Z!YJ*%DMOe44C
zK*J`T<>Mi~tbM?l^)EWKo69~f`WzAWPnRA&J7cM at ErT~P9~$2N__72jRvj1*P5=%m
z_`Ut(WkpwQ?j!Kfq0suWfpeAI`nI&Zpki$pd&IGo9&={cOY<gXb{yUj4L0xD2o}t(
zhFS9OgJP_rzPewuuqABR0$Rz9ctUo%cedr3U$I=(+A6ahYo`BL8T}``)u}w9QCNlw
zJ1&)ERj)e7_%t(JL{VS3l|xg>AQiZ}iRS7;nq58H2sIK}kaET=;vUhm7*2Q~od^Ed
z6di!hF9KYTQ#pm6KJuZN6MT#EjeQSzN6DZI`%$eZu{EebH6VYX59fk^^S$~QSn<|V
zzH3`%7>l01Hv0WMKbph-URW)6DtVM<d)Iggxnf4XbKl1xO;w>BFh&OOaZ8al52Oj1
zeTw&Qv8pssUjQ}ElcWgFfB9iV9)gk2nPt9Jyx$I$Ne(YRgUxqzbQLLRlBMnreUHIi
z?GEHF)p}`LvE!R<phJE*nDweWiTnYarQmmCDN at fAebVFq9&|!<{FL~e&yO^k{TFJ;
zLgu7Ac<XTS>cBJmm`YbKQC?rVo6ht%R%<RNdH0w|N)1-E#AVTT8;OhIhsS#lU+Y%+
zT8UH#>O+|CCXG9yqwQ!U6LB_p)FC~I4Ek~NVanc0#R4ydrQ$WDVo%GR6`{_Kko3Yi
zH<f=PK{rLcZVU3A!_bGtG at unZ&eoer`emQLtN3gNx9K~3&1EGiZe`81fv`D4n?{|!
zJ}vErwiM8GIrE|1z$CKij0X#IDmGVRWUVFe314Qy_thN)K^?fu3mf?>MOL8Tx5PMg
z2=tGe9+(%XAWTH`$F*Or($&cCDV-zPyG@}p^`wUb3~_!(E4JP$8xZnRWOW>skZEZ=
z2g<z_ZKTZ(>O+{JV1M%4Sb$VC|B;o!2c!3gE|VnRl=J+f)35YP%tq}8D(vHYYw#-N
zm#fd7YMI`m>Q#)W{0 at +!tQ6JwnSQKB#z>8SihdW_ at x80EwA<Vq4Mv+wL01(02xh|c
zgR*X9t?@^@jDcQU3vtVOZ`)14shzXW>TjyPwxJowDWiX4ouCm+T`^d>bqE^gA-LvU
zphyEB3`(wJP29VgV~eD_OZp$}(mgBhLUd0>{HEUjqiFrtYzx$jzU{*Dr^Yv>zwR(~
zbsIWC*+Fq**NOfZ7<hO80uzMqxUF at hbSj<AV)nobVJ$wI5fkAKcm_Tj!TQ#jWrpg=
zLe|Gd43<r{D396u)`nbZ>>Ce;X2~1Pq_y$h$T-<fsQ(SIGmCnCX}ipkXnhb)+~MA{
zCOw|rsl<xTrAG=AmL45!y#AKuAsj;uU-x(YIdbQ at YXfm*S0d9n#r{V$lXC- at kR!ZA
zUWfpaml83*y9!W7%@MV;&Igz`1XZAHQ8&j~Ly&fC)j;EZ$%o6{MEqub^RXNAZrN*3
z_oIfO&qW_ckjtX=dnXPhjpR`Xs~Gymz^LgD(SWnr=||3(WqH(vsJ^s(-i)zsM|6CQ
zum>QoX5pS=woS!8OHT!{4qsF6{Wx60x}@lyGHp5sB8#LSjvr>J=pAW=Zv=qGoE%_m
zb!Zk~5o(!U#6QBVuc{Zj-)A<7V$&nu4!ANr+Cx~(N0Pvd98DQ=&$*+*2e?@MSg<dh
z at s{)xs{r?X$iorieo3-!)wx5ZlAr<JgEnHY4w_zm0>=$yY<!|T2sWLuGjA9Yt^V*4
zT70!07?C*Qj;hFLgfzghC<n!OMJ(4}UleZZ^ZWK~@b}T@&!<r9Z#<x>ihNo{<CF|H
zQi~O<rFw$WOeX-i!3)l>2&}}&PLOMGcmTl)6)e|&*72cCvnZB$Quv;LJaSTIhdHZ*
zGw0JlFN3Fv1*%$+`TH{H=3C8dS^iXswT2X^5Ys;lWU#y>1bI*JG5H&|W)7$u{C{ln
zUjQr3?L*t<UwTA`9k{9saaY*#lAB9|*efcrSL)H6n*-;j7v9HKiW0w2fN9Q!oG*ID
zi(38jibVE;OXP<Uq1Tg4jn at wV8LhF`iM;Kt^ddl2Fau=(fg5!R@`XuEiGMcl9k at gB
z07BkZ#6{LqhTn^w+$SG%$!vVE=Pk}lWTCXDtQ6`x<cIWVY$gS!0Me?Vk*J!!d_923
z=fKavW(Z7xFmo+fhCAuPFjKp5-(hymTzMAQ6Q7Bt;1E(mU+YD>?zhtkuC0BcW`nV3
zuCSvdK?RD2_7kW`-T9RA53#AVlHm+%kvVZewRP^(sw=x1+xMZ6(IK1&nYc=omb(^0
z6Psu;=L+EU&@afzyVMs$2Cuwq4w}Jpi;%<-)i*W6kWw2I+%dKw79X>d6A}=%*}Jmk
zi;eEz7NODSGY^q@@`s~MAT)0ScSGK(fWK#lraRzP$I^23CBH5FK5n^1Hz0y;`g8$L
z+z9ZKsVD$6DBW6H56{0>`F>jTop&}8prkGX*t!nNy1_r(p0w~kuhzE;(4~i|Tt%|H
zL)E%wHY!-(Llwr!1HRH1Um3X!#N9tmkkcQ6$ljB|g6i;1n{Hai@~Zag%7A!b)+SV=
zWtOZPEY7=0Z59J%S3n%@(q4HKXak6npPptYUW3}#yk!fk`Ocrq9|7p1r8^q688lY4
z{xgeAUI)9w)hQ4+^~M8~oSC2+_nrl3yYGnifDHv|JJx%{`RfK*2S?g=>!}IdH$?9-
zW3#a4cr&)|+9xEEvB)fy=#S<BOd4qAwj*_)w%GTuqvB5!GUCFG*Pz-+50t(&6*ZJ$
zZ(b!Bfn0l<q_8u??Z`7DUNGt9t5KzA!$qLb%EzwORo5H68BNR~$ut4R&K0E*lYzma
znTh&7RrJ_7Oy;v)f*(zz8lxK>66Y8(LC16GMXk=#X+y;5qWOgLkZzRE_z?%vVnD$J
z4g#tXv*qJ^kmPFXSOZS^{EO;C43A1yV+tCyYT#Nkd5+bD61zJ8>b#YCGXtNFq84F^
z0H_50PVz?d>(17~UCblWgdo=(P{}p+cQyQrf~05ck@>nM4+%bBSXx7cZ*G}Un?gx>
z2bf31RCCT499flIdV+NfOKHvNgW+}Gx!iUttR-#J#OqQWRvI_hKZL6;1;B?wIq#k7
zsjJ^i?WrNTW;vJlfSsL3Kp#VQ)SZh%*#0x~DO}GVoevIh_JW=sHc31a+_*oUx_jX>
zu*d+9vZjM>M(c$qSIOcLXcc_tO#X-_^+NM{{(zN!usD{OlUP5t<=oR6maCMC2!O})
z5We9X#ql|=xxxpwp5VN*mn&ga=$N6sbLE3WYx_{k at XbMf>irOe7b{T=kA}o;@QzI7
z#@@Pa+4rQQ_IQe(2p|RqIG+)im*AW$SP37mx#XlrIu%Gl&m>TbpS73>NoOc}4e&A0
zN?}5ZI-P(ej9^G1=VqG3NkqhL$pv^96hn8FD*BN at d%8sVLf0ON3CY-gzcNv5J#rCF
zTg!qU12HM0q%5$k8!ra!{M~KB&_h_>Mw|u3>w7PU(>?}Y&6r{ee|}~h+V=5dd<7D;
zUJyv@@(_ju9S^T+jYdI?Vv*EKF2?SJ<O`l42C39)hs5<*W-uLae>Q2sWdISH(6)<t
zE9i7U9<Ya+|1}gVs6(r#DValz9<F~JG141pSaR7Ho`rG_IXY5VGMgQAI;a|ALys`h
z2v!f@$Cf}SHoC0^egl=HFSu`Qhfvj=ooxP4tBK6BoR!!XOVPaeWMO*JCL+#~$*5t$
zV(bat<Vq%hRRsTnkss-F_1f}ScX*;<{hGRpyUmw)`x)|Q0ivHa6u=FExH26{LKD1h
zv@>?I1vhSnMCs+{7sG=By0=~-{335SYD~1G2ih+H(|q<Bcx%d(gM?w0t9Zdw?gQs-
z&e(CRRXYkqe{792KV5l3QdvR_iCeWpuF`a+feQ;6QyjFF!7GcC72bIqfFCpdNwh<2
zF6pB54dl&uIu)BRj(baxGv+e%`nvy-a(Fu-D1nCI2!0%_#&e%YY$eBhC52V#xZ^N%
zamoV-3rmjA2$-%OX~h<&<Um!RJkOF5UhiCpFH`J<*E#F?s9 at EnD_8UN#7GbL*$KUX
zTG&O?$P)CIZTE|_8eB35=Yhs|gLPouZjy9wXnKdd?~Qg3UzfRhs&k`_WBZ@>`vdB^
zKA-WK-{<G=i|<2Zq4GaE`-;KZNEKKRpL|@X5rbnYFG6V-kwGQwZ%6<z*;oW#^-pQJ
zO3pOmI@%wUzHzc1r+Fj4!<_X^#LP#P;gi201X{)~Y)47LcEM7`hU$kw9kaEpRwO2&
z^)apSOw&LL)r4gA#xoS%6=hg*_B6MyR^%k!Qj(xYERaH_03$?6u)AIbgMsYS%Hg+<
z9OBKMAJ!K*JhwBLm9I?naDHdqGkYPM1U5o`W6w|~hB$C4JO8n{d==bwwVCcOgsSQZ
z^p4o}XfUXuHK@}>_UWje15ECSMtV~Y at 9<3|nzaAL997ru3UK|JFgQ2+9^QAQUgN^?
zQ-B<@$Ynu0W7ywG(N(S}WI{1a&til!7j`C=cz-{Nt?j&9<lHX6G>ULhI?qIvPWQWr
z9RlVKwRHqgH%!wlI&_lxkSPF5NXw&ZU(wgC0f$2aBop at SGIaWNNK$&h?0}g=nn~Uc
zGlYM~vOxV4G?O0E06LM$LGY4Todcpm8+rOW(X8gfEy+);^=G1ySJyUIWIj5Bf8=6X
z?l3H1?CbIPuXBMMw|(L5V-{wji*cM(`KKkW^~+BJOw<>Sgeb#Z^gLPH!-ETt8kt>K
zMx&BrKC#nlIFLX3Jc9$B?jAo_;e2SuQ79UE+*_`Eb6 at pC%o*dwi)H&l$t`JLPzPNd
zYqo$ojoGKQccSN4FMYMAioerqe=+4qIV{TW5w_<S5c7Q^fl}*+U;AwIF@#(9ZNEtt
z<vW7+g%bi5pdq8Mg6oy*1dY#Z)2#G8Xk*)J|6#{c{rU?`viDqP_vmR_*wH_)zWs40
z6g)mYIn@>f;T}s4<97iV-mJ$dfWFjeIFpNSnr=O4ZN|9f(0*oX#TE(+<w(H1TfPXG
z at y`Qx0{8T!qe8a1Iv<5Upr-8C%L=idIoW$YCeX_!Q$J=*blAy#Q*hMls`Y50#hNYc
zwN=ze=k3~n<lJZquYM0f+l?TVaYxc`_I;80d(j$2OEu@(jDRHoIBOo at DL-njZ!D>k
zA6SFi7`_TGWp9NlkW(K#lrsf8cVgr1eM(L73-KOA?d5R#*$*8{?#JOWx>j|JBb at c9
z2f*($)G4Sa6cm&t*)}~$ktD48N6_A+W%RC&Q0J}^EMRb><YSZx*ew^;d0fkE37BIz
zzbzb&;+6?#rd)8WJk<vlH0ql9pzgwzvP^4Yt~c~KE at Jjk^&>V^5S1>ZyhH;3v?3+|
zIicjBf(>GS!x{b#`7H8`WYzn-Q^o16qWUZ0Mta$-DT)3^=X^=1=pX0vAae!Oh}yUp
ziqNT))J{XLZ0(xMg6DIz`U2-!F`rLmR$hDel>VUYN~+}|q!dcCor~)O>HcMiv3lOz
zsu%fGF{;obx}yr{m!e>+wYR63PpS3S-+{HiZuT<N?ekzVtIb3 at sA`qHM;;R;=Uumx
zJq+Eio^Hn)9oq*gnV8#KE`8XIIs+|bIS~<OzUcgocVBTJtUz2If=IF(a>c#)SmW3C
zOcYA-IOXJVwCtwyC!ut7_v76|hllvmY+LT-ju=@Q<z-~_5$GV|7<Z_YuJ^R)g$%NQ
zb?}<$SyN2-=X%AWNl#LKApD9eyZeEu$MKNQ{Xa<^rM_EsYV1=TV5^USt*D?7z+UCA
z{3~YtR6u+5kPqS7i|QQb at hODZ*-ri)Sj2FFK%pj<km5J)V7fAv&2I||<+1bCQ6R=A
zcIbH(V;!<t)RE;1Fsp7-f-Dw>J@%mNQ<7L`hr(HpJ7UkUX6iW$^MZICQd`^C0tQsd
zV-Vfgi3=2A8bp3l>*=dL))zGm2q85AX0J}i=ziRo3jurKp?|6dNzR;O$q>&5h+Sus
z?B+U8PjTaT2t*}<H~=UdmDQRJMg!-d+E2tw9zxPS^R$wia^>!pmrZ`YHkq^3v4~fb
zZD=8tUX<ZCzd+Gg6vb`)H(T4Qx%5}5|9>{Rzsz(?#5?khzwvWv at V}_-w{fHY4QiGu
zS8X~sP?^h&@Y+qI|I(4tU_vW{3|9I7HRk=#bDF74KY4urM(FX&I+0r0=Bf3bvcH}A
z*QLOJKeJpf<=oTnZZi{o+b<jRl()f!6P?TH+PBcmZLD^mIbE21Gq{tKg4rx%87sX<
zHvM(uwC=!k-WH~enaOrdXQTF508ux5_I^|gD>($KH|w8Ir5|AX9v~9v5mJDZ8c?*2
z2`!BDjrBDHLG!FtV<}J6(pAzWWj)`FmN9i-+A)=BurkQMxGhiddN3LJ0u7y_Bd>C1
zGTId#((%bClqwi<QQ6vHmFmk1cz>U?P)ETmC at QVw0fw5jFwJ_K7bn3|)vohs|M21+
zXiD#wSgOQ^^XI`Go<2)2>Z}a at ***@1&{LGW7 at vp1{Jb$!y^qjax1>`lXywpp
zbU+JBb-_w61KT6LwT|PHn{^63d1WCVQxKNI<ijZ~B;-a06SVS#{;KjR*5+D+_MB#+
zsa=ub;A8Om%l};H at d~zHk8!M`r!2O0MInelH5hi1;^hJ60g}Qip^#@=QZZNNO_V_#
z;zgjSmJI0e=C)8Dn=z^8gYz};`YjS^GpFA3FD9Sl9 at ccVlD(DV-V^ikWU(dDc*+me
z3ON%2I{0vi&1f)z9^pdDm|X%}J!KDz5kp(dIqr0Ly{mC37B&WTshDSqsINkdu)-;G
zIK;ZzJ3ixOP~}+=BU)wm3*K7b)HR#LJSIY7Z5Ewy<0H9n=?mWXl<Ni5H4j!AL{Vcd
zkrHx&C<8N92x|sIFk7IT0h-Rh$1M;!&h<;Jxw4zsiR$VXBA2Mwp6^E3-`H21Cy5lH
zTo17YELYLQBvQPfNb>{p*(L%n_Veg5L6M^MhSJH-%0t@^+bLPpH{KWE0Ey$)!6Q=W
zs%?)oRIjr8{3>#)C*TGvi&uvn!!r!B{!0hx)!_d|XImZn-<a;@3b+O8Yb#;+y||x1
zLHdWis79-)Ec@%9kQir~eho<rpWSvL?(>tmak|U26|atWTIkudK(Q-F^cHnq)Ar3>
zycf^suX$2E>9g at _p=UL`<<n~!DZ-$2N%M=dd#u#KuyRdlY{{B7W6w}hIA%6ScCcRa
zEW>TALO2`&Cd1!a?{QOjUr$Ub?#FMYqpxl7_P~{2DJP!zpl(=dK7});tu9XsGQ3kx
zAMd~=X8z`(bL9Q0eV);w?A~#S5Z4qoV^YcWtwLSXWK1y at bC@?K at 8j~O&4CfEEKJY-
zm6P|^_KLrZ6C*`wD`@Ro*U~sTopxzT;S$>dP+YM?iBmtLTH!$z)Th<djVOoIN!0Ei
zHdTNJc!klp<R>%QQDxk0iDq>bv{NJ~=ViP{SAHv}5z*2#pX<;8cwL<4fU%~kcfmga
z%Z|wP at XF9oPVlihUQZNYLO@+yEJaOkt-Lb5122c7;@0Y^5;VL{vxo at A(@-$s at FuT<
z;uy#NuK$cc?6 at S_#nCoVE+MZ*Picj>sG7m{%VBM7-#g`W9$L~akyxOCH5%@H6<gaz
z>KqiIZsaV$kVa_wM>^z%+XW~xpJx?yZol?2D=MEds4z+kNU)NF<+?+cc_VCF-2y`7
zcvE{Ct}GP;pqA0KDkyEFCHFj^?o(*JqMZ|>K}c6qyI25Pdm>y^I?yH&q;Hil(hCND
zkU-o3J1{ULjnqy<-}#8=x62#o52&IKKI^PZgRG-&7rd`7nNP$DLPX^z$`7lLPc97f
zS;rUlqRrKgIMj<>K at uu18fch)O93Bz2V*Wys35Z~T#R5M%A5QiA3l04_!|4-dJ+hH
z|B5rg*`p!jRpK>8zh)~c5 at n}3Mxz#^o;PQyq^Dg6LQRVSzblT0Oc*L-pSd!xh|N%y
zCaODA;?|h!u(+D$+JdFNk1RoB&a;749 at d1}sl<pF9ftn2$G%C%PK=u52KlIG|C%2p
z7Hq3K7G$c+;pGhi|Fy?s+41l*^W~tX*Y^q>mlZXxFO1G`2Oi at ***@2zJ>KCMUA8T
zZX-J9mrSb427b;aO%z0#k}5=}GF88vm<xHqq2shCb0p7_=RUTze#&`VNO{pQ-{N;E
zu&1lycrj|iyVPd%Aar|r9TcrXko@)fNc?7jTMwM$QZbuUXfCCC7-q2~{Z8ctyXPii
z&UShP#5j+Dkth778?b(QBh3g#{d(@X8OE=B^&{rss}xW)NE}K8WzT1?u?4R@{-FI?
zb~zjsV18^T%$c}$S!w$_X at C5ot>f3x{j9ZD^;<wAIg1BTXMPBH8&$^U!S}&NPsd-s
zM0 at Az*(14fy&+4%02Y;)%Q^?}zKN)=WD`{><$}OAkLf*FGG)L>-WemUWxZ}XU1N_w
z;p_+&f`pPn`G&&OK+(r&v0uqkY|o at +%z>MaSbhc*G{^1-L#jZjJFl6Nj#g;K?kC6S
z_Uf+J1NP6gckB+>$37$k>~JffRCp+h%g;s9E(AN!eaPsc$&uAG-a&?LGJ5mzaNm#z
z4|*uQ9o6Ez69eaF44b<992kQeYOak|LubpM0Gdvj4o+)2d|r}_VWqHLO}-*ZiX12o
z^Wj`z-Qlv;O|xrrt+~Q`6N6d{_^9 at XFJOe7n>`Rwxqe=gjHXvO`wLH4MKx~3!~p_R
zU?l3uX4 at -QaZ{@F=7cV at hoib!*<>VJb-O|$kL(RLzL4wIaHHu91#|S)V!Ci6wfk_n
zJOnt%G9u8o1Ese`wH!W;xM2cD4FTV2JV<e>)_-Cc2$MwG`j2F@^ukEZ*Gbwj&-e~Y
z(etlBH$Y_WxC%8nt|&OtVC;lRHs{ne9Z?O6IwWL?F~ig#A%Z)_H+k?)qQ at VD7(ms&
z3IZ!G^rC!MTI9<Ru7H%V%Z#I2PXG<2Cb`y2<`T<{3uwjsciF_|j-y%0&&b_Y1;#IA
z!^mHaGy}+_iS#tD4#%w!dgw4_4FqnQYI_Q7;QsP5;MrxL-Y8Uyg$p-0S)?DCFj3d)
z+aG0*$b6q8&})_9EN2JbzSW_X<XS9~oBTy)nCD=DRDv*o^jxfjH9sfIt?HW&ERbOX
z&UTDu;e`lhByy<kY!!?-c#)UhLF;@ZK{=romX;1IZ~u*0mdh;nDLGilVpV97m4RV?
zzVOeI0NqF$?NArZ35 at bu)H5DpNrDc{$&anq#M7P!>Fuh8QjM1$cH at D$3>&cFOMs8j
zsv`Px85wmM)WKhqKW<n^!9iEQV2E2d>!{D6M}pO<?R`_kz#cE(5*nq08;URQnGH0q
zv)&OZJEL9wlT8J}3Kw1R>BtP>3!~}T at su*`E{v(2uR0`G$T^eO#Gul50!iKNOaE;Y
z_?&<H|KCS&d)6~EU`@u~BJm_e==)dlCP%*cCcM>d>;6_O+|-C!*CNdx+oR>t{fJnR
z#%OKY?9F8~M2%JOzJW?`-GbI-x^A6nMGGSbv^cbwYD5<^9B%ok3mIu!MNCeIF)DSc
zT7rap%5+QY42^D7Z at 1P{DFs-RgtJ0-k|3^=6&5rhjG4ZH$kgfboE_~I_5kRFqNU*D
zOC3P#m3Zdh(u76r7I51_vJZDR6C(+1WFCNQZd|28nbXb25^w1X*^D%%03VK82Xm!z
zxUyW|?pNb8!~G7lK~WkH)JtcTR{UX2uDL`ztW4)i)RC2dNM4NmQos#|3M+%P*QX<^
zuGnWwz%3RW6!MbA8)H;MzHF9L at 3V&ojbs(`36`@z;t1+!U(~<$3wY)GP-~7v500Z;
zzB|s~4FBB(>T at E0MA6Ti%S<w at 53yQk+TUDqQ9p0i(`0opGl}y?=w#lcPh$}rl(@P&
zWE=v4%N|O{wNl_k6%jQ&nW7BEQymLIrUDZ#wr9z`LZ(`$P0p+}i`+AOG;{erbjQa1
z!eA9EUWaRfDyLCl<pO}7wt{WjhzXmcVW9^W3gAcVxq>=xJZ7Hn6RzeZNI_4xF&~Sr
z;N-`H<nH&)YAv_XCP15OalNJnon}4;Km3w#(%x7dxi?tk@=OHHA5HLmlW6VHW5)Cd
zyE2=KrnGFBf$5Tc6UO>g3N*0mqKh+_`zp#;ee+rCz1a&;_mNk#O{V0%B-r~{!;)<w
zg~=kAFQ|961 at eB%3`wiBia&%8u7>#qNz$Uf>WN$hwT at s!PE1qx5o<!=X|4(CXL9kd
z1=%^&a%4FxI+d6&3}ZUp`_!Et!rsDlvM1z6vi(jI>>1B_3MZVas&LfZAs!GLN<?Nk
z|14}q)|7O+(pvFAh$pyd*WhA#!npsrFwjYOyR1mnzm^|)QFUDS$es|)PxwmS2m)CU
z0pcdk&w92E`Gc;XS7_VQiZlZ|-;(sSm`8nuTMgCfv6owhM6>y^WF^<!^yNwN)8@@#
z#X{|gql9sSr!S?v2g!n<-t)#c^d{88BMqYMND{<Kg{V~h;VN({6AnR8GZRI~L1}F=
zrq+`}KB0}Gk;f=(!QG85YoTn1KOi%IZ2r7rqL*|)aB_fYFku3_;Rn-59pCN+p&=}r
z)Y%YU&4($yk}fX)&1z;n%elX4`8dmXYQ*t_r*3+YN^%!q0p#|>$VwBD`~7*ar~z+|
zPk#uZMKl_rti}bgQ)U+q0<B43OCBP2F$*~E%uyra8inTf2WZNBm1p?ho~e^d?ApJh
zq+kAhxIK at 51pJrI=5+_BG3-iNJ#mn`B!dB4Hv=}FEAEpm+a-Y49pUpEa*!mrtpn7q
zZDmR~D*^ZAYwO?LC3jVKZjijgY5dRmMb0eAj_^GrrUsje1*=TNzTc9%1RqWdZ#?fb
z`E4ht&s`}!t-|#D_!>FyYM8!sJJ51IZy!kL=)&8fxYK{9P`BT~_qXxfW2RwvdIOgJ
zskoO`;$OcfDE;~++-O|>siU!uOt`va%BvX~9i931bxhj8VN=A?pJ8hQg6{&7xaT{S
zH_r$@aZ>1ipX)D>;>l{LmG%-7bT|$RwKW?(XJw44VXr^_$zh;`!t48V`MJ>}0doIo
zn1S*@Z4UgL4;HRI`mAXP`mbELEpVwsC3T?1><ZI;syrJf^Q=6snrs<I0nSq1_N4*N
zHpeKChV8)IwWxH(vkXN!twsPI^iN)l(D!d4Kgv~Qz8{}NFaLBR<1+JdDDsy+&cGrt
zwNUEf*V)g4=jU at Ang*obGN|A7pz4u>=E{CM)zFJWXsz9!IiMgBdUtt#JN=VoMZc~2
zY-wO7y*(GQLsJ0cc-fnklYPa;1+btmJbOfC;vd3~Ell}oda-!`>u$*va!m#NR9M!;
zxS!p6)K{73PDr9~2SgKr_NA%=VVmD(1Ead03?e>O1qh@>q1z!GXDDd3?4j{BBgNM+
z;aqd-uqjQ*OEY4ApZhYk?l3T`!^7#(Bl%lDIkgky<4Ameq5}5J<MPD*5YClCz!ZEK
z<BeJ at aa=DwR}4E8r>;iMy{_9YDaBuBCgdE?csq=&s|K(1zc$}!JXCB#t_5^3tFexL
z`y`9oN58d+lXWLwTH3oD3>*$M4do|RUf6Tr{wngHEuH5!FR-fIoL(0Ha_!C8IOZ|B
z_hL12m|A??DnE;S1x&F at ru3x?+BWrs)GdNz1--uu3dS1hjg1ls$DaPYWEQNtE2~xn
zk&E{$(~jJOL%WfU5D|$vYm)i3uZog3*R`52dDCPKLdLLcX0Rq+gYkAfSf<&W^o3EF
zYt$1aaf`&ni<v)q6X*<LIr*;X#Z`DD4UB4R2efVie#t{F+ at Ci=5kvEAke{Gptr?MK
z`54BsiRguJxVtP!7LqSTC_}-y$<I8;B(qr~fe``eUEWS!om;ttr}O>48;u%Dn-Zb(
zl|4nXWDh90bFJP`r0Gxe6Gt!`6QxmLqXr at fEFHIrnbk<|TqWmFm;%S_bmh67a6i4n
zle-MISh&+vXhxihG3{f=(2!zE$$V%vEXM0QQVxh+)g$mPw%V2sE!Mk8dX}~izn(|6
zJf?pG)gaX&!#;gi$uwvxr_68dB}wqz(B_<XC|6RndWJuuF`>~c7hO|?7{6HjA%Z7-
zU;IgQfPfG-!WNzE44%s60m?GfSA#<*hbcbU!&(>Qvtd}?QXSR~+?2LY#q81*Dm#|F
zh?Gz&Yd2{kvyoM%d#rw_Ii-241`MV<xx*z=Tx!^O+4r5|cBs}%(g7ln-%TD~w_!Rp
zphwX6R16YSziLdc`5)-K@;}SS{_?bac3Ee5Op^CQYS(-{sH`)#(OI-YfHF5<!*C=8
zhYyL%?stQonIc@)ug~*NdP(Eb^19(5m5CA0p;9qEpYd%lmNqH5kz=Egyc;JY_EEzf
zK$^W at p;O}DG`XzBjosIM`dSyS`9#nEZNUVx{()W%M(mP%i)KJ$@r}EFNGJQ*z;9$8
zN!*n+73w at Kfuu7kfU4EG?P<b3-dgC-xQkOP;=^LMY}ySUoKNX&d3>gktmo8NLSeNx
zfCxVjz-o|O-Ota|nhQbwnJW02GNWZzYtByVGJVZ8R>P*zBdl+S^`gk@`=2;$MCH%4
z_eC at Q7%=gQdczdxdBfAcWIS|EKcDBtT}-w;R*?*1G!~mHn{+dmGZe!SZ&}Flb2WXd
zQxRXrMv^bR9Rx5NM)hVAi6yZaJ!#W73%T?<v`lfzNHR|ODmm|lqFP(2+HT47(sSOH
ztAqWB@*ep=U2j1cPS66b7cXXkR at dX<%Mp5GDw3RkBbfzzB1SKAG2v-`sr~qUu$!p*
zHL4e^8PS at VThEkPMM!&5hy7I#@?2+J*H50<q~1`iFeg5%9vs_n42T`O2#P)sSC8yN
za)Q<j>{;c^YFFmH`qd6Q4;Mpq*B at yd=!BsJfhna-7^CWyksUFO@{c1PJ*xK-%AB{0
zy`q1BI*a`!?5!PsRcR|eXDI`w8N|I|mOV9{KUEpI|FrP0g>5^(PYD^geOfml^e6F@
zv*l0SoSyUubRiYO5OUcVjOt+b4dv}Aq8hyL#u}x-aPNX5VtoB at wTBlNplA7`ijAVm
zE=>E=oLI||jPfWuCq>IKz=g^k_&1L<NkX&K7VOu40P&ar%qa`Z1S`^(;#36P7UFvt
z at wUWsZB+***@xE8JY9c0YDwzh<fre448?6URaSjF<MJN8+@>aKO`5X`bWt6q$aVJk&h
zknSB0_4`rsdppg~6lqbPB+4|k)bskry-Kc4=N56i at L{3KOD~rAzbfcFiY|O};>BDI
zjGY~1<>v8<aUm*Bd)1|zt&Yti^fpE5jv{)(@!AoF(cGJmfe>is?+^g3+F}}Z at i2ND
z^ctkpDJgtkx{RT78F`XGMihX~!{J7)jJ~<F=y!w3=*O(DbKp|X^dBmet4kMLfNiqN
zB6vacmZZ=MPJ*tHXNW5ixjlCfN(-LXKHVU8F!NR$is8#D_~2($ri)t-?U`fkd(osY
z)OoIH)bBboHlRK*rAj0=*;%|k at C1#)F<VCm<9*all?g~2E72+1K|6Grx}Ws$inMv|
zP>-b6bZ`N5hS_kLmxuc93~u>++tLr7KXWQnwv^NYE%l9&f_4!=K+xVE7_w<|=#RfK
z4&yi%ryYsM1_I3WR*juV|MJmThfzD#qOm&EQG|$-6#(&N#r#{SBT at qAZ5#dDK_ek#
z9)2Zoq@}rnXXvku1f at t_RbMs?xS%@}t__`UhsrO<U6%Elb>!9u01B=%ZIOZj=y4W^
zmO$Fp$_qTo1hL*f9WQ$$XhrbedQRW0=hSp8&zd_GuN#nx$%yYc{d%E)eNf-)|CC_t
zCfT#{gwlSOKwdq}>-nH-Uqf&w<Yv%$RT>=|tPtx+LISRH#Ut$le4)QAV;LsgLkeRp
zR$8HP>!EG;tThRZ!fEs{TT9n3+20Vx{ask7)C&up>%_kSyAIb(n~j5icZsLPZE)f?
zwJTd at _!lYvWeJua|C=uGKUVY9FPD5=Yd5Jso&Ef0nuERv)Nk##wE70_rJjE+T|1It
zne34FxaBU==i3YqmAU at s+!_2rJ$b4Y8fUQ(**YsICMCb+rGlHHqk7-rdT+2=(ejLZ
z87f?nW>bnw^0DIH6~QGy&_<fi4O6<-2Bm2eJ94~(Rq2OyF!v32B0`B!r=$3Se{#2D
zHs>vTn%hKVq{VVNR_ks->!?8qX>X7|sBl(w`@Y52tCgbrOtCWHNlE~GF*HpFZ=mat
zzRag(7dmCgLcZ3qF$G5cA8|M9glaV%pYHm>{DF4oc=SUQXJq-Mj;_9#U2ffEr&iNM
zzOs{AY`YaGyk1wvno at AtJbr(BNrKGrovu&a$roj)GhX_gVIhT56ilHg40CP?*9Hkx
zmFel|gh5vzfSV+LDly4)c-b-)v+#|^)VPkmI_-+-gqjZJp?IPMY?0&#dlnWbZ{3H=
z$4N56ClMfi#9*>D>N*g<U|P69422gPbJYhs`v~L{^BOLt5DQ{m)3gg6Q(i+de58nv
zaxJBcDuZetz%4zEWn}#9w|=tT)=u&?Jjay_vZu4+zZQ|8AI;UF`UM~jOdrzM%3Qa^
zg8oLzg2GN8m;uc*mHdjKnXr_N{+(UDi05u(s}4ys$ePI(U_~20w~-lMT}@Xtt>Js1
zR$gn(&YD#kZq0P&OO5*;5g65^HT*w(y?a!WdAt8#W9c+m?%6#Zu*7-BnVNY#<tar)
zYno(cI#^HR0Yt1kpi+52Qb4qFM&~J&ahfy at QDa6c1WF`D1#O%{Q$SNdO+iCJK}AI%
z!Nd1%fA at FqJ^Q!TZ!P{~Ef(C|_viDu-q-v6y2jLU?Di^B5$gOTAc;1u;6je=U<;ul
z^H6~DoT&@T@>!u~u5#bGXlMP|OdDjLi;6tjvcVHg&1+i)M^p6EdBiqpW5jd|Umcmk
zI;SKux|!;d=UiPPa|c1e)ioKVygXP!rP|Q42P0zYBeCK5!RxKpOp&?o$Spo;ZgJpI
zjv>d6bf2dNTj;rhInLPe{v11 at ***@6^@B(MhJ6U)8twc4`S(?H$O8jj&ABA3 at S%p
zxv)t*)%3PEI=912Q}~m8WQ+-a25%RnP63xaNGT=GYCSPvt^vG&G#2ODN_|YdEycsq
zrmRVByKcYIDO1c;zv+D at uo_IAuNgDAW`+{SCU{8KtVy^+ssX*boGI4n7v>j0GQ+rB
zT?0*a9ECD7q28T*l%B+6v;v};jn-bk6R#m;^6*aT!;5x!Bc3Np7sW4O71+#;v{3M<
zDL%_?avoY8TeNN`oT?r(FrJBG`PS&6xBBNilRsI at -36Ij>{_hor`lCozHlRR#c`Iv
z<`_kb-AjQX*mKB6K4vmIjOj!)^%1NLd_jjRN_YlE*ozj2EOOcEroNl|A;F1w^ihRe
zZi}h7@|>gDY(!p-6JM_S&DfOX0J?4nT;HR;H9*UUy^d%M>;Rgg1Ui#*b)td6vxbjV
z;dxwiThK?M5sghKtg>mJF#aCT0RH{!9W;ORU24 at uO|AZtxP;^*u-E$L>$cum{_fkQ
z#h at qJr>XjL?jhspwA4yt;2$N3raEn>eKPV4DX!siHOe{Q6%||(U;RknpNbJVm+vGP
ziXp*kt{LkeH=v%92fP}^T_7>iCRx0^Z{qSsznNzFdaP*qX~kO2dRMcHDJ|#a(QCMC
zvi2tV$#5~D_Xe{jsnkbWDa*qgmgNA!lhVV>{wZ at WQki$f%g{tSRMkxGZ#wE4Vz__(
z>W;`<>tQg1M^x`$93w=rbvBzwO9J~R^W*hBbe-oZ_f8TrT;|lG-Mj-UCB#9dHJFqL
zGEgTxEOr at pxf9>uFO4o5D5nbe2@}qg3CaLKcc_K`91lzO3;vFt5A9{w|FOdJxkm>?
z&Jx0pnD5oxg!lP3!oy;&iemf+f_NMjk_ML$;Oa-EH!iyab~WY4`aKmhl4|$#midyY
z#)A8pd>#OHC{CSpx#})CEN*DK*4#psX>M19yDs-S_8(yIPrd6{aYaTyySB#Rhtc5&
z2cnvD`i#amcN}NPy(Rpe?+{jgvezL=5+mWULgVut%O*Q6OXyFGM6YZ at Iro4q_W~+!
zh!U;iz!~!;@m5A6+$MS7bVYnLi8(jZcFo6?fS<KNh78|PyDa&qm&%+{73Fhwo7!qb
zur!h<0R-LNXX|bFn;Pu{-}6wtuRATYEX9y0 at qkuMTn<++JE1?^@z6#gB)`^7wDm(v
zZhxE at GI7dT7dX4wlWedpOOd1pInl9%O{}|{hw{=ul6&E<*_ExA!^K})Kb+4-IU{<s
zy)qZ?5E9^!;<(zapDVi9UUsF1w6Cn6LjZnw;U?5c$LEqn_g)`u at -gQ(k7Gkj`{(vH
zyLda4_g&Y2AM4pJ*%il6?ut(hPl|7}VSys*DxBzwliCA?dcf^upCNO)j|sXTJNC+p
zf@`j at 6=AMOcVX0M?8}+HOIv0isRG}%s9b=c?>Z1!wCT6<Q}p*>L(7C2Ht6C>kce~i
z2tCc;c-CF}JdweKs6)1L+{h3s=yCn6o`%xr(B}CgXMjc6ebMT=_5bV}ANi{l!0IR6
zIvv<j{mZWk{R4Z)5I((O*f^@xN*%uv8Q at uksbn=DU=gY2k30)|wnD1_70n})_Z4Qv
zwgC=6S2~x?sVtZMe!)HLV*d`VtuXBhova!}1EI<HdUUHT4e}$Ka&GK7ggF4NKOXC?
zmDY19RzYN2wCOD&RcAYij1I-hhbhTC`{)2D{a^hOwm9~sJg{^4G84ht00*l&;yuYE
zLzXag$JyMkwfH{Jv>UzR0SS@%QgUG~Pzn*CN at GKC^**<KEJO}3)!pGn0;udcLjSla
z{V^vnu}@-CvHzI<-f=Y9t6p!9m3lVk`$WgiOFzn<A9y^0B-dAICkV-IJr4`~t*M<W
zP8`a`p`PRrT;Ed2Q7D;tC?iA<SpAE+w7WP|;ZZMQmj-S#%jFDsi2GVD&m~802MXPP
z%i5dW#j>tibB+<TJ|aeBqctleij>#7#Fxens_616Cv|Z}W{fVPRS{!YIhPGKAX}&{
zbuk4If#L5ZD=m=PSA626D(-zlckVJ6twlCYynSV{44HdIzCk|9fEScWQeUq43q~Z3
zM^Tn!$2t!f?_6IV at ***@ijXXAN-u9RU4H(}>9`OqgOkk5uCICI`;kmH^L!<|l7Osx
zLY*RT;L+QeVU<vWse?3#H4h{0BK9IMF-C|wnewtaLMo8Z?fkrM8oS%*U4#~1O%bJ2
zqW2$w5gh++2G0m_NR~Yj#49vAK{umgclud{a`wPk;g0I3&zefNwU=#n;!#8kIYj+V
zBl1~TPvYD+V^sMW#ck~_d+k-I=A!7R?CFU(Z-Jp)J>JsWqatR*#5N<u#xrRgC!QZR
zBPI1&&`)5Z`2aMR<>oDUdTqt2IcRY#*Sz^?(R--Nf4=y3e{s01ZhGHNZ~9*+)5WoN
zi&e*l3*e6Z)Fx7Ct1Zv`m2QDN5e)0A7!i%K#1truepL*1Wx>MV48V-N4Njcz1`j+U
zehw2&FFmetSEd&d7!~!QbnDdGyZcXAmH{6={ss3Y-Q3vxmhgv7uCmFv_HPWHBMBu~
zUwbCYdQomd5=-|#$}I0E!TNJx7FhH(RLGiBwK#0;W_{Vf at qkueS&Ss5G1OVR%+u~+
zZorMkPS87-K$(wL)RRu^8wn3J?h}qdOpbm_sK859-5X;~ljbgsM`7Bt*g>vmcPYyW
zf)cq~S<+*ZF>!^5;>poJ$;GpFA;#45_FX^?ADr5!6GrevRZH(y<1`*_IsP$IKB-2E
z0nrZJZ7<Hf<?08h!MZj%fwAYszO0lF+_01zj+=nOwQ@}~OEPe)gb at Kc6beVG%624E
zci=oekdo7%ttS)IcojZ|<X$}AR5#xRKBv@#a7x!dT3(H$=j>)s#X~GXfbqaqG*JQy
zo<RlbT}A?=Gz;l9)PCZY9)%YY=M9+`mJw0hs*HAHs)4jpY+8ARv7h5)io2>HXh7 at E
zwfaO`W4^oh-!UC#a7c31SndyO8MiEA9=B!GE;FWqZAu0JIp_`xKUqB9l_U03gsnA-
zr{S5i8*f6QJVv&o&yOeNW4w at V^eH*8m-)F{`2cL8k)Lb`IU)37DCNdPea}N(AM&5R
zP!oYPVM at 2ksM1DMqes(JlC=w;$ztF6_Y>pnMDvjI&h2%fx5IOra%&fX)aI(<OvdfF
z%-{{cW^>8^PXGA^DlZ5==9M((n~th;ytr_nC)U;uQ;?8V=~2=8L8gdxMpq$1=@aLu
z(A0x3SLzL2ON=05^7j}+JhD<*f(P;o?m<UyJi36t^L3u>qc>S+&L^b!Z};rVj9l;d
zV)VEXKGPr{y}bz at -CA;tnuNDCeOxNoVK3X-H?H;9U)rLfGeL<JVLQ%_X{hAonvuaW
z<S1Q*{r!1*knqx6Mu!$(%pTGwI--1s0#l-(aKJ6Q|AyY%P1a4Y3T&^dKOT5r=zY|@
z6#1kWl0+ArBmkQD=Aq2gXJL0%0IMws at y1It@}xy at undZ#6Z1Je`PK=p4d-L}Be1CR
zrP|j}(7W%;q|2T!o6sGIhF;BjN&D;F^O>>Sy)WMk_KyasJQ|qmUoZlR-k~gr=PA{g
zl&&5qnzF|aLRhgG&GjEduQoHGWcA;XF)yaR-#<63!R=2|+$SfUybVd!?!PbhO~J7^
zFB#FL-)dUOheBYbq29<lsEASJw*v&`i6g3oj#(%6;Qi6>0BfQbXOoYIJW^z at zb~p!
zzCI9%j`8VxY_;G=$43XKdecu2qVa7z%H=eo!qeM}RhIKF1x4>4VuQZhD+70Nq<sws
z0#U7$<XePaqQ*jnglU^iU+sV5yYh7{+xPL at 4K0^EaEuiWO$1RK{>~_|>>v;q;QPvU
zAdd{)2_taISz0hfZMhqN#K(&QSoHmJf7_WFuGe at _Vv&0QT7d&)Y*KA$eQnF!gE*Nv
z+g<##p(i8Xi+8yi0vs^{J~r*|MbPtkwv4nyev`cO8%9EdEc0b8O8SwdmwFk9z<6(O
zI92Nm!?q>x!jwRKBnx^=`}-%@t;{ASyNw`{acE^}K^Qbp8RV+-`jLl!ap>Ms0l+{6
zlLN$`rC%}&XkpsMkBbMBikNp_kWESuqu)>~t&fU>?h`dr%)N<j<Mk at oav=?0=Wxuj
zEQKQQMn7c+%((|R?rR(ST{3E?;uDLQFt3l$-srX|o9pfPs4euH<)=3GOrLJ~V7cwF
z$xD>=IZr#5wl38##G9VaVf*DVX3p}YWy4j0-Z{z^lKj#Y?pgKxDdj}-Tm0IjEaWyh
zhZ3SYSsJ at mWO{dZ^`2~O*SETfy1;^7$lG2&6I0!>TQ;cmXb`+G8T)u2P9Gp*2C}sy
zXONlt?7fQ69%ti)OYJYIX~Ay9-hbbz&_^ifd!MXqu3q?4m~I9$r_ZgP3R>iz7puQ|
zr2cv=4?wao)z98Eq0pA3F?NXsZfZNLfh^+QJGWW^F`?auX3v7{d-NRT)|%Di^(@^s
zTe#RFaSGhpl5p3B=5KDvmO5P!O9B`_(jDRYhZXu^Ex>BP1cN2}FNT&LbI^73vP6)&
zFBuh7W=`pw=_PP=`Q>?Oy|d`P^y$W`J?!9d%XDCftN>>qYPVs at S;FZcN)eYHCS-8K
zW#zU0fszGq4~`&we$dHY<$q~jS||mcAPgnb$>PeG!sf5J0L=h3r_*plbTn$pIwtr=
zPg;s3%xd9m4_x{;V at ZVZ9iv{~SnRdWiy}6(T*IHxN;<oq)M0<0f*^B4Ou!Ez{f&V&
zFsK?sgR5h+Z896&N3lDNgO&D!{lyLC1>F5O<`056fN1w}bcGnHQJE0)KSD6J>OpLx
zo3{HQE72Omh^XZ4Uh*x_!;3TsWp;EcrNOrVLIzQ+fID7YvTetcm!J^#W42h42BG2F
zz?(_?vH*vMTVtP|^_3|NletHV`~G`zdLcc at kO|H(G_<|-eE6eGLjy{YoGr`8#QppV
zB~FTNG=1T;HVSWGduZn10U=&+(cHEofs25e;E60I-f$uQigK3&D21Fz`g->QJPIA+
z*3%exf;jgmo`8e0n(EAvv^}Z$B#EfLywvxrK{T`)o6m+vUw<FAiud+KG}%B8Ngq4U
zVwhoNH*!YUlG|PtS_Y9|t$RV!DjQFU8#bG*3|T->YJRG55A)fJ#F!J>Cqb{bHzwoU
zjf7?M9|DTcw5D_5ROtEULuwCkwve;0`?@rU7sNXy#u_5&b=*_h3A5vja%iCL?i3qR
zOgQyS0Cun^HUeHCljEij+<I at p)h<@7usokesP@$PPdgu~r4%*rf$sF~3`s_B`cBbu
zdihI3Ap!a3EB5GZ19-?+>+4A_Q7?c*7lc4*(R$!4t0}*>xp05^DJ#vFPUT0j at QwZ)
zTSA(vYSyDGO+K>;j6U0$c(7;dESA5uVblsM^$YM+pHtVTh3j{|yVbM!@QFCFIBody
z_d_=2Hc&mJ4r7D%D@(d(l0N*g6kn)Evg&Qxz+J}VN~)w$is;1H$ml^I$N(qxfV~m!
zxOpX9nD}yLvn;tPyz*@W5EFcAUGL01W4Ijj)udNLHbzL;9 at pr098>eCE(kLlpSVNo
z)|r~)&V-%JV`_PEoW~ez%;fc+59+W&Ahdo~_V~(5VGp;Zr10jcLMDoIu;*DHfpIS8
zVhpxCpZkDHM~C`!0%v8%$iJ$K*(TOsI?VUI);2Ae05|jcwLI#^KSD%!37j=OpsA7f
zuRWN*#r{Wx3CGJK(}++@;YU^6-=8+2p?@Tjp*&avO!QIla*E`@Vu+|CHRrc$DY;MT
zcE0D9yrAHO7cv?H3wp at LA>z(Nm^S1m7d4xE9J4!%7i3FFKAi&nN_t$dr(|X-#C(`R
zrSS*=63E#J2QywZgt6|187UXtM`M3e>?ZmbFBesyE9-uopOK<PoVrr>aNs}#>8pY|
zCD=IFGD~d%GlQjtnhG3NS{>lHY>rFZsDCCo&np2ltr6jhKP0m=0=Nhbv=Oc5OfCo_
zkh-6-*@WKn--hf(=sV*3L*eN9MDPDQI|GMkzRmwSK5J~Q|M%PPHvd<7sGw}bzr>$d
zbm+ili?KY^t{0(`xf_|e3y0eO4E|*N#}4;Tex3o1-tnnyJz#Mnlsa7eZBIEAJ(5RP
zyzyG%1rd$i%NIg-cpEP<F}=GD1ntKJVk^`*n-`ee9M1a~>1ZI>XN<2pEfXFEH<+eZ
zK2 at ***@Z;4LwNM`LRQY_44$dpf$}^%r83IdH8{{1eeJV5GkwOvFDjBGh0EJN
zm1%pl{d^FdG)*KlE!8&>(#e;%)LWsjrQLy2p8<_c1ECj2*un_nfn62&kr=?}91nP)
zadu at t)}m4vjRdq7+@)ije?TQtW at L0yf-d3)wo$}3)w?+&PNLm=xDZzK7`VaQ&mZPy
z2 at x13`~|)bfpaaEZbfQUM1rY-#>+~fV)NlSn^F_rE7<?}Qsn)mBFWig1We($e6=mQ
z<lK%HdRoQ6)9}hPeh(I4X89qD-Y(UD>FQ`;k_n&aLz1IXfwrG}rqnLP^A>%AV{Xe=
zrGM9hX8kBlV!Y3xSzis6{*4)rfV^ijNb}h6+84uwaq|{e_p?>R;y(=Em1-F^@r5eS
zW@=iH4AOpgyEhH<yV?c_bme(L>Yj at 12OeYjOo%R{w(MM$><kuj!Vpg7xhT`!lzsm3
zpDA7~Ah0``Q}&Xm#w8kWl;1~4-JxuNA`G)%0^m4wAGIxkv?Zbwux<x1BJSXA)t*QP
zWip{TsQRu$|J{-UXyZ8H$;*~s;<M&F>jAsBzAeAB240p~Zp#=u&I;`TuIz00<}y3v
zk$v4jzv-dJ%aRrvaW`=Fg7eG)|Mwa$+P*LB$Uq*PwR}TcNAg=OmRTgMnL4PA6;dDC
zX7pMewBS at N>=DBJ?%+zojy7u5H8G6YL at hY6cxK&~HurbFB_(Imc&&#`TevuhNccp1
zR3&oktvA$LW9v+*@Wej6uwwv01t6{3-nFM`awjElxgOgUP1uVTDsaZ{(GB+0fYWLo
zV%qIC&NwRbNxq?~9#d<Bix)~R^6ow#Eu!>z!{|2SwjrdkG${ifOIE|5{jT-<F5J<{
zl#cPu1nc_*a#j|TOSP^f<>N$N4DiDVTXhCAi0H3gJ^qHDlO=*1B|WNFKMDM*Wc~>t
zgKojnPZHtlK~g_#Zc3EmWWxOz7O>zCB3Z@#2iS~ZzNr}^EmVDvF1ko&f0QjubL<^!
z*=jmoIq<zg1r|G1<Fp1dq%%m`HyB&x)pj+$CN1C48~d};1=EKs2H>g$eDw<M%KFF_
zgy4z1BDM%(v9)wPH1_Fqt_U$r1QNc?La*WX;-^Yt)Q3}&W^aU7ns-jV<#hUFf?4ea
zQk3=p#y3bsCfbnZ6fi1XQQ<Xu+-o)-lrYDrI)7A)FIuliqZZo|XJZ-ucV=!G?Kk5_
zoZs&O0Q_bl^OyVUnc=Z<U at j-q<VcdP&6`_-V3=X6(NLoQoT#NtTpiR<LDr5Ff9!>-
z%~R?~liViR(X<<^%29O8wdQ0W%?d<Eo>wq{J!Mqas$FbOkjj3LE#(!E1;2>Z>Agmz
zvYxmEq3A$DxtG>JJJKw}6i>{y$XOilBuZxwMh}7+YhcowHCawC5l@*)<IP{rjJB-E
zr<<hD;IlO1QzlA83ziv()n~+(dx~wj#2x6N%rj4*dD<FmTzNr`uG_~cF(<mmgc*zJ
zM_N;9QD#f3V;Nk>Q2(oB?Htl^tf}BlSqxoE)s9xQl8FyVj+nWDSJrP<V<#c#RUG7P
zn^sT>Jmor=kRSq~0*YiNDrRG|IhJfdJ-vqhaEW?@b#WOvyn0M(N91JJ1%P?;vay~~
zpIlU`PTv)%kp(6%<p3XkrK(^(Qh?hm)sNVuxh33J2zUaL0 at iMz+E#JfH=MM6=17+K
ziP2G=mDr_yx5>v&3R+f{Ow3k3L`&CsFNq|n4|%O$*Kb;ktjB<ZFqj6loY2l-ja1-@
z#0pcij#DNu5bgZMu*kJd*WcRI$BHUmziM1Im~(3SJQS*DN88b<C1m at lk{9NuzIpYr
z+A-6g2mHOku&##b``Fw+UIfy`8FozPc386lBQ%8-u@}CNVv{a6 at xW?)V&>1JCpq=r
zt at 0F-oo6(DQks}xX}+jimB((mI!Co at QEA&`^%JvFlPL<T88c0etOljGU#Ysh)_m}H
z8BAwGe42oOpx8`KAC3`6sOAJdwjO^92qrZi<>VD5szne>Pn)X{=xJl;y+)Nc^o|^l
zmpNqFPR~f^Gr5Bc!&oq$OyBG#wpa(L=jnPW@)5T;&rn|d0=UO at X}YI5>&?iY<ChNr
z|KfT*D4TbSYN}B~pHXF?IL{Ez&FN%0VLej8fvKMR_cUS-`}+wnl)0z*3gD-%RXi!S
z?J$=_12o0ym2v(d41$)rX9YI4)*_QDTkc(9R)PAZ<AG#slF+zfSm5|3J5I9Vt+ at j8
zIWZ)QY>?Vzw8Ppt@;t57U?Nqvt4fsFM+E+~yP!vQKVznN?R-_iypLf#Sfv%5A))9y
z&-T2}$vS{lZBiGO<HE{@_&tQ-=@p}7<s;eRx9DssAUa){8s0yn^(2aE?}>#upXa>d
zP)YUeBP6pMSzDsbddX=w=j4<L?8XWFx40MOF}QiwYI7CD62YI>_1-0)Tqa1Bfg^jl
zPU_~RSsp54-f+2r&9~U|Uqb`QKoR!eTHP((Uz20O*Wcrt=zodVqzHknQBi|m1iR(f
zu3xQFD11iFT{CH-wV~NTe0_!cP*jywr}$q(mTj_}DZS;*Qod!qgnWCnfG}U*J#V9}
zz+0f%e_)ALbN#JyCzG-lIxFSBUH_Xne%WJoasdg^XIqTOH3D9y)q!LHpcVi3`?7ql
zinU~3X;<1 at e<%2?*Y3iBb?^Q|0MQ!}j@``~IzE9J;H7A%o~EvUfz+k?TnIG+6$z1u
zwd-3N#x{?Zk2o!xJ2J~l%St41=5ry0Xl~57`IvT&EmQLuBmD=I4d1%9KMzpcL=6 at 6
zyQIC-<*Q5pGW_<8#3;HeX+3bE5 at d)fua<Sryy^-Hh@|E*btSyBos=$D^scejnio_(
zah7o<9!C6PdRPPfqa1Mp0G%7*lws2?_N(<C%txrg3mL(hrhZ)Ib8aZWH5uSH`K+r>
zlV5-zMA$`S?!Fp4z63=&9tP6(XB5Zj?Kfws6=<c%BmEgFe-$X>zdf+^G-2dJqDFN*
zD#ab{DD{vneuz$fz8m^06biYGXUV4;4@#@=PH at ezqg8aX2eWCuhHCB$i#;oQ^|W9m
zQQoiLT^4cWGpijf`lvX(l)LdzaVaz$#2CA;48&|gS<4>U3 at Q1H3IM_fZA7P#d3eFF
z_9t_=U6z}`o>+m61I^C_)_F0(+7iOyma_Y?q^X>iGJte$)a;zyR?W4=oD#=6Vi=(A
z!_Z(WALM;Q8vOUE_+=yZNtuw?Xxti!Q31(w3^ZmN`J!vj7hP$54&OdVz&56nU`8l`
zO2ffYi9cFbs%Q1);pR1v at Tq7W+~7YympB(716%%bqq?8?FM~oL*-U{0VM>qp2|MER
zD`1+nm%}N}0}p6$V#0#JDWrE>MC<EQ!dq0w+1VRw2Bi4U`Mqj;E`NV^!i%ZB4|AOZ
z2DMuN?u at twn=wy&lR4=Ea^kcSl-$Gbvf>K|$7f+?uLvsZ_Y}EOMfApd-IiTU3HoWR
za;JzA8(Q=S)Dt=8#Z4BUC-rI{5`%wxIYIbM%T+X%vM<bk2n5|f?<tnr-N4*qVUA&6
zC0 at 00lKH34F|D7h&y_n?NpOeA!zDzo^iY_QUong9t23>kDN{#7GewWYVd~?o8&spq
zw&pTXPpS{yFb=t!Af|huJ8`a-gKDwJFsK*Ri(ql)e!(U8AqDl~4>$B2qhFi*&%|Hn
ztll>|D5;nZjOeI1Tk_;uMUR&VtF6!Z0R;^N?^X*|znD(@%}$mK#fTg~qn;h05RYNC
zr^o=#mB1|lyM~xMWtZu0(<`8%0-)j6 at lyf+***@ADc;${?rXEMs{=Q=T4eYzG2TbR$0
zW*64|3p#4V3Xh`vX2&i=2mUeVC>7ShrSF?lEOB9_vC;bLdZ*N}62kQ$IJwmKru5Pr
z;gY*CW9*W5-32m_n1+%OyETM01dhhJI*6!?Cjh77=xFODfVfh?F$c;xdf;$VXl7(*
zL1SdJ)acvw`OEJb8oC!MNY?O(0V~L0b4#fW0(Bb|V+|LwnH_2heTw at 4E}2;Lw}Oah
zj at N;XhD(Of=t=Z at t?r^C2Og{0g_GW7?gHR{`EYdhr;Ri3u?{&~M}7R}zF?LO+)4}4
zDH25hFUWXC1eE%7trP4fW({yKzc at J1vIi+J?2Agx*)kdBLrI$Y)yYTvHX02YE5jD{
z at Nc3iHIh5Ll0pIqmP~!#k3GO>z16=4scT+sg%E?7!2 at dNbc0XKSc+***@16L_+(YxH
z&JcakqKw)-$bRKE%Ky6E|HF^-;^KNHjaL!s*I9SYG>LCh%5z>R;lK@%TBXUk@`$)J
zoc&s<536!E954-%xW&z7Xq|e=>iUsR#JTn|VPkl7bxu83x^h+6LXQ<Q&MC7c)!GW5
zN;XSttH!vpYSO}G^%r;Yrr5QRf`rC1FyRxXpPfDVsLWOalA0z*DQQ5~QxtzVLBB5y
zT}?0G=nueo$+rezOI?R6rYQHZAuxl(EE*CwsBS6Md6x+_6KU2obNxk8vr7ib%T-*n
z=8;)(oEO;|m|=`&7DyNDc{TCFm*c*&a%$1TyeLWt&0ls=RPoj`P+*TWcw~Zr{1Wg5
z0EWzmKc5TnJXI<{z<`VyNWC~zL02V%B(Xcb*R9Y%QV(<}2_V!YN+pl%#xXmwqM3?w
z;;BJ&QTOsD-X?9}KPt950iIp#PA3cSP0b#<DV(SoabnHoe$uO-<_Q;=ErdW%H>(DU
z{(I~v0ys)LRN*|aS<S^c at 2BN?`Ddmw=*p5~z*nC3zXz-{mUc_Q?Z1Rjo&Lv+l=o%j
zqVRv2=oegpTyt>YH2?}u1Ge0E>w}6ry5rE&U^1ciHagA7-EA<ex*P!Xx2#_R?+o?L
z90Q7FI&`45KnrbAd^6uW9K~4>EpOcV(-5SuAo9d!qTk4Et#KLH)sL|hyJhOG)&7=!
z#9?Tm@%5<O>yzB6;g}l%I*AN`C3Uk!_*z{AH&gfNyf`yA2dXvqnZiu&#^F{OTYL?-
zL0d~rIjhiOGaOTE*JtJ8$-C%I6azZkqdG;8AbW9wi{w0eZrS_hr&z}WG}!+ZA-<4z
zD%we=jdY-YT@`{!`>ef5_2JNQll`!zcjbZc)Y=!UA*F=E)A?@{n;yQ)`BT3<jWq-W
z3dVf0>typ0ywcgx2xRE;zBx9!oi0*ksBV$?`&lg}0QhY!ZYvFK4JA<7YRj_vd4Sk-
z-gK?a9QYr7#!rsCRNZr4 at Edq#gHRH#m->D;_<`C=PA`L6ndGfxX at cQ#D=vIHAqe2L
z`ir}k{ADOOApWkp>`mQ?F`7Co4l|uVck^t at Z=v*<pA8um+8OWKusbzDrcG_CdfMGQ
z-`9syxhRr2PYhvn6XFb487)%d(wP*AN7uqViGR_>81~g24L)RAB9-`9zBDmYp&ha+
z2R8<)zOkz#8$paKhV7oYp<{{9!Uh0Eq&=eN>pl1gb>QGbRr)>W3i8vtc7vJt`A+>g
zqsmGi$^*laZ=%M^z2-hQj<02rehnw7X86OD?u-Is at GWh>wiTTMOd0W(A)G~6=n&A*
zE)1`g#QxUwhYv%(Igs(3BJ+3_C>d?Jn+NQoKxXaXe0txd(bd0l2;Qfq`JZi+_22qx
zWm4TeJ)H9gc5N4PF<?~PoL{w&{UxfWUoD|lWCo?Qzr`F3&_}eDvQCZaTGWaH-7>0A
z=?DxoS+ooM*RgxR8h>1pMcNHlKrLMTR}qXC^6b9H7wz;;#4Qn3JDPj at y^L8AiUoEr
zTeJnSHj$>frH=#73&s7HC%xZ1j(5MWn>yv13Pq46isnf#KwizJFblH3P7<pthl$xu
zDR#ikT}YfUgtY at KOu;wvr#5KI#!+@~ga2dQhd^i&uqvhTs<?^(KP)t2^foIiI0`K%
zLTPwWyw914E1_3TW)>#E#2KHn+JaIiTbfnhKxu{u6LuCD1{18AJ7#&$u<Hb}-MTlQ
zUeNFA;5O*v{RbYS6+jcOd&yPjGGe+#N|giQ0A0ppbabsL(Xe^8{U)1e(lqCm0#J$u
zQEEO!^JT@{To2_DE{;PKDf?_$@7Y5?2IxP0IDn8k=B(apTRS$q_z;e13qL#1;}GBI
zTXj5bg+AOQ9#TFpTo!va+x31UiuVLKM9a9AJn at svDmG;}MTalZNg6#FBPhi==BRSI
z{J~DnJ$7wjT*o)osi6 at AOGkSwx0<y-K2sye#?+kf9{<jAy5C6VBvSOI)lqk6LPPDA
zL!<eb#?s(_YBPW#P5=n`3+lIHYCu-pZ{Qof9tyZ$-15pcn0_YMt(uXG`*O(Y8!MZ~
zdw(RoJ-q_98}v)#b*zXl33A#4*nq&gR*Y%gMCA3hGLt5A0 at nVOp_4>RU30I)5S4mg
z(p=^5xYJ_3+*dAU6LWj9yiA7)0K-lAc|ewvswgDmT}0`NB*<;KERxk|7ohudE82WS
zT;~*L($%)l^0VLSZ{cMtmtw|OeHVU5Iae*W`Dd0IfaNeY;ozFe=8GRh+Rw#2m45(v
zcGG$AsHXJL)x+qD<~Djeqinri(E*<;KNqXnGkC{Ps~feG at s<vBiAV)nPt_X3S7{C<
z)9KrzeKwnNa7OqW%IE!cEpWDFtgXlm`p*Z~04p9q at Q7)9(_9}LM7|x&*0{Przuo_-
zao3gMl%Twx!zZaBhB|Pq?3L5l4N^EUaqJ4TvYfMX)J~uDTM$#-#oK%zyKA8o8bvbA
zX7*eqd?5Px&KZ8gtIe8jxp#rh#*qht^o=fb>479s6cdYrxl8vv5d^v!jwLRjhtQQz
zg9zKYYF;wnRhq;gyvKuxca(BCzM@<`gl?I~^W*+ at zWr10khT3oDF|`--6K{- at N5n5
z^)_a=YFD<j-rdtTyv0+d#a<o38vlt1GRK#rQff=akoV*E1~2#ae3N|dZhqU~CMM`B
z)5{7|b5T;vWJ0YVE8$M%1Zo7!4vFc9bp&0Q5|bh-Xm`rZFIQ4u-dI(+)Sn=|KCYX4
z?c4|%h~<RV_wPbYvjr|eMWW2|q%*|&4%Coux>t5_*Cl3knSReh*?0F1zZdj?Qm;Dr
zqKkd*84flfuR+i3e>rF8YAl5OjLaG+FO*$^=teU&UZzMuNuhe3+#$JoZ!IhV939%X
zbhaI&d;dt%-fiAwQ}q+B;8A~XZMZBT$$-Lp$TOb264|4DQ*)$^?LBb|@O$0lj}dW?
z+{W^j9~}(2c(<(LU!}UnQnzvcaM|l)7~`OSV^!?k3Cul`@D%rxZnu^DK~U=jkIb`I
z?m&VKd`21jvvJ!2NMZY at p2fp4hU9*Y4a-Kdz;7}AHnucC>L5rPa<)5Bd+r%B^50Ol
zh02iZzw6OgG}tJ2S-#6m?_=0 at jnx&2v-x(_&Cze<le0PZVuerC+1(2`NHG14l_)q(
z%N{vdjyXs<qBV}@CC)Vfqh&&wN&gNX9Fy)JhkV8!W#bv#dDP}rD-gdnfjr!aZ$VcK
z;}i$F&R0 at FqzK|z7eK)>Y>Q?G$u0yN{B)vS&9fh at oGjAA^K$m5F@>l<Uzas*oq4+W
z<LAU!9MyJ!HuZ*`OqFI|+a8Z>e__>i?{Ym?{R*4vnDE)I(d=2t=zv7DKpL7nagw!T
z#kSjxDEe)9&%uDoxms+fyuffbSeD$r`=3qQ2keL~URRP4^4{0tB!v3{^qxj?|03!5
z;AXXr8z3d;&lbAA8#!X>t6*U#CIA=uip_QUzjjd8Kaz7zhf=2uSe7n5rV5uEBCQhj
z>-idgn31cor>31|wS>O9Ynh+HN%*>!lw!Z0VSV;%!}30;R*p$uDFL&ZGg(8Oi%e3U
zRIUq at MLfu?;=d+kzl6hxL6#tnSvPFyf<z11EE7Cif{hUlTNX5yEJX^CPj(CjO69jO
zV0gl(H0u5ni`Yl9-1qYItoo1kDxiy(qqy(*LgHv|G!l&krJ>UsvtHT%9<zeTeWhFu
zV|t0UQF5*4R_aN&K7IFC%wnt8HLORhob}AKWqu`zzZI~KzUTR$V~(i9)LWk_=%(z?
ziL5yX)7v}q8*+8$p-Kl^>X+-C8-OdmIWgixA-;T`0NK%U-;23t<U=4aYdhI!CzhZc
zz~~{X1q9qc0A`SN12stJ6P8c8&A3M&e$qvHMi)QWSpgGWs9gC-9R)eTrWv|E(MkLM
zW<)^7vm<PZF6RCXu;<aBFk>dK@}-l?Hbd>P0AVHWP%c%M<%#$M1T8S2WvEA5Ujt10
z_+IAH3Hkl*i-&MuH3gU%;?;HdF=oe|mB*O&@XCa055%3R4 at 3Z_MPG=@H>JK0eLSvh
zZhNh_GB#ub-JFSfrq^Jm;c?O#XdU_!F%F7=&rhYoE9tsG8_$X<@O8kVJBw;O#0rab
z0JEYJ?ZAM{FsMG4=2LI#TI$QXEM(*CL`juVY!RR7V|N;gGNl3lF4qtZ(Bu#%StClr
zilCC~1b9`wjoQmwr;2o*Jp{DJ0Q2ZE`Z1Mo{|2cpz*TGI*&b0=gKG=w!(uB>u at uue
z2W6v~Tb54&lZqUnwAkN_r#3ERkR2?u{HAGWOF<7{&perY25Q#;J^HRe at d~io>c(?&
zH&nwIAUb>`MC8-3-3g>hL<zt&T#c1Fz#Ef%pZxsXS%t>y3CzSvGg3g=>t4j>5xO}0
znWD=lJt3n#yqMR|r&*}+sZ}RYzQ3ddDLAHb>`k5;mulBb1Xlk2!#sRl9+Y>}CHOU3
zhl2TG`Cx`z<YiCI9T?J<8G1Et*JB*%vRm^je|ovZ$yg)cv$^|~Ua}C!V{96yYfcCx
z`+yV5ooIE5K8|PK3#^6x%Ugm at dS{p;-j2x at 9Oi3oVqRm2Mo!LKUfbJK5hxjZzCVl<
zyy)SQvvYNou70adn~Gfu11p@=*(&|J^Yd at KM2la_!m~p)D?TrGn;y*@O5e at r4*yTW
z)Vb_~|NmXa_tHwPEn?GYpb{FsXJyD3TRH%YlIk!dxN7q#2~QKEp*Go~nbG)~q!1qm
z9F+mnRHw;T0u!3SNUf#@BVyE~0rh1(-thElJhIqe8|O#2KO0KCAZkg7j3vW*eZ=;i
zoO&+j7yLsd0UQN5H)UtYTxR9Gx3GbH4%_!P(e+X>qLwXnqJti(5fTUZ4lzu&vn(Eg
z`gw&J>>a|U=xU&mv5on%oeUiG`&hEz<378i1GeJIs-(wkos_pKKcIpKrJ`6=A46o1
zh9bg9n?rnrUXL%%B{%pCEPasWWC#=>)Ln&rn$CyfM$bsLbtTL&gsx61PV>jyW50w{
zYJY;91<b7t2hczX`t!`OEKtRSzl~>?GX-<wfEveuN7z)dfzd`SOn8JNHiYewFnpaP
z;`%4rW`F_jhxZ*u7`nY~GYWHNqAmGUVn_U-x);c$76P@@rC$lU|0F~5cmBtp@#4>j
zT*rFTBJd{bB(Gp^a5-VU{TBfCz5e`9$I~>ugQ>!m=v5ppPwE{bBHfn|cV<YdyxF<_
zrARbzRV2s7*+1iXEdeIW^#jS^(W=l_EjGK>q$Z>MxaFNi at u1yz$f)9l$$%*v&U*v1
zc{UZpxobD(@07%cXjvavD&xlnpj926$_f}mwtIeNwPOY2O59lpHImy*u!$fdfwPpU
zTin-ddlYb|cjScUarBgVPvX(wIj`55IyrI4Z`avS*-p_H%HefAp<Zk+TGHN+fiVv?
z?x_g=r$EM_N*A)XFww{mJq6^%q^<2MHu9<_7T2qB<?@>tLNg)ZvpixAFN#A0##*&p
z;|9DD*sg$)SoB)fmrP$-aN`^vaH#A1-WZr61~4)c&8yQeZHA;--nUH+oLcTIGV|x$
z!_>@mcDGUFEomAt5~9aIM&og68u$8IxY2RL0_<7D>GeO4J+Giq-vXXe+8StZmH};$
zfe~vgg~icLKTUcTtcl|J(d3{}>Qy^A;HXx5w#`e>jhYam5la?i{ZL<}c?#~Cf3tyL
z4)2$Zv?TmqhFNhUe&R)-vO1_*k<{tyB6<LA^YYbrV|uM at HySdcoaH~4gBhz-6#4Q7
zbaEO8W^8{Du6=sdfWx^O<DMr9Bi-6J5RO_W^%akifyy6cRWJMXJY~xzF~&#|p=-dz
zrRMN)PhuaKXZV;o{V`I4{((k3F-9G6W^E(J411x0-LPtOebFvue^7J#Pe7Yy$4-Y~
zf%ThFzm at ejd@@w;uZ938ORyo3GSD^<(&x`VqekOy$=%DgHH-b#Iy+DDdR9G{2=&BJ
ztmmQNW?OyNTZ*3`ul|heJC(vGH|A+L0(IStyUMds>Xp;V-vZ4n9bJ4GPg&!OquWh*
z<SwFJU;7IuG72-6)D at hSsAX#)I!N!+ at FM)|4N_Kcj1{srqVqC4n?%N at s&aUkIVSxX
z{}40c_8k9)e1DL3tX1u(Rv05OASZa-J=7T-DgY_`h82FsCtr(v)|CHjYJDH~0H)rH
z5jehTHQOpD?w|(u^1$nPurYtO6dVW`3}9o?N~j}ssVkm9r>=#&on_t41UL2q*(}3a
z_dZ>d<8neZ#wc3j6H^?A!6pGGH)c~6aR;Hk>JWMMnq5^a7}|siS8{bv=U)(m1KT5>
zh%CJy!jf?*0%$9A!@mp~q%0itPXUaCz^C9_awzjM&+zsa5<@Cy6sw&W#jH)BIb>}#
zdSva_uB)6m`-gm#l23F*NVR9OO&e2HSAoU#v(@KK4;4K&6i_!gJ)Q*?%P~6A<s_%s
zM+38AMDU#c@;jsx`s;%s)l|{bt1IFMO?IpOdSu#s3Aki)xegErK#wH$24j6xGa}K6
zWQ+sNvYXs!GPF2|NaU_k*Y449w6Al=S3hnTDV;a|=}+H(G383B<9o at aWHzkashLkS
zeZ`OPecf~y^7hA_zzn53_=mB`e1TUg`Et8cqT&?Mx_|$Zm*uo-J6#PA(y2rtb$gtK
z0a!*4l2q&r8g}>WSc$-9R7F&V4mYJ_n}Roh$#(naK8!Hnt*f%1v9r|}=Rh5yH+KZ<
z$}CF*P1TLjoCcw<9uf71hl2X)kHsIG0w1YGSU+rx*5ga&c(<4aRDVy0r}Ha1&9AIl
zQ4t1mPz04 at qbq>iiH8qxdWv3a#pY?So7xCq=&Fm;xaht&7%?1yE~rZcHiEc at k$pFM
ziV{V^e at x4J%XwA!s|T}%ey5KmeAa3sBXcgh#|?@#1g&!yA%EwStMQcf0%yX3t(F8!
z0BO12iQBbF;%EA at S^p0nyHhu1OpSM+0`X{v6gDXG;a?(hLvw+}9r)+nBMe_T=HrB3
zPUX(S?7gB=$ufbHT+RcyK3-kTf!-1aiX{7_+5j$=K5(N4V{1RrfXX1R%5#SCfHj#n
zjwXRb#x at jdKiP59)rs7{ZT0k={c at J&`SjzA%csnfV=83(<mPyYGFATDw|2%O3&WQR
zfzoO>yVx9`Gw at V2ZeKv%ieV%ff9j{akTjpFeai3d;^O0ukW|<+XYH)<zy!CZz-zB}
zflYALgX2+*f6cUseC^FIf5J$6-wsd=NkOvod>Os|276#AKpPm5`*(==m$LN=B}Ww*
zr6S1jLb1c(gM9U_lK2GD-K0Ju)eZeeh5DcSTjpC6zjZ8A8{QxPJkYtHa&1nr^O-_E
zc&N%p=#6`<$hu+H+uLU_Y`VUfy(pr^F21w%i%Dm0TMTKGWG6`OaN}{}%e>dIWPH`P
zH0WZayX=H~5+K?9(@Okz(#`sO-OPi}u?Z4)!Z(gVhqOE6$~eh+yn|Ju8lPEhcK11+
z at sBR-JK?OblLDQDO`!GzLvO3ZHe%@ft6x69!rg;C-Sv<9SSBJwY(v-g>c6dm$Jca2
zBcW>BHbG;;Z+o*vkL*~!YQfdlLey<{^bdT{qeEm{qDD!mY&u+Z0yo$(fOBrW$;4d>
z+Lh-Ym21VhDvEUvm^*FS;=>TUnz7YAM;wWXze93(7^NA*WhBOztv3PFltj<o-4jFd
z^~DJXhu at baRb%VV_wRm at xixe>b8&v{cI>qB+LZELvHDNC at xYkc!BqW at Kd7IvEF|f|
zf=gO_738Yrd+UR07OIH}pevTGj;_XRzIix{wCA!a1B??D#sNIdqERa8XJJU~ROQ7u
zap3~w&QuL~8LRKTUD8j9_3n{>15R`p at BI*2XJF(Y>spfgqI at 2kq|gR}R6M^KnPM0P
zFs8LXYSoRG=awGp at 5SSK)9YJp_X%&f>}t{e?xfmekIslYTZbwQoBQypd!qkiu|3O_
z{tR3Vh^1K?U}W*^m~ZT7W$}@Mz?UV|ow86Fqwp<ZIr(0=6kjfVvuiyuR7zY2L3=z)
zHb=76D%a+{QUKh~UL5{2h-iA9EzRTf7BKl5X#4M&S{qYej(>t*?)R9P3xl$>AG+pe
z#8}Z66_}}EEVpl;;chrnU6gnsC1`r(mMV6~6)_62%SjB>2><2a0yq%v|H~WqUP;jZ
z#n;96c|V;k_uT*E*}Qjuy=Xf4|B>!j;6OS9$JZc;mepU0@()ZMW4GC+Lz*aHY+1^p
zMlK%J(XmE(pi=$-T?jKfLhsN!LB+;6=JevWHl;s;SWG$OspD_ZELD&?DJo6q1pO5I
z0`<y^P<&kr8jHb3lBHg-<dCdz1zO*Wg{9=<z+nn2f|r}AJJ8Y_GevECOKB18CWesf
z#m>x`-GLMSQs66n=+^~^eBnoW{7!d!){`5WsCp2i;#6j0sSLyvJum+lfrFX9oE9JG
zKCEd<rj$wOqBxLLa-P5`_F6gDfS3=sWxRk40whWYG^P^Vobw)!1PpTnGDjMW>Y?l_
z?e!jNjpRHuNC2_}mQZ4nK^UkeCww6E0E}c%yJlNVUz8SlfxL$oXn`M0oEo&!aF%$e
z%>ah{s2+Y=9O11_u7P+9v{ZSX335|gKA`~#H6v3YX&fHv;qY-fU|YL0b+hDD2e%~f
z&J<S$0+tRqFqzaV<!i^9uuf9+8Pd4t8Ek5C68;ojk!V+71RV4ZjexOM3uYF)@6@^U
z_sy^-XF+E-w#go}Sw?`L3>Eb2IY-4_Jg)JZDz at Q;122<iO8=~&_YgE_7*559%n7yV
zS<5TT at JTId+FUMMblArYX0;SN6;I<4+=xok9SGKr|7wl+5<*jdqsSbkIUBQIayUz(
z*0=sSAMh+0%R$A`6UAwu-vO}qW~0iK{=x@(L;DwJ#M{_%pu=M)b)ohIf2$IYU*14h
z>FUy^)&d8#8UaV*uK%jtd?2_aQ*nGYh8z#jliv;~QZ#D|D}zwCTWhPggWuWZE}dL;
zLLEJ^X!~xPIy)is88G&(+gWa<;i>RQTuSiDQ$RzB5eA6YcIzS*Io;HhEVrB~wURB`
z2qWyF_N!0mZLa4gdw<^Z12YcPD^VIy%`ENRnFR{7F at 0L0y}MH1<mpy6Wvb>~${>01
zrZ`JyVjZwjADUkk1|C7FGH4ASz)3y8%<;G(j7P=PDAk at ZfRJIn?-`$!`%mKM6IU4i
zTS;fxbw`d{77<DKkJ1q|tU&@yNj&5D2n(8id;?H^JsN<PKUjOz#}`&Bpn}~51Z&yF
z3`C)=`hX at 4j4kWOInw~cTb9s_YG%r|`=h__^pE{aP>w2{i6;{_mCJ$n6uo2MfV4Nv
z|2hkT5{w#dFoBh5M{^LvM^(@1@`OXRfep+!f7*Lj0_wQZMZ8<e2_aQO%4YBY7^^FB
zj{#2ZMZ5NNV2WJ*c40d}#_tDwfCOq>^o|hGQiY-Z;J~l_;I6cT`on;wG4=ntVBS`)
z<|!<l7m=j at Ff~R|7p#u1-8=iY7Xc4V)Ccd*G`pM8X_i@<9Q{7u#u5UPX4>1<lvTp7
z3O~wl at N(1(%>5fX*RKby|C|hE5kWtaM2YM33ULQsbWvn4%|tj_{}C1AtXUq>ja-YX
z(m9deSXzHvBMPMvl|B*=bTv?6rUI631Q!^aF~^9q*A7?soX`(XtFFrckgjx=fn8sD
z%YO6mLWS3bR=%#s=Q|aPV_2Curd;H!jf4`kgWmFxCEF)c7wn_}^=q$BD<ircc41T{
z<!j(Ovg at 2p;5P!Ynli=?cU3{X1<=TX+QfY9<459V<me&w;)i~~2(+0li~|cFhrB9W
z^U1 at -?UODd;wmv<%my;SQS2__x-UErro5vi#m!AH)RC-JMecO}?X`s`38Xtw%Wtx0
z_Lf_QQ(u0L&10o(pC_#!cuVkYS2_ku4x=5g^ELHYOzOJjL)Sw+NAp;TV7NnhK~s)A
zxzqqV<9KIveG7RsJl2l963b)Wc=?cg>ZDSjtVv1;cy`p`tnMjF(b~GvoM6nF%h<XO
z)eoWPSgcCSCQC&(229dvUHc?3J84)enXLXth6v+;aodHh2Hg6U#6=|5^>h*dWb<|y
zjyTP;9XwpFcwOCU+ld!mWUR;Xa>hny+Do6PJopv>-h4p$&6PpQ at UG?{q6L*!?3^n5
z!*Am*I=E#o;4)megLCZPzXlVv_y&uHd?;i35w93BHD$7`1oQ|Cu}OD=hv?_Pf-1J_
z6Esn$dp at kSG+H{z!*!G*@iJ%Jy-y5`knI}1*FNk1r~MNVba?;6Ow*;p*|e9~3p)LU
zP!!N$`T(%QSezL_qU}3U5Ay%*s(wZB(-os1b1w$)$puEt2ERV;B``%RPR{Srhbxps
z)dewt-NlLh^z<y%aCAzd2YBqhw%E7{tt}5{^^=}K%$u)I{2PXHk at RZ`L4wRrGW at f_
zMQcl>pgpTN{b0r^>*Qvbv~FrE60oa(U|`!%gWRf$b`E;D#&A$ld_7(EpiDw-nXkbE
zQ78d$O_A;gwQsaVzz|kYoL`RtRB_z3Gbdj~#8GVe at VyO%31<Z at 1Mf|_(dd?h!GUaN
zKw4l;dwh^gUhYb+eoBU5Zs`fYd>E&dO%PFXG+oRyI<Bv;{zyC~HE*pTnWhMEL7DzH
z-*k_E+}9tC^*p^au--e%GM at L&jB;w4EZLS4Vv78PBtP$%cZBkS;v>9Jw1R5ht147g
zKLVZ=r_|HiBer`3A&tz`A{9AN^GJ7H at rvUaNf%?Jrt9_*I%)kyVO+~iaF;f)=dl1(
z_+4$@$BurL9B>y|deN?+rzqJrL$q1=59Yz?_%L(~8|oTjAYxt^ssRmV<=@AvlXqU7
zmi8SM_Z8AtXm21j#Es`9QoCE(m<C`KKt0KPyCSYuYhR$#Kiuw+C`xi|7UwmSO>1qz
zJCivDQF*K26$@1KEQiN3eXsUugdGX6l;Xw+ag}-oN4*{?w_N;zFEonCguq}=FeH(z
z{=O6+x8^^<M*bT(b^Sv!m`pVGt&Y^>=)fNgR--I|`?S8d-Z%{`c}<z~V%1=7ZuXI&
zf`B^-Kz?28(mItBE;0BNsE5XsC0?eq=q6MXSDi)1g_`6GUC-Yn%yXu7o+HZVw1a&D
zscehZoq12|ugYBSzv9ry)@-g*sCxDSeB;&RtYB3MoSCMd0$i1Ea&8AjYmaxXjmpn&
zWO2YfA4|oz8GJ(&(E(y3%2h8CwwjQX<KnmCT8=60zVN7n7=E78B%LSf=F()2>UoJ`
zQRma;w|2&|UhT`$>4#DPu;(XB+2E#^6s{VK1+$)4g>eE_IL~uOtwhVxek&f^MLSH{
z<^U9<0rP}4XsUr<x72(nb|s)BUb=2BRFc+sQci;?h>&QFP>sRYHa#iGtr_`0Ouczn
zl4<+ at uQ}<oIz2U+rdW?p+mu<NDaumQlQg4cO{3<9l?xV?8kz#4nNv1yWKEigP&uUu
zLW<^!W-gcuXeQ)}J1Pn)0t$lPyZL-RzvK6x2M2QK&3#|jb)M(@{dy;Wn#dh6>ty{=
z+$DalMI*t3699WgQ^zudBZ_&G&X00Z+TFhn6JWblvAqok>QEBSxQjOTXmWnBT7S<_
zxSpW*`)d|9pO?!woR|Nx&zWzL%~j0kca)aEDo#wMs)2eb2i(~cR+MYhk at hPq9sJ_;
zbU_gQ2h=9s^c0YpMDYr+p9tL|b`<5XGcyzyO3|$7<)c9PeDV^%=s3D4>tZe at hB{G_
zs at _~e_DT~{8j^M at 2tddEwiJN3+F!{fQmf4)U7|Wv0>)dJ-50$M$T^}R9PMIP1Vn`k
zzK%h}exM2`s&fU<9>FGemmQ^V`Pw!KNWPX|nFRc5vHb5AjMDq`-4T%pnPpMmV at tW3
z7KNe%^JKk}9CE*XgLq(cJHyH-O~}CHh8#%ay<7NBT)w#RPA at j4OZ;Lt8<)y(wzSHF
z7}cEH50B<!m%3AL<fN_)@Vve9FrnQC(W5I*vXN)x-Onk;Rt-Z>a`|~6O!5qwlyTMl
zY5=(N>(~mFk-l~OKsz=`NUww%&O7E&bI@>%TV^1I5A%r&>i|O5asrELUpWa1A|yL0
z9r&u1x+>Uvz`=6GEeO*?`T at 2pbT$GM>N(PPq#<?b)2?aDP+pNQ#|OUT3G0O4PJ^&K
z(4C3wnn`n3Zf4K>lbIMos4+K`iX~5!;X5h356Ba~*r9qj$%#vjsA>yjf><xp#`P8n
zlKYIKdCxG4R;ZvSaJbU#&D*UVIBVs&y~A%3+sh4?;%)kpknO(VhW4o;zHr;ZgiHYW
zcFgM>dscP|Q-Wg9^JhQ(^m|^w%>4S2UxEOW>i)I at spBQYleSnd=g<85sJ=X*F|Me4
zvkNbHWm|<w=tK<9OzdZ<{+=m45yGF7N<OX>c(H_=%sVQpE^bL(`femx>l>wSYYjL&
z&8 at Pplv*a5HBapD8k at Xa9vb{bqWA;Yu~QiDg((uecW0|Y?HKmA<%M%{>#gJY!1`n#
z_OQ~I&a-NX3<a7<*Mloaqjwm`=lxtbp8I`IV-$MXS&H9_&ahNNamfOb)Wm9dU|T8w
zY(NK_i>C`830s3^JDiyVmpDh- at a?9&Lp-56V{>VS-z42gG<{D(QtENcV=cfR`NNxq
zC&&CUFK!8kg_}~VQw_Ym_&zBpp5mj~&?A1h@?hU4tOYVO7y#*U0e<YQkd<q%1Kv at X
zrUJ0>o;*lCDd<agSxB)UgV^&GbG^XB5wT8KI-`<ywUr1Zf1)@8s7~40wR-Y|{R at _X
zyz255<Fd|}E!J&-rnSY4th|y2Q{p<R at P!bYHuDFX>8UF=Z4b6y9y@*-vx}GZDvD_W
z^!n`WvZBJ@^teXFK%>K{R|CXktkX&B1`yg?c++@}UdA-JlROR-+JL(Fe`HO at ABo;S
zC110YmU--G;*X04miPUCwyfyU+V&l1A}pj)UOSpp!8-k6QW2m({U-T3KVXvi>L7|l
zAnrV~peXoXi`(+$0h0_sasihrP&=CB|G&%+%Re=vz~NHW$T0#w(fa>pFqSErC&0`6
z1`cA!nPM6+(u{{}g5G!Y@&S}d49r&fw$h=I)tg1$3<6pHRah3{E!w0SiOXib%QqGD
zcH6U&NzHi;Jrz)~PwM!Hd}^xao#;Ns&$7K9bWYd_M7T`vp^Kf`J=&l>xy?>vk-+2I
zQJjxmPgOI(vjDK~S5Gb`)Z0ceU~Xz?+7X<WBd^Mb3}fGWajAk+Xqq_nM$0L&z1`GN
zR%lw=DKs$b8*w_L^+XY>Znh;d3s`~k?vuuAyMW^?I2%-uRMt&EJ*0;fy#$1PGe?a|
zpc24dRA0+07J%k2dlfm at zJv^ps6)TeduQZi<U{rh8uLX@>1);ipR~dOM+>tCvl5Qq
zo2$7By_vu*X)qVj>31P`Qzb6)1?VIeUb>SaHfzrn{>=7CDx0)*6w*ihCd-ELF7_xu
zXJ`bqK%NX6woPX|jCz1gCrEX<C~x$*(LG5;mFS?XPj&c`Y8L#K`}!d2G)Dlp&~>hH
zKCu)uvs<oTNFvtMTVlCp^>5AE#+f+XcLSQs7b)l^`L77o-<EnqP0xf8gXiE}XHX6r
zrEzA8pRTm3#s<*{IWUMD!4_!9+f{F*{B85E|Kc95Pr55kNQy`B%P0~^oRS!%nh32!
ze at 1kxais#Vj9H|ZEygch2U7Pw5N at RlILUJ>OL3(#ex5GEhUAB3J=D&&6O^#0QL<=K
z-H&S3E0wBYg+tz!PMJ7zo9{l{lFh70m&lsxRvLgRSxHLTg*_A1aczsWuN5mBxI`IU
zP}Yw{9gBr%$OG(@v0WA}oqop(_MBlE8B--N$822nWD2beG#KI=b`ow9%S5tBc)}?X
z<A8>o*jx(jlxL$XL8^P;RDtx9ZGmZ#(9bi^l!0TG*4!gpG4H4b4wGm*No0??RhhS;
zqdVZY4OVpepL=t9cavfSf&t8_f)xN8Z6-D+pUR~R?J*>1{FS)aKQH7)pfZhf35$L8
zrX7_|9p%GNA;4Q#=f4y;D)g0qd3r`!u>IUc1^_sn(j02RdU+jH##zD##oeWP)=~MP
zTg$wS^Ap;~P|pwhG!)d8 at ***@Sh1C}oh-Kwpy`I}BTf(ldgBr?kw$9bpEdD6*k
z$E;R5&3WRgoq68lKH9ZqcfeYq_bC3PW4eH})Nsnt`M3NaqPbsw1w|14X1(y3wM{4d
zB)E!a2bjC_0H{=WkT;`O=$47W=>h8_A?h8M1j(zUQtNR=pX`+Q at Z9c^>&+`rA){OW
zM#7ET9Tl6yy_I%jH+C^E*=-swvo-Ze<hT&-0Qqz;Ce|0hvzeeVTju_ at gFLJ~uu)-}
zdLVNf at mi&nD<1Fbf|IeB4^A2 at vrc2)Mra2V{yibr9+*6$fu7zXVI;2asnFVz8Ztn^
zZuQ~<pzd}HpR5URE+ATTf`W1<ZMTZC)}3yK=t|V5#lqtJcU-G6yQvR2Xd$&Id;a9)
z+h)nO&ZJMVz}{!a4Sgutp(vL2=<~{l!VFZpEoo8t{^u|xsuVyR37~-8eXCF3K|e`2
z4p{E*55TGcml*4I$~W;x+<I>rhd_k{4m56?^KR at _4J3KS{RLKd&C-s4R(TW3r{=O(
z3Ii>y_z?LEt@(IW4boDGv=@qcfD3r+GhxRUZp?d=idQ6M#mr5wdhzw#x!Fq6l5`HI
zbjyQk%&in?<+sjfFGhcDR+;c)W0DsNyd2)Y=%c7V`v&OgD?gJxEubAsGwXoNQ?UYX
zIpHQMAPOp#k8?+o*>lrft#KcTP7R0od_t3X5J+HZl?|)8;Z8IT<K#C;I5N_z|E^Dz
z2 at 3*H)P=%?O|c4~!rw2y at v2-xo9lJjL?{}#_)1KzCCK$}_>>U{hR7Sc;FnlJw)Vxd
z4PlYS7KGF#cx$K(l}@zyk at x;&y1WYhvnSziSvL0A6u6JXFU0a7b`2OWJ|{ta-b*xn
zKG2W(jY=l!J1~h<S`4Nr0F!efSlsK|-Ir2!gq;QWFTS=Bk6Db+c6S^nJG;(eCs2Ti
zXEsXNj=bT2j%6I%5ge7L{XKDrZfqyHaXF<j#BWO|?gKz$Z^4shdjt7#{83ZQ8TX~Z
zZW^1JuDR9$mspdKuRS(Z81W%_p#qL<j0i#<&ii(!<ogH?hvJYY5f(^bxlk$B0fJv3
zJql?TW3phgH&P8)P6AFzVrel-_c|KlPy7*|Rb(FV91qG9%|U+Sul(D<^4}?9xlO9_
z#^`1=Z-Ie{;c{@zR9Z|}ye%uXHm*;8C|tJUwUEsJQMNjJCsOu507k=sgOd!vr`W-E
zcy+w*a1Ic7t*-#`B_r2EvP|FZ_CGvtIt3&MNiLQq;cG&y=~q7*oEJg_40hJYjKzGX
z7kie at 1lchlZIaDJ!VK_vuYd%uw*a!q1wf(UVys>8jV+E_oG$nilLU^4Zr`W`_3a^g
zH2#O79&Jn{Fj50t at Gwz=nT4+z%fc at oSJV?_cn2x>F~JNA$P=k@^A^&V at bhAF1c>F$
zHF5))_RQD+R;F3iC9cC9W!2(0;!AJf&1U?!#)SdXbqP7jK^%3syJ145)VpXz0R-vr
z9Lod at 8%~J&0dD(TLYD98Hc<MJJgvuWn8rBS@=_r8-k2i!=*K-77p(!92w-!#`FN#J
zrPj;B^n8>kEPLaFEOWu?@_Rz)I^LmKY#JSN-RY;7)u}U^ZB03wRb5mkV}J at AYoW{Q
zN|v3LED*(kh^lDWYQTuu{b;JZ8<?_bV^kP+#h9gms(yY~*Cxlc?aSlrgy_KrR(KfD
z%c`dKH<=EI(q#2mc-Cs4rH+eO`F83tqAkCi0;HP1AyRA9$CI_`Qrsltwg{{>X9i%5
zV>nnpB5yOC|A5de(Z52hSffju*i(c3c|#_XuABhsc&-qCL*^bYoe*O!mwD`R+2Oif
zQ*c&a^p1fPI=^Sep at gRPqS*jxUeOD=%!!S>0aB&X_;*C>pX{5w`D8AnKQKtvCHIf8
z(1N64ozZ~+DQc#H_yg4dZYy`}3D%{}Kiil0VQh0zK34Q7V((J+>;2D#1y_mB5GhME
zWuWW?lea5-*BRgEoM$2{{IAvoD3|Dq>x}_~wqHI!8d!JzQc;N8;Fm1HVPeSJ#GSR1
zIBQcyW(3e&DETV~|0pXrxO=R*)Cg0&{~V!$T4TbifjFN`zj5Ni?Y!M#WkL#DOaUK1
zFVCqR4+--y$Q4|Q;~mvrPHBgFy&-m4CEB_ko%z%aWqC!NTD~F(*It=%Cb?SN17#O@
z<k}0+##mu|FRk=}Tix;8hA*SBvw<BD9$Ni5G16}n+B+ckKwAmYt?aqTcF!Um{N0lP
z+y+;7W}f;C3EFH5-^9ubNmzX_)u5|E4R7wT=HSlB_a(s_N4aKJPysNz<KCYoYL`3j
z?hb?%YlrXhFWzNOnomA_tFmU#7PZ&<y4zzdmu?UbeNecSz5E5H4pHB6QGP#26Xr<r
zHcz(x#wxp4vYp+mxgG1}s-C1YMy@>;;!%7z at pH)uRA~BqSe|+c-1Qc at RdRLG?8_?>
zhnDe+KpLAPe^fqg{J5b;d at 9GAcV73Z!)nqs#1M^Ic~Xy`KCSyL>)n at Q#Q`tWX=hSk
zlYZoSAKM!7Pi>GHmUh?j!1glot>U-&+tj1o__t3PQpCj1fsM50942J8c*f#NM^*QK
z5Q at s8eBxz7s-(_cFTOwWyxkga at ayWW*Y>)&^QLAF1#!N}yPx=DuNI8;o}QiD@#t0d
z^o3SRf<uoSFRg5^r({1TIF=eeKbk7o+3f{RanXjK`x at B#ZYOqKSvQ_%u=HKZ2_a+8
zIf9#}5!(Fqz&$uCW30-<dU_UIu)gr>+Mm5%Z at _w?$A8;`9>#<``|;Mo?>TH&S+>Vf
zJ2G3W%vN75;)J{tl^!5qshBtBMJE2u6O<M%`SM&7_CDeKi>(C*AVDu}a53!6uJ(40
zm$;%M3+7GZco2;!!hdOTAPxY4#&M>x-77~N`+q`~U0E=5gUoP3JJFu7mmN;RBc>=M
zDr$+sc at 2`xqc4E<0aYNc at ewBrd?BvS`MI#YG%U5<Z&TQ_{B6Da_)hhT?HS?)Lt0>0
z%paEaU?_6S;)~bTWd#nLd(^O=16^c7nO!^DFW`(~A40`l$sd3Ql&D}?#y1_}o0hJo
zaV=iN%|xv|F8={DWOO8I9bprbKM-G-!+nNmK##b+Vb at h<cA`7(JDE0|hT-3dXLeq2
zRp<-P*|X~yffUK(U`v2d*+kPEg$uCmDKP_to)iJ&5T$GO)q;JqX&{VEP7>Xhm)lSF
z(J&>{-9%~GG4zRnng{)4>~nbwqZCI9t|?yr`%p#%`s<fQ^2tm|mYMPz3{x=Xm+Bf4
z(%NX=yE~=X^z_vBjBOR-CkFF}@)eYv=6?J%7t?xds;zSBPpI(roqJ$#=K<0UJ2vAG
zmuM2QCF=Yb$Ti^M>a?H37OREjoSpIIQ(?Pw%|$xFhD#PMh2GGs3ROmF2W7^q&*J|E
ziKFsPW50jOy=UR^{X_p}L~KHi!QH+g5zZ`p&}t*Up_c-(BZdz8h<xM!P2j~S6hT_%
z=R`nF_|QrWz0*NUcP7a2U&02nP%QU}LTp_jN$n+4b;WtfHc at +`jrkQ^{#0dBm-caY
z#9v at xQ`vDY88N)-N=7{GB046m^nybGJMc~#mkzpA?jD-W>^q2NiD!ohEVL|+Eb>LP
zh6eB~-d?=*H+Kr|B~K at QONZf<sLtA~-r5p3M*?6g^GU#X2`G3+pMFSsJ!<hq8{b)F
z5=Be?cRtFJ_TSa-=UrDf4(o>h2U1d#qawzvZngA5vPKRENStX_*2)1w5G~3=R)vuD
zeX}d$PVg%Pw8%Boxq*J+plG>TeH at s;7IvBERnl?7+9opIymluN#KNZ`XcYpyH7BcT
zZH$4aSrSm=%Z at 2e9WFT^7Eu~fb9>fDm^#F=;uv_Dm|Z3yr5S-lQ94zdol2RGBT4zc
zh>fyU=@@v4SZl at +@9Ib&kCADJD8$;=0ErOlP7JFHdn0 at 4PtcJEvT?+}4r`7bWt#};
z!rk`FOsyMj<+OrjrDN(ACGktk$G%!^q)>|;XvO*NLC8ff%3PtuxuFN$smYgc045>}
zrtyz at kD|>ZRejhuFz at icCy(&^z-sDrQCSUd(t7S78h?F`it<7wjy*%;6j2Dx5QhvF
zCidmQ{QL#<*Jx1f>>%O;0^UOEZY{@`@F0R`RG=J3;u+fIE9HU;<Ct+F;PR+Sjq4bz
zX$i4!35wg~#ntZO1yz_)F@}KkR)1EOAdwBoZf*K<>}Uh_j0!hJ?hm1G9pg)R)9u<#
zf+|t2n~Jzj99%}yt-zzztl%k(lo%K%YLMkcF|g+&>^DL|rdb|oQH*RiG)S?c*-W}k
z?P~piRZ)pW2G*7!cE>apP0$*}>0KDDgZ;3!HQ~zZw!Y&%_b;a)f>WE_q7Lvryg)vr
z_a;gL%lZ|oKV1lOi89RI=0`Lxnuuc at wq~6vzg_FzW;(iZMe6 at hDTXs>SEnIkwlAJ#
zM?y>%ea7qnt0#a?^{3L=;<Fl5OuWMY9!(0kOFfgr+EBUAU3&ub67zaOw(xm2me+3V
z|H<}z|I{a<Az75-oW#_Z0J1nF<TI9EsR{yj22S_jW_OM%ei)df<4?bFRtBvp<`Or>
z#6JF0VYwX}!ee2N4<VKZyfwyx?APK^k+&c|hTp84bIKx6Oo?U6ks`_dYqI{bJJ#%(
zobmUX(h3<}l>_!h<RABQ*h|9Aw{*kySeO=#p~%rr4Z5?S at DpvSSPuLlrp$<MNv=aj
zvp5eYpRdN;&gNpa%puUk_*TGiFa);*Yr9lKzCip`#2MpYr#jr$zz$(+lr^Y~eFE`t
zduNDeW%?V5qsql~*jy}=&jpGx?;&r>vcyAegFvb&82zTsNHTDOz?~2bsG4=r at 5|QI
z at 5S2KevYLRL8VwU_^`x<tyqQGPi03x?4o|9@$0Q7t%0(#1P+9r6ZX*Ur}9D{vKjQu
zkvl%D+C(suD)j1- at PR>ThrH&2r0erNNxc)sl-xufsTnPSMhC5=GI-N704PS%j{cfR
zOWUZic8vcEWxU){QPb^H3ZQ`sq5yYxPQWkkRo^pj19B%)24R7$09iqVSx5mPb#h11
z80>ghk=RK$Y*+8oo(&W~``S(><zpUTcMbYowSZ)Kxf9=HMPYcwwBRT}@?l-^FhP8$
z<{{tFAJY>J1e7ujIc(UAg%*ec;3PY->{-2=#~t}t#__P1khziAd;lbkO_zHYP5NS(
zBlZ%2{>rtQJeo6d$B%@|yj1ksXuuuoZGraRFG+OzP}`l$4Nqqm8ZamP==)nrn70K0
znkFuBZOYc6dj@?<go;;?sN$J#4ImKntLBn4 at VE;MMf*jfOCQj*=!s<$h46HD*ch0#
z at -(I?DsGuWftNzJ#~yQP^B^X(&cTd%@>#<2Gs`><u;k{|8KI?Z2L`&gqeIvJ*J`&A
zGXHX)j+Juk8t<J9;2;?SVK7r^K;ki=Plov!D_x?N67sVd&A6JoQNJD@!#7P$A}dO=
zPHU!7TfKyzD{k)?N6w@#p-X(``uk54zf at PbC5e~xqKecnCdwT9>dHg>WS;P^V<aW-
zj`z?=$;$|vj(Hy#zzp)PdrtatxS$RHHri177WB=ldQQ&$-*tZbhoroJ8l1dsYqxX%
zZ$l$B5$_%PwhvrGEFd%hUHIG2uYj(l(er=ati1HUa+!s$3gctncDRePXrNcQD$-xK
z+SMU2ZJ90VSVdWMnhT0*lhwBy2c~~*GvI7iu47z35g7Jf7yx6i$(dA~b*Ulog$iFq
z$>DxK4Dq}5P?ArU50a4%mS->}l^>&^=(;jqXit;5BqQ!<gW_8(S4rzx(Js<#eH4=m
z^0USOkS(VYW0y!n)Zy(x#LE)J&&FPP^2~fl&#`Do^F#@`3srO1jOE>Z(Z0t6yA*py
zzF>1?-NMKNVd2$uW2equOb1e6J=hbXfbqWAO5L)vG8B(40#VT?g=Xypa<?gOs-<Ak
z_KN!n;Mz)4aIS$ia(k>HKv69Z at xR3~x#73f=fpQaRyLKImf9A69?&<3-u)ZiIdC>t
zT>uOe3es0l7o0yg1XsZ2kUTSS40MySMg6umy66KCTRV&>1umc0wy+baZNOD5?KD3A
z&*e1#maSK=OI%Cz1^U2-+Qs-CLLhvWmZ;IY1iWuYQ{1TR#y8+W)1~k*C$C}UPsyX2
z(IKOMzNoM6tNw#P3uZU?Ih(sDD;QsP9`UneGt7k_Gl4tBLNDiOKoHE~a<t6rmADVf
z^Sm8K>RR3QDw<X2Y&3%}Gc9rwr_GKHMN-!*p?9=a_DHo;r?@aKeF(%K(EPNNDs4xz
z@;pQm3tfwjZ2HzzpU9jkPrAwHpnIQ^gfXjYJI55%j$%;Pi|VpA)Gv2I^Rrshp|-hA
z*7C1n#rFhxx}esIQ+fA4bxCx!Kk?`p7NYsEa#qnvEWw2pVLPZ3rZ6z7%s6z;C`^|9
zZ+?Ya^U&(W0f0y*xJg%<3U|O%%8A%j|6HIwhiH6oLG}9J`T8)Z>|-wGIo|kSGD*+!
z?mt(;k-G at ol_`1)R~;skyS;&?b_g&u!=kjAhMb9MvK;DVt96JFeIIlETw(_K5Li~t
zF#aK`b+kJR#JoCuJv|B(Ma2~!FAN;)HW{sQQf-AjKaw+zyy5d-Pyr7E++t;Wx)UTq
zU+yDZ&8OiM$Dzm=9UU9;m&dKsiB#M at ehL`OfLIndJV`4C5MB*sonIQv3-V1-@`|qM
zvTu2EWcAY%^F!N1Ej#F8Ff5Fj^+YKN-8z2l%SvOci!x>$DwuJ;Fm}Tq81hZ|C2--B
z&=OW--Mh2(l3iGZK7kWEm6A2PJKS=vXVE7p>N4AybdgwA>+f14a<ZAMy6x}$^-D`1
zr_N>w8ZdDNut2zxE`r?vO;+{WXPUQ+lKUZka7jWRBcy3{mt%mW1OoWxzl`Bho%m3Y
zKC7qAP5_MU^<xdILK5VcFChf?qGGB-wqWuDc at U*t_h-u1uiXs#X_rrcH9}fK!NLjM
zWYi|7qb-`D-;qF`6aWflo{$(3&BXFFK~l4V0+4fuE3$Xn`uF;ZW}K_UAU{4#^IuN@
zCIL?nRQi%<-1z7U5g236RC*I%S}xqrG;*<R%^;`p?1#6A at 4RvdovsO~c!)i}J*={}
ziz|Mpy!_n0W^X^}1(p at f&KG8IE{=ucUg)SkZ=PAqLCA!iMI5kAo8`X#q-orYO1&Y5
zc*HSn1A>0Z4!fQ|MNqagm7z9<L_&p6Qk!f}-_H^SG$c3FJ;S0hJ3<v+C4K?}{3Pi`
z6al}tI^WQ|$oc0m8ag+xCwd&pQD?Yeik4!Hlt$SA?}s_lkg9~1I57Q9KUJmvfT&no
z>|YL~L~Pn}-D?{sL7v!-#nbr*z<0DzC+lYPJ*^ACAWR2%g%KPdEuXTtU(y<ve#D3a
zbcm)_9!{KlglyNx+-45cOl)EUa*A9dr?}Wt(Q3olo_?F*%|NTsMU1T^)afCbkI+FZ
zAWwjIPg}w2wxwoVpJ)iYEH<~BvhwaxcGAUIy^hom3Sim at mOB%dE9>qD?CzDc)WnhZ
zumX*<`l}s=t2nTK8xK@*&)zK+g3_19$)4J0Vptz03~-*)ihA%pE*dMbdV##b_)3wJ
z-NUk*y0 at v6<AA!G6~s4XLTyx^2?=HEL=*2q+{Kh0w at u7wynFTi+0E>o@#y%K@}+N8
z#puQpVUA7Q5m5Q7WxD}v`9F0=U~Gz|-siOq4Zl!(R0l4pmc+wD;mNE-f?LYyMtr={
zmuNnp{^uI(@9vb*{0poEcoZpF_VL>@UC%LF-Mh9i_M>;*XRUf`kV-Q(HqYeRD7B5^
zbV9?SS_dhvbIfhdYouL*{ad+RWWa<P!y~!RyX34%Q%xn+ONRBR^AgEuylf3|B2e)s
zNppa5U1s`ttx?l^ZK>v{Y8InqsusNg&1fUy+K6r*sCvxz4h;bR$$*@`44E>@`e!pt
z-;Vg~zGkEM!;*0rurQ+rvMN9ex`r{jBU?o0&xGdgm7 at SvK8%Xns;W6syMF=t&(=C>
zHX0_GG15B$EL7<)WCxaid!t5mp5|JG-g+;cFt;*AvW~_E`6;Jrk+|kK4wWMTLAKjU
zD}7@@>g9i`$_UDGzmrz)hqd^7d#^N_$KM-U`{~#)MBu3zOXA+V^PQcd*s~*TvvA%I
zT$tbq(nfYvy0xu>eDW084zD2m4zOQyPvFq!-}$zCR{!kBZtXn-1{_dElN*Jp_i7q~
z2l1_ZA^UUaT#GG(1;yu<h+Pcr?<saIfPRbp9&Py)rS-zM8}SPH*PE|f+lgjAq1yfL
zo*J^ee}oTdhqPgNQxqYitY!$h+Z1|qA$!~*w8L#^vw(- at 2Sf77GdxkE5{T}=Jp5#9
zJy_(mQX!OULvlwz$?D5k?RRrmwYvuzrc-Aqx6<-_Qa7S~B^z+(B^37jWdPtYGaTVU
zTn}Nk*%mHLLB9>7z2A5wnFW>Lc}p#LN1L`AATvR>(c=-u%w>A{0lK5H{Y<emwxi%7
zWJ%BmWbe&lJc$5w*B96EmKE-a0fY?J{z53Jt_Walm at XLM65x?`e-4Byor}d}5iTCc
zjQvymqB}Zb!k$<zmZq?b!j9RzE(?p9sgqDxhQc@{o~@><<F^gSwbrS%Zy+Xe8|9Ed
z6T29ZN^!8|*D}#c#OG=c;EWjYR|2+4L+#G_?-pThjV>nO4t~L0IUvi2p7<o6_{?#k
zJ at w{I8&SpG_AjL;wbDM9+bS*W&X7q703BcZ_lISZb&UzfX^&RiR_oT^n<mNU5*zDo
zy<5l=bew6hj6<>Rfay9iz+rF3e9lB+Eo8>GPT9ZB!Jn!t_U88<LSS}3MtW*{Pumbk
zFFLGb)iL1iO7u<(c_)NB#IRnO7jJ`OT8;|OVQNhPRCn)52%|DHd&##s_c|CoXL!Sa
zLReqZ4_&=Z;q>&Pt($^QXd>!%=djmz{@twb$t7j<>Gk%+w9T7djt;}O<t(R77<AX5
z7NO$R8kBZ#r-JgJJal}-^{2_s?2g_^RNL+~Mla?<i%=UgxR}ZLYpUZByyr@~!ma(l
zEoJ51#mSWtm!tQP*}+9;Z<pmKmK;udKI2_o<RH!&!Jt-mx7dhB2HFcxycqc1Xv>Ej
zWUdYCu)NB<rayKfqn07wCIjyly=(o~R}9YPxiH1Wd;iSGfSGG>i7V}tr>0%*A?tUN
ziWa at cPc&-<5Kz(tcGE=tZ&|0Ja$whfx0xJIoTy0++G&k%2dP<|t56}~V_)POT<tY!
zB_-=dZ$L|=a`@8iC`8DuJpK?%JCgWGyqR^JCd at cf_u3|w;XioqJ;ca%Lz}mGMtuSH
z8uqByY4sgYD7bLUuMJjJFF#~rCTR6bF`FxQQu%==(%|~H{#(~kEczAw0_iF6OO%(K
zm_E6<F at PUQd@`Y!>C4zh>teKR#?qq+=Lp}YJdFMFgwKdvN{99ongo6chUKgKAA#to
zpZmB$CM`5P#(Fq51(Jx8y2Zl0MNM2Xbboi=-6+@;!0syF#yO!Hc^?Pl`y?i-bQx<;
zrtGUQpie=5IAfKv6=-_A?HO}hJIuTLR~{jN7$RhqBPUOX^{^et)yFy8P$z4IM<o3k
zV?vH%Jwthk`cAZOiDw at poh&o*rgdpX at 1*(Y2<!#J$wM{bsb1f9acX6{zoAMj6u9mh
zlxL&!h9VHvo$}Wk#K$a)))VB`eyqb9%a>*GvYXkosqU<`9EZlUf?&h4iPT-H at V}cQ
zO5Hu9n<`7W9>T(kT7IA8U<8$eHv1G1m5WrH4?52<9UbuDEEuQks2ug_unJZz{AQ83
zBWvGDM+kuPGFYkw7Hdfat4?MZAnT03d@=UWQcBFK!_D6{{~53cj?}U1m%~C=9p>Wx
zM3n3Wom#sbfB2ut$r)I4Rzuhc;0-&a_L@%>e2dM at HeBo3o!MPfph8<?q9)_+V#H>%
z;2PncW!mU!&}h>7d}r#yF2{7}5b{QPcoV1>Ko at tgz~!WF^5z=j^beXvT~*wnPlV4u
ziYp8G+ahJ68h^CR+(&+MR3-r+L3(TT)Y{*tP3W+I(hGI at Z`P{-aSwuQ?33LEB7E)N
zzQPeZK8bIFdwq72Wk`n2P!fv0(&g(@SaQDs*;!UI>F^Fvml&#@&X1_{6fTdPIv0Pz
z(j2O0i*|P)&$Ah6$_>h(#4af9fI&7GR{Stuw at 2zKJ<6Qw8k+ at OjQ<<SYF6Y5r6^xK
z$%5d0o^WML8t3qEt(WTV6ubto*2-t*x)MF>IDS3i%@tHI+O%kbSo)?XPbgCK9M79j
z-2h}+`qK-lD2>5Arnl^!+CcUwb at a{^JCPjBEbK0O1!uj?otTMBmCV^CwLxxu$84MN
z-w$Azvx3iY=n%G%(3U555?80<%e#mGkYrR+jK5WWGM#<Ct)+y0VyV~4b~u%pI_VOj
zy&PC^K4RrV at TttUrMz&23kOmc`=`f}Ytan`Np0$5<o6y)ubt5U$J79_DznNSo|KHm
z>{=Q at F(4H~Jwa7+f8Gkf#YNV*@k1xTq$sg!sz<S!3NW8<xIjMVVEp{s46L&6VOwVU
zeuxi{A at uy(XN)U9%Tr!0KWWU_694D0!(M;-WbA%9A<AlYE}<s<o4EW1DkWnelm&`~
zGkT+)CcRIDDlWR0d0LZrV=JLlduD{`<CP-v3t{*4ubI1xjP2+cRaN|csr<|W at m;{N
z6q_^xCB at ***@ysH6<ZH3o6ASgr1%@Q0M#yK5ure*r6^7t!U at v0Q_c*`(XYkbF5H;
z at 6oRO!5uM0e=zyu)xo&^QsT&FDY(hGer at n25Sk8HOGQ7b)<3CV+x<|k4ELb1hs{&l
z{7=zUEw!BX3^sC0I6rA8A;7gr7(i*7uFn<*WB7S~gR+fGXg8H`;z at rui|aw;-IHAO
zyKB7Qa96GW!M^Uv^2dc=M?X?f6mgGANrz{$990JfcdH(}*fp%wg(_af?DT?*&nxf9
z_UX|quNmv03!h?Nvr(VAB$GCOAgKM?PMc3&@>$)v+Nm)uPZ&8XTavW~tH`=I=(9Xc
z%}nf;QB4DYEYtlEKAx0NkX>PqngowjBNm56{(mUPquh=1ICe=<&9bOv|ErB&TSAMR
z-Cqc|2MU1Kf+OL-N^Tautn1I4fG8)~*q at H(+fyO{Z%ij;tB?KGtiZIWV;rMKOS=B@
zrhCknWy1r%AvHFA06sw<03gsMZi&3H<{W;yPnH2?dh#|gBEaQ_=YI$N5E0!zil=bd
zM9l{2C$%2a=B&Jw<iGvtZQdJ5 at YBJFTg*7`u_JvXfuljE+hlR=^5^JJe9QxFhv|B+
zx_|R_z#d)ZCW)3syBoOTM}PJccuNqg=P(^(<U%}|OAv03eJHueUWa}JDlgMq$+x%W
z`@54u5aBOu*t5q24yzZ25(L04?F14p)5za-XE8f(pS<*@y}g-KRXL;>?ki0?Hqp6V
zVw#gb`^xkL6_~pPGva}e-d?knEs+-Vff}R8euFYBOmg_ERfWwY(3=^+KIo_M?Hh!h
zbBDsyN)`eUT@@x*XdA-hK4Ze4z~cS4F>!n!oWYB96&J*bD`?WCAjRI(;B&@8FzxE+
z7kv2{48yAo+^Zdv^x!#}8-z*2Y{R45!|ObTzDV$+nVNm at cK0NGc5(ZmnpYE$gZTlV
zS|{nIYZt$ht}G4?JDBKB*6pp?Nv<p!BL;e~tR`!2uN;+}Ouq^Pw6XQsjQwpvecu;g
z6gL%~HiCN!s|wHnfx71V*^|GeVbpli>q=dJY~Q7&9<y)hTQR>oihgEu`tnwenBd#G
zkGGxp8r!MOQ#fg2ivfsRLOXw{ebcZNAaY9&-K^o<-1MdS`^YV65oQfhlpZHuM}-aQ
z+-(x42l>e7MOFIIv89U at AXwy<bI2YaZ29ft18o&m3@;3cu1ZR;d}R;wBYl_{pa=^*
zEZ at m&8NuH9hi1~gI6e;R`6WyPAGsn5Myd-;zG3+#OWR8C2H7Zq4%Zp^Og1i7CDQ55
zUmGw<c5ftB9!>^Vh<m+)6q7)UCqkcYobDV!vrpy+$sfD~*1!!FDjKa7 at Ruy<>pG at P
zlB36J89z38HNeVg37UBn at GCo1uXVi@{QXVxk+o^$J!45>G4~xGr}!N(#@fC#=)nQH
zopui|0Ip!#^EfcKY;#uNty1 at U#EW at Y-a6iuK{6UQWd*O<R(f8T9MUtk`9d1ToDzZU
zIq8}xjr9kgZ(Cxxy9R#chesu}1>ty=s<$$i*t=_wfGh;v&kMf}nB>1&{-r|LbWqx$
z`I)~~=ojS=3^3JRr}%5hl6sKW?2j-!k*8)&cJsj7*QEEBe at kE3Q6A^%9y(VEHA-&l
zG#&-EYJ{l at j<a7_(FVrp>8(zT-WbTDy*hYjK=LRXRlfT0M{N1saBI?5A%DXEw#`(;
z8-%U*dm$1w?k%*pLm^VSh>sh**=2$M89S+K^<kLC at X%q6fKqJN+yk?3v{UfMvjM at p
z;eb7k2~nwXXl-hP7y_RDo&8a92l7DE<(OOT*m%c11vo8S9nef4Tv#D~Yix$C!-sCg
zEQQy0TeLK0FN<2!%VzEoCspVr*DaBTRRAjcC=l;ORos-8Y?jPc*DzmJGVs==E|^}l
zpCMLBX~r-o?Co;pfSJaObe<1IscZ|cr}+jlYtv^{c1=C+EQb|8vLJE9c=J`mKUY3E
zbmR~7R(?sP%97bCy!oJ2^~1xw*qtx~0UwH9a_+;1<+erRD~z2Ftv0RRNLRjbihZxY
zibDzu=?{VJRZI~s0xmzm^xWLxJ*L^YwunTrx4z at W@+zWEh@(=W!p)k(z at f#zsPI06
zD at 9ffWcf=hY4fsQf8lkUeykLb6w_%FBf)Sqr5S|249L2-ii63(=epQ|^wHj9+pryP
z(<_<BqpcES4>yDhrZ-1sB}|4x+C9eXF`EhGp32?+=Y>wqqG2G at fOtu_W7$=AP#ygG
zV6yn0<vQMd<8<JQJ{5a*1vpQg1{$xm+hZ?S1BEcE0XVkBUcYPEnizw<izfjtL=J48
zcJ`+T>8`PqmO4>=7qoV%U}&8^5NPp59OdcUr#ZsatmVIyTuA at 2^au!s#UIeH#t`Sm
zLUSie%yc6~$ePStfWNnY=<u~KtD(fl!KcyuiEC at 1g^BfwB2LU~S1aH!A8X!*?*$+&
z9NeVaoCkDlvo{~@&r;r+>vnF)0H=SMGWs#L7>JK>@cJ at _stZ;I`iTUnJOIo2{X$%Q
zqxLSQ=Ts)5VM%0o{Ri>w>pW3gMqG>HhH6<h-U5M7%(}_q&=oh`FNtu+*ToPVeE{t8
zW=7f)tVGo%cft$9AELr?1LtOVwte#G+jf9u at IT9KbsF2>97j_`+BOmTKAX5`TIa+k
zY#nwz5cjx0k)H5SSgB49agq3#Pah{obBgc6T;$C6$k_0@`!Qj6)nL=!?WU{RaB8B2
zGGuk<Xn*$wBS*l{!b#;>47hW4lEZqEjNSqH6wCJ-EuYx>zzNU87DEsZVXj|XNk_49
z1#5ed_=t0Ks%68)PCo9}AVkhuP^o at xW0}Rsu=Z<8b-YMPg(p;aeOMtB6M1lxSGq=t
zqy$6g!m0;5wKst7GtIE{GH|;-mZcasNK;zi%dQ9bkf+zZ<{7nKA63EQH56_^RHtKu
z&SM_r72#2b_Q!tUMA0r+bAV9{!kWb$)f5wrk0uL?V=r9&JqOXq2n85?T~N%?rz;Ng
z at m6I)3FG_yj)nsFYez&tyJ=RiKe*FRfSb?V+86+v+&Vtk^6vd75&SFN_=H*fh8H&b
z{SxE!p%&S1g{k;WrCC<CBUW{xcD5AX(gGw2=T}l3eGJoy+p?vATbtu+DSoa(@f=Q$
zpW=&CXJ&(sn8GckCN5KQioNP<1aqSJ{eaEhZgW>EYkgJd;VGxeI%XEQ`K<Ph#tvNc
z;E*fel><miJvqa$QE2%^`AK_TiTF;H=Lx5PHE6)fcPi8!dBx(RXVLs-(p=rLaV*D1
zId7`K4gRcwE_42zGy1|cG2^OJS}SPN-!!z)7rL`s5^Dhc*eHIc>RH`=0ktZ`@BK6W
z$-yDD=N1Cb$eJ_)_c0)WtzB%>3Gu3`Bgq$6MfYC~8~+rr2`KYE_WY<rK?G59qlqov
z4}mtWCxve&NuGQhMShi?>gnGWh==d`^xafeMsV&o_&UUYI at kq&?5nV+*dbXt4CnPH
zDo+Loo#lQzfs{$WLNQ#DO5gCs*(Z8ElCX$NXw%Oc at lialwv5MQ0i(6(e at Pq7F;vmo
zNkn9O at m+h>La|XKb4;OiT_bDO_OHN8bju~|EUroRSh%t7{@+fMw>!vf>jXftr%WcQ
zp3L=jdjo0SMg)M_izn=Qd#ZU(|D0kouhM4 at aF$4%v_E_8;OoUZ0~3+8&c&5RlP}96
zr6fxLVm2$*c#W_R#7<2;{vjR9K<pvJp|cS at Rj2X}D{ZZ`V<noEU){IrbAbz!%DD>Y
zWucRFt($^mIUCQtWNDakOgQ542s=Vl9nWWe0&TBT1#0KzLl_XGv-KuyvRH-!P&N`Y
z;kL{e#MSr_ZfW+6u}vv$kFW#v(8$?(&DC^;*%uhTzIzpBz{w4arx3Qt5+DE`ydKmk
zgw9BNclC at xWgJ0&qo at y99%GNkA5hsWb1%nxA4(q0p2{kH6=S4sDqdDY;k$^iCD-Zd
zaCF<{_+3OxsS|1o+|LB4MWaV$bH4F<;Q^DR(b at uF?}shNZ>U&vxC4^!%!72c(FV&s
zjKhLRsF1&r9|$4#=Pl>r|L_b`Ufb%}uoR2T3{!lL at 4dR3acS-+7ra%TRbJm&5j#k%
z$A}2|PI$U3RTDp2th at 8bzGkPlG!(`<F5EU%2j$y}M>pl;&-aJZqu2QBi~8o57<o%G
z=}M1*>?}g?>V}>$$xA{^UN6>=Q<1NXwqyX?C_HzWFt7?h>@mvoVfAZ2Y8gYs1Vpmt
z{^+tn9xUan#9QOvYa))USp6Q*@~Y#Fs8QMq6~CrV>T2>~&FuruDoD|ZB)+Jmos_5v
zs at D^+l%Z at F$G+2;PNRXf6U=&&abaSnaBM0r6<-4ot!L}!2oIMpjMna1r#t>Ki)g>v
zbnH=l*JnH9u<r_Q-S}^;en4;uV_|6(Eyd77{yxAv;qU%Y8*tZN<TZu02rzksiXN?7
zbV57bRHEy80(pV_*VN0?<z}jvHD^}cgK~AhQi%_}mg2b}FX_sxoHRd+`R=ymRH22w
z7OD0xL%%}@ym=<-Kdc+l{mU|TAnR at q^8 at i^%+A%|f`iGJPMcr&ABlSp!ygD?#>^lQ
z_QtB&!oCVe<Ju!}TSiX{1Ji8ct>@1i^Nrsa>(9EPzGgY*HT(;DLcFfld<Sc9?GF%6
zQwI6f@{Uo0&Sv2hm*`!$F?MgfiPY8Y;towjKwNsFut1LL$fukJfbP5j4K0$z8_0JC
z%KM$GoXDXA3j^Rqlb^+P8{u5ga at znpV$J;nEuq>N8O})|Rv51U`*Qj+L04+22ePEX
z4O9=_988Xo2HaRGTc1|9Tp+rSwOZLD87$=2+_F)<-ZR_|e@}=3W;CH48AD!)n#UtI
zZ2fA5W63bQ`CABAyJ8w2E#!M~^Nv=>7X}h_RRY>3ipW6twMxK6Kj!*?O$jBk<$q~X
zZ5Efye|C27eQGf=B-4dWSx(G=zq5j|22`fPAO0&MgsEPx9a*56IcYaidkKHAH338&
z42WZ<GbJ;U!>A;}>}c56C4+k!k-&0d!AJ*=2)LR2YKl#SEf~cx?4Q<`ZOyvg!_L<g
zL<^;s^9t9-?^UyTEG6)_4DrjPIV&@VfMxL^xCIE*VuhZM5?q#L1iz${bg6hs5)&Jw
zzX}T<q{hM4ZVXh~cC0X*=c at we$)gIT;_hZ?3jBPxS^i*U{JYVN5#s=iOgEBR2Hlif
zH??B(loAoXpWaaQ3^@M*`7x)e<-Xfh at t=ka=IZSk$7ibXR16Ay8Ivh4VuVmEXBXbN
z at I7zMw{Wq5T3%8=4Ls|h1w1h5yfBc3LrI`5wg0KG`Jv`^2QG*P%PsF5u-tmjFB9$0
z_IX+q7-UCxVwvXaD@&<Dn9Xhv%nD`tdM6HG6kjR&0N7{>(WdRD<EPpT$be*Gc6#8Y
zcMrJK6Ekl%@L6+(_A+2|WDrI0`Ba;V8rQ<r><)Jl%zw4)isa?->Xow*FpfsQWFS<F
z@(ZANanQM^DsRx}d`+PQao at SW1*gf@$jw=tWtBaYD!HseZCCXTj4klS%C?66frM4i
zY~a5)Wnn?GwQHx_7hcEF*>(P70Z%HFfwhwh2Ku(k|9TX^&^_ila=KcgviXyOm21=s
zHt(tllK7Vvi-5+tMAr}QuFH)d)#ZH%TU(gbE}X0G7(*ufLQ~IYiMUx;q74U4#u`W~
zYA31I|2F4t at 2wC5$($U4Q!W)>vBVmxri*JyF|`L{c!5kf&`hcd$+h1nFUtfdC6hlY
zx>6z_4~Rt`=b}KSN(%p-h<<6Xhz&tU-5i;5IcXuJ^C9BtfufiCJztUx{pAc`0 at 0HZ
z?Zdb1!rhA3`)W{oB-Ufu_58&hAXOj#k<jCf0RtDizlJ40CW@<w at 025V0WB5S$}WTG
zTn=HN3ZcJ>qHXpnFZU88DmX9;G=3QBmWfrH;$ef?KK2x$AB#8rVMPkboi5A`4s)k$
ziQ2XBGNnF=xy`XUpEok&(U5g=U);%XHK;SN)C35x8g66AT^{L{ul`qctN1`&xr+WF
ziUtXQh5^crICGu8p5?~cO;T6)i#tfdvyvzpE?|PQPKH5t+N}Tfw*{Q|;(Wi_xHWX^
zY{%gOM8DCJy5<J$+9nbExojW7;*Yo<Opx(v{l<U_T8D?`1u5?8c*Gy56Y_<9 at iq(V
z>s~|ZkgO0EUv-g16V70i8(r}4Z8`E&-D2VQQzJF64l?)YTy+0hd-On)I5~_M23k at 3
zrX1ILLlMuaOaiv4%vNq!sH#RQE4VM0vn#}0uhWPtL}Q(Nv1!(P4!-(eC4W at vTHK64
zro8&v_U$=ucpd+BoeHV>_8GJXnt%UJ*;~6RG}a5)qUu`)KC5~Z8&2vK4$Ieg#C6i+
zYspjM0?sfZb;Vo<E>;d?vB4EKjZKOQ!rEY$SSk$B_#8>LY7{Y~Yn$$A5{X-o2=laW
ze2;9n)U_)U9B|XO%!_!nIZNg>+w&^=;YB|Znzm*^F!YiZ*JTmTrFIbpE#l8j&dNSn
z4wtW@^Aa*u*BiYpj^_8VaZS`Ym~L%W`{%3w{PM)yaB?kv)2YX8`?CHMldvbN at mjsb
zx;;i8^uEj2-#j at roh_Zl%uM-gzqB2EJSxhVq(X&wL_G>}eNdg<_xerY-TwyN4K}Gq
z&mL-v+p39cB;Al>RYX=D`6(vuy7L)A&@)Sh(%q8#by<i*hV-Ia4eR3OYxCuzANNGe
z7k1a~WI|UXYyQ2p2!SbC;PDT8+Ct{4sG;o9T;<`~vH^LGlrVWTPaZ+im{W^O9yGmM
z4-(kBi&kpd%=`IKzcYe9B1TIjp=12V6CxDf!}1GB2p;#!78A9F?fu+~8TdHnkSc9U
z%_XT88&HmQn7cKgiS-P7mTr$h>5Z at 7EYpmdr_hcLT!H_Gp^Ez28Ed=94E_*^`s>qm
zZgk5b`!)DQsc`IRyUc0p<cJ(q$srM_wKB#GVvOZJQ`lzH+fsLwPV))iAz at R<V`9#O
zK6fZ`5Sd-I)~eB7 at n=M{a^}Qwp;`~$!@v&pT)0?SBzaGgRol$M at 3!+NrV`On!8Ctp
z=G$PBB7|Cgin;8$aI?Ga^Bs%Ip}^f;`LJ7PW}q0?|7)uDd7L>P#XY{Zt&GLhK?`L^
zXxA5T_UE5*GB0^5{+$+86k)v^f73PS>%MW7?G092GwBYQ)>e at E205gKgFeO0Mp4Re
zS(Q+c1fQjg0^R8wWiOJvv+{3I%Cl4#)RgY|UuLRXL8dvAkE_cso{6VN2KPuk0+clz
z-7}ME{K*DGJ8JgMB<o3W!@);&C*I{-7#BIV&s}$PV;bxWUczM|@-w>=v41aIl9Lp2
z|Lz4!cXo611ogf8<#l0|Pw>wUf91D7 at ***@0dKy1DAD~HYe<F8OvB%I
z4H4fC^bz_O-m=tQYce?3fL;dC?AOi;w%s{m5=>%r_cp787?-bSt3K!1piB5q73=xU
z?8~1TH6Aq2p**$7r6}GK8TZET-HgyTGR5|yl#v#Q-#^}rSl6=Q&&JECrv`T%v@%YK
z`GL=$@3p-tzF1j48SpF+v=u4QtEN74BPD*h_KaVO{DS|hy=^h*S+vL2>p?s#k4ZOa
z`sSDeb-z~sB!2`Lj{o`zoAehNz#n^-crES;=8fM``>)XNjJJyB>P8pS0*8E;-H4AN
zf%|B0Bhney27jcNc$jr7a<6+UXZ^dMqdxt9#{-q=9O$9^X^lCM_2RupSw|_mW;O1p
zZ~w0BTi`mxwM^pgDEaT1*MG{Fk(rAtoF^UE)zogU?7Z8G+?8x^xOl>DpWK7_D}9Jx
zsl3qo)x8LoDJ@&_NAQCzi=Uv0(KEmG{;E5Yi(7%UVaStB^{Gjs;kXO1H^I2yf^831
z7N)jlcu#Jl+oBbrPPBzzZlKQ7mk-vB4pu$$$S#cCmnAQuypiD?JB2l^^j&w$3#OlK
z?%tVo>o7 at 4bgO<6zdu0!Jbr)lfpgjNh4Vuh7d=aYGM!!Nmp|n`YrEc4{hJ(a!tblb
z*Zp+qHBEe#sQF`!@yFTrlzx9{iq;^`<8S}Po0k at X-x~dmktV%WJyj4RIjt9?b8-Sf
z8?uqaWeRciELCx-dxe6C4~@mt%|v*-UuzieAN`o at 8%Bz*x4EdZ3L5I>lL|F3;_}{k
ztEh^h!<yK3^lY3(g$&$Q*TDxBf9Aq;?{5C$;OR`?(wj97o{J9(pjSQ5l*fE<0+kB(
z9%DNlgpc}rx56%|kn9^8tWs<pC9;;g4L&X!r%3|d=V1j&nkM85@)e6<He_|HoUoW7
z@}HoMm%(DQbw}Yd2Y#tUPguV8sM%}eKOo=^-VL)YCrlx4$UG5zbxe;c5G3e~)9*AX
z7R;~SoK2C(P;qI*5y8 at ***@sHR0njthJ|B at wY-_@&>?a*i0iqu$GLA%<nD5A9u{cMPa
zboLz_%O+mgt!6IPneyvKG|TP(#b at 0LGA+Wq*?{&xeH&x-I`>XX?r%W^OCx&@_|ub1
zp7IHAi4#G3GZ=5yI+`6dpDjxS-})gqLx9+uxU|=G#T#Aky_FG^@dgKpe<uV7d88}C
zrmbuM6H%YolbLbn at ***@JkfdIG&_QC(hs3uYE6S){(6pG+-Q-5Ct+(SXz0<VZmYPai
znw7EZLU)gXK?6u>pt#8*8iaFg_2%j_V}+b0_n7Pgixic3v`-wfHI!^CURe1_`>QnB
zTUmH>AGfs7?R<B1W>IVKZ~NOshc?ybn*)ZKCl~uYePwZ7%ByC+TZ`XJL}%BZ3mI3~
z;r8!MeDCBt<Z^B|{|H!et6jlcUEqnS at F8>n|E#xl7FCgZt7M3B-j+0bT at 5X`b#r2`
zb5Ka-!Y6dCxFna1n7Kl36|2G7UK8xuOwSrs=}}EjG)>(RN5HjshL*I}odP+<(Y_j^
zqkAL0{vUg99+h<d{f{@(lr!%Zr)gTuZOSQgPb>`=n5NQl%?yd$niNSBP00lXoEc}b
zCY4-Jae*oKJ;5bcYAP2{DA&Y=N&!WY1OeIf$NPIepWpZ2-~Yck=XDN;b9f!jdA{!J
z-p9R<$Gx`_ at pD$a*rK;$$ZgGc8lgZe84t_bBy(cpH#TGV;mK6iz_!~(V0(X=IyC%D
zpRq-Jt~8V{w<VzuD~txxiXt}O4yJu#d>b0Q65H0Zb#o8|8fCR-ELjOl)@pYBsv8#n
zc+-~Zc!9{n6C}_tcQnVQuB&}99;JBt55_P3z at pFDD|Yd-A7NOi5OdFXfCY)U*z!ik
zWNWI|oi4y~L@=Ip6CG3wRbBBF1_(8(Po=oqTb#Pdz)crv&z~!=QqDSb#{9?-Niim@
zN00y!a?9nyw7bC&iY-4UOvm}{`t(zRw6U9RA{vudliKr+f)TUClky45hX9p0m?&RY
z==D~VinnQQS?YF%4~N^4anf<>p>3S+BVt113pdxq#o|+N(wb+;#JqekvJ5xao~IyP
zN6w_CPJOzEAjr at ***@HH$jNaK%N!!`>z^1g%pC+gHXLpp2``RvAI`j+uA>03?Dv*8pX
zE?05t{-d;#go2Kh6v5S}q}o;L=?Y%z={ni(oOM?1?#ojpZM0Ns4}y{vxa#padRh(K
zJc>P4#esu<;`{<(v2wLd;xY3M7umYmauv*|4{R~*_!hmwFpc`q{w9XvxCo6fex*6(
zg|oZP)!c;{)|2K-&z}mLOTLb4TM3v}oa{|jh1{RT1$>^HQi~qTcGrnT4H7i-dK%x`
zXikinKLP#hi+j_ax0Hv&e(h^a6tBvf^HSWvG0VKP_%$9-57VZu!RSL-T|m%4Tj4dH
z8RtxI&nDL+W^Fc9uR&Ebf=|q>YF-w8QH7Zhwf5GX7wY1nhrWaujSQ4bzF$8B<APrb
zu3+gC!JNBfUPTLQnBuZ7D#yqCsGEYnPQdDuMXBRtJ6GZ(bp42p;wS!9gy?(<3tRhq
z+_!nMn2q(@!q+RQYab7P`mUmq7c_`9N-#8hzka<E%s>c!TS;N}1dsrt2oHs4vD>j|
z`L1n`cm2RgLw*F6ySN1fPX4xeJti8w_qgh%2bW-;24H)S`5Jy;j)<--WA7Ng<Qx>e
zjM-Utnp>vs!J8MTdMD%i0&PgF1z8K#-bnsSE1DF{CC3g%O!vzY4TWf;oL$9?!#?S^
zTcyMw8D)u$a_7G)NZk{H{6fEeQ}bJyuKm?EE6bN9CqxaIrI$jB8#LB-)!gqKfZ0N6
zd2G}LW#8 at nV_us>cgPlv=ltJGUY<1eTnaGa1O(52{M(lPhP!;ryI9KWG%ed40@`ER
zD5W{}a6~}-Tx3<YW?RJ`fyeaXykR^)E}%4OSD0ZL$;*5B2kKDy7!Wql;uxMX0_}Fw
zUt_lMp11UxISs5&H4gX>arLLFj;G^(_2B(fgR<F`g}a#{^iws3l7*Gx^;xTig=%P6
z6*eOg{(j)G-Vh+yannjuV&G$(o3H11Q&s1=SPj;Ntv}>YKK#_BG>`Y}kbTqfdyjE|
z;%}qZ?cEb69<- at YkrofS*9INmPeh5HMyVFgVRNVGHbgTA<(pnZ6<81v2sb-KDQ(yT
zlBfCC)y3Q-+N|hQ<vR?X&eLZdoffzmx)aV%m4FA55nb~^gRzO9f)2;`pFKvt)=}5p
z_fFTDl~56!l}34Y2qeLd>&F{#5VJqi?*Ut;xUMkdd3e`MFlcUS@|^6>Rl)m030t*r
zNnb&ot at UZhd>fEWi)|{7ckLLnK0CS-M$3u+x(rk6LHDa<$b0#lR7?5?nBeKq4~)js
z5mi*KF`ep78QjzO3LALhf-w|ycDeTbv`&EMw><g9*9UNYb}D>wg5GcdVC?8LPgSXf
zf^bxjk}0mgL#Uzi0Klf&6cNI at UCf&Phu^*JY|f(+%W9okPo7<zdWPISj4{>KQC<%3
z=t3_LGb*{x$GLgVkJqkLrc=AnMX9d&DL={|K#`n=V$HyqTA)BR3(j98_)VDyNjU%1
zG7*X>Lj+|F2Y+ROXAz>j{ig7|+htbTLb%lr7BSey!k^pZ{?T}#JHch1Dh{)*5_zgl
zM(UgFnJ0yswqoPTjl=$g1Q(~BXCJDPeS8XrhA#it?GilKK+EB10t0 at etD8<5<YR`r
zZq<giLAlU+adv_ydGqVG1ljdxBvePy#jY{oSnLTEfguh8+fnN&IRRstykn#K0jceB
z=8vckmxJtVs`ePMlRaEauoLnA3C|Rp$*eeN2B6t?e2>_WGIWx>cVCL5WCJ$fGE`SB
z&h!dNZz0WvwQnA0g8TspG-gt5nX5RN`s_%*XQ-jWa#8nVZQnQ_;)GXz_B1}~5m`jf
zXhHUx6aRv(Mgw!iQ0`;5td_<At6T;+IrYN8uBy^I$>!AI#B9#S+5EsaC3W3*T&EXc
zE{G)}e&IAYsS+<)Zx=6%K)?7l9&9l_GI`=t|DfhAya;URZ?6hP9B}g-RpT~Pf&ytD
z6LVj>bNsXys`)QN<6&bD&!%<B?%1ifHrt+`MEy1)FKN6+RM$tao|!kXZpJ4Kis()e
z7#7*RJYti2p at Vkdm=}jt$h{sSZ6qs*A|hTq=*C5`C&e>`j3p;>-Dx=CenJZd;zmdy
zY%TVHJ-Ub;yGKvQ at E(!c)*tZ^1CA(#z_2_>yM1&WXIhHJ^yavDI9UV`eo4+cUS7%X
zw(}Q5;ksgE?-`+1`c;R}3`G!T^jf<sm%4Jq9R}n&=V97Yx^oT!1QLzy3GWEZXF;$C
zbdu>AFG(Q@#%&%Ny3<y+1hc0><A5P#>I$qg2MzNlL%b!=AAYnOeHoa}v&~$>^fIV`
z8(`SrwFtB&+S!v8LF^!vXaRgMH)v4eN0!=wEsO_05ivhjv53v*#)k#j(4``1j|7G`
zEseLeDtM>1e8tKfZjuHu)_RitDV|Ke3Z at 0-)$yP03hG8qi&lstg~am&pO#+lv%Da&
z6W(@NAkNI*^9n63r$>OuQb~qo*^t7#3VnbT)<P=rj!b4Yi7yTJqq2?z`vTWIN%0ZM
zI9^w!MI8m!Mmv=9%96|o+DExLF-nq26Um?Ve?a=`>+gA7d>gdf*ZC=?A_|e*M3<c&
z$i_^rt7is!7k{fvwbxrO+aICCq$h^Cl_n=$<!%4GGCCjvm|$~L?qAezU-s)j(6jM$
z?NTh(pp&rL^Z1shA(S#;Qiu6$?gJZtC4b~t>1D6i%F1~R%nc2G<8EJ-4HUgoeWPbO
z_hw?^qf3>`F~*Ep;&D`aRu0E#^g5?_ISS)5W#KQ43{eCQ2Ccyq7Lg%wb8eFQOef^|
z`<T4M;{~GwR6rQLxHvDrQ9pn5^mk|?A at CeBHMFkG6Kt{obEV4?NQ*4jyigdH=R|Hw
zI?=C;>#c++7GRD^1o_Um+|K6KY~6u&v3af9jyuqvS5vJ?dhHYkb6uX~v)*(eZMWQc
z8Bp$N%~WTT0BZwIoP{`UNZZAh*NCD=2<$stxPM$x-+GDtgZF^YmS^t8QBt#g%h`=^
zrr;V6L;vgtS30qCTI?v6DoBpzpq?Of$rty<Hreo*8c|a3D>pbx at N^}pZ4VN2Fuf?>
z`{(dpZH{TYB85<Hr1yH<h*_>wN10X_58NYswBtbhN9$M?6w+VXB;Tw~O?BL;kMN{P
zh7vW-CJZ<rCRdYCa1?>lBJj;?q`~mWUONADC0|ZGJ?s&ov-L`)$67e8$$<GY?sW3_
zEljQ|T|AH8dFfdN%Ll-C4D{hD0xKf)D(K`vKm%RNxel|$+Vc$eo{Urf2w8P^g&T9Z
zr+fJ=c9Dh$L<9V8HHn)C<<_mMJ$Wteyl6+VU6Xi#>ZoX3DhhG&IO1Tce<l;)S+_ti
zFCY^x%icPCyA<Z_*OBM2yhG7A)-6!%Gb?8B9SieE&(PdWTQT`A48~GoHMb8n_nhTr
zKB&!)he}9{Qz76wggBb5XBI%H5uD9sQDCckTb-AyLB`oqc;p<>U=#+GGEZ|M!OSX8
zX(Rl!kmv*Ve&w`xUgI}{2+q!zYz!q5Ts*pN9dC+YeXg~XthNlcAYcT(lO$&-V_t2*
zdH~MgY9SM&WUW3B*K`s<_3;daY3h^m`<183v~3 at FM;>mh=%lRyb^o)Z at pV+3G<Lp2
zJ+b$87-4HSOYm07VKd#<@#=w2Ts0;<qv>zF&3S2$pyMfhP2#?pVOb>&)4M8RlFs#=
z!p)&4T1w|B=aQ;|;nDM+doPgaODQ~<<3_b*p=7-$nHfP_>VzqQJW)hZqe$67k|);z
z#;Lu0j2B~wvZfa1R{}P=pXLv8Ntapm3j^B6>qitQESqZQ_m%Cw_k4LDOY- at oNC|7E
zcjf4u37H;XVW5KRd9c0ec>S^o-|<9O`qQkpki|#n4(rMtX8OV=#{{ka6M2sMfDpi8
zhKPPCMEQ1|kou#;QXY+Q@{q8(dqPspJV_&==4Rz3RrPeU<$KH}`Xj!JW*~ks><Agf
zCVHNLA8b<n4X<?+IHs`%pcEipfgsb}&_#_Dgjk90Lx}4fStJ6hoXof%B#cmXeTQBs
zTTcoG)uX$HHerKiO at cw&AP(V3*>lsMFr%7tuLF5PZkk8iE$e<c^<J+iq8UL~{5V>G
z3GLlBFqSEG5xiVM8I0gobiguWa$^6_+UiHNVd6%1Jl2~em3XXgc?cH!0mjhRhihXo
zuit0IU$b2SHl`tlzgEZ38M;p4mzGl$q*$#^s=o|i{H~q#rmh!)HU{U9;CjtQ99uOu
zPbMYy&lO4F$?#=cayB;0*rBm~JsUpf)T`p!wnLOIPosiBF(csn_`P&vuQs`_ at F}T%
zOnSUela0h=ZTiRKzUje4<E(?Q9Hry(s{`Q1)K1sZ{mbkFb$|ufW?39dJeZ)|@l)!P
zZ6Jb267qRR4K%m{{Am^dtHic>`B<R{!CX5R280509o-;>(cY<tx}*#8zX+bb;W9UF
z?rx5*qkpXy at yuN=a7->XYsjSxjVAtL9AfS;`d2qGUvip8_p6;Tfj!G%MTA*<z_6e)
zo*&3>LAUM3AozUE9i|0rAPQcG;RXRIgL$%UMnjSV{d<5Nwhq5!N=bL_n~<pIyXaiC
z9nozle#R=X4`QS<y1b#oqa=<rUP8mYS#V|{T<-YHdo^OgS5^Ysv=shP;g#k<_pXh?
z`2&Zc{!3O~$~K`@kyn)H_$%;F21a$=XD>vu>2)=6u|IH81R8%lFn#)cUgImFdx+?y
z-#D!GT*qJME0@|atIlR9v;CS(zTK1-QRr!|)nY2 at -i`txCsM=p;Q5p5`|X{2@{o?A
z6%j073>C$00By+VppY?0cHBl()V$+>EcP>YU^tF|Y?2RzP6gub3cm4-qat}0C`X39
zk<t=<9w!Zu6gIKCW=8P52DNsRQ<$Xd>Zmy}lnsipiW#lD%3aMct<sUBP0gCPOu=A8
zUf0tB{MyAWD7yO&J2|*sc$KVRBKj%}sH at Ki(-W-+=4Gb|zTs$WQ#E(P`Mv7sQc_HE
zAOPvLDJT|!Vn5#hY0I-jA<_I^mW6$Fh$}~UF)jqZ$)=5axo_rAyx)l(@&nOze0@}w
z)7~q9t9(B$0L58dm+sU>mX0}bAN%NGnF=8GGjpSL??3_aj`Ev!wQrUbf<FE(T|1Ap
z*yTXHCu|{G$yDovxkS<0E#glFF;4nO9)Yf8!Rc`~$G1xQ<c|`pAI60dz-LwH^Q(`U
zfJ5-s83;|Z{)C?knM-mFS~yXLdF$Vndl?HQS{9rYx(vn$cOOI2sk_7WBYFXYk!;tN
z>^ajjn!T;N$r1!J)xx*;*74%^{Q-m>#E`*^br{YWMLMm?IS-mlDQH+}tGX?WqdmDs
z^d4xHeWHGfou>){G{WN2qjkb-$VTyamkb`GUp%lm)lbh{AcgoTca+}iS#b;pkq^NV
zS|IC4o3!;0mbvezr`Cr7mn$b<%0q+tdmGmuhrIqJPtg_p+zf$pmS6|nZ;aA<$@J_7
z;qB08@;|Y6ST5k_^i2Ekxyan|`nC#bMDpO+YQ64KW`|m~S)J+I|Ek5du>pIz*wKQU
zzcS`SF1FN<I9u|!#wBQZB>7k=w$l5gkE`CZT931g)wq;WizYvDOK;NsC=+Dt>#x|?
z$}?H7&vU**f#%Yp at XmBYRX5`e<{}vC;#sCnHicp>tmcmDFF`nQQ-AeX3)cR)fpZZd
zOPl*Wzh!xWKo`RoO5ac|R%5m0v5wNCU14$P-a9vjVLJV158FPswcf_w{vF}_fhE at C
z_`q?=Ns+m6`H)G6C;d(bwNtEeJJnu?#%}<Xk_S-7k0 at _HfW|6J(Ivgzg{RLDx;{as
z5X;z at 5F^`3O|_M*Dkqdp7z!d05JfzR7Ih<*$|rIqbFUC82}y>Us%><?-<{i+=rzf5
z>b6KZF853!LSW_D2tZ<zf1-4dubt2g>BN!N>Sx?OM;i}V;#pnrmliN>HdCbqRnVmm
z5Iym+)ad#?gz4y-89>of06m5rFl57zj7qBLr4>-L=j7>O1`8GpXI2Alw5 at qM6!i|C
z;mKKVs0n+ui=ayUxw$}5ePf;DfSb^{S_kzz24 at tOT_rL>rljU=?v!nQzjWLJR-U=e
zK&Mn1enggrQ9|-qBJ)IXR-1?BHX8;S)s`T&^GGn2v)Px?eyK2AcYy-tKj^GY0DLI&
zbM#2H;I-3eoKX!xn@|0P7tn_QN|NGC>K9kwxUY=kKbUN2UH8My-tTBO*kq$r+L8jR
z-{2tWryIY!K|vnrui`DKJY$3<+7JH7EBRsl=uFk`=1>AUZ)<mxw!-GC8c%sc?KGbw
zbe-wX>v-k{;DeK)bE}eXU`FH^B;R++f<%CK@}O~HT)7e_!@P0hvIIbjMArr%Et_43
zfI}LOiJQWV38}B0xSZ*}F0<a`fv#69+!r^CDkJ{q(jJ*Z&^Am!xyu{Q9)Gmx=(0Lc
zy7l4#`iei`Ll=KpPO!OYV*HYWP$`}@yJ!*K(^q4>2>mw6V0~E~T49OuUvoPRemi*1
zW^wD#;a7)>@is4v1=pjc9z5j}Os=MRcv`oErtS754!N(YKIt}qX)%~O9E)zNNg=n(
z>uoQ>GWc<xCnbIMw8Ws<Fxs|_%Fb<<wnI&>yjfD|SpXX(f0;K$6isp}XfPaQ5VNZd
zK`){IhuYm+=egx6MffivB1%I8B|XiI at 0aXEnOf-d)5KbJV at c|9e0S#4bj!MO3?cF6
zFDAtFdwF`?w$7brO5wHLB?<Y7AKsqNAB<2o)(aN%TGF{(Am2hX0ICg*TU5K_c(In_
zXN^DCXVxW<xpwi`YpI>;xBalv1(?xj6Wza_J=#fX(Czl)c^5+gi7V;xNbX1#&w?7|
z&43qHj)7$IwL!i`EoSrD)!ugLPV$%S$<|4?_j at 8EarxYo%`r>`uf|h~d85 at i2+j`c
zhlck~1QDi2{-W6VJXohX!wc at j*Q!h77ym*~>fM${S>|3~pNE^Iby$r;%Zsq&k2=o?
zf0?_ub=rjw0VuGQt at hVIsR<z4{LE^nai2(bL+5ua`t6<rP4p#+tKRk+xJX=^MeR1X
z@`IZT)DRJIsO}ON+EEwh*(9!W_F6XRMD+3^*d`zoPX9?qws=7jq&Zu&wO7=lxDp<?
z4Kx1LApI>ZG9nw_UBc=v?eZM>D0y6En6uu{=(STQ#14q)<H6(d(tzTB)XdK60?I0=
z!^${HbN~@Fy^&Whzn;z`I3J$8RLo_arML5~9T?WcDSZA;*B)P2AoqktP<;y|q19Nb
z8x43=*Lc&1qxF9YHw$L_FGovHxGHODIpcEkCTgpbbV_oCpNUJnKU06_Sq^b!-mpYL
z955#9=MF{S2#M(zr>1;zkj|stIm3>NEU!ufi3!DqZXPlcr}D9#4Eda(fuy452%hJV
zDYB2XYM8!H3!09vp8ujfmehQh(-23Gv=lW^*Yu|9WQWh|N}psb*n(-)RfYA^`tT~5
z_@|b>IbN+vt~5r(LE}pagWV?+3%7rS%ylWXdk~Rg_$>LMBT4rTZRC7eTdsrzhq*=P
zYECMD&c}|#xf9T@?a&R6Sj3KuXDdyg%~N?Uw?oD5jf=~$>6V%j+z-nPAy00jbz^m#
zE>G!DcpL~#NK8YZ#HVP2$+F(?y=Y`;o8LHO+%RIigP)wL>yP~JM9zc5OB{^6#@La~
zIJP%z{9NXk+5&i-5#}GK<^LM!<}AUx(_UZ`IFo)mxspDcZE9A)$brdVJTX*Sy`tAd
zzkMVB9p93SK7q<_RH&~3v6EUWe5`<8>j(_4fdfPf<Z*)J!{YA$umC$A4N@^yDX#QV
zLWB5>O%)vA10Qs^23xdR)}Y5xZ>X4w%aJ#j{4N~m6VYH<o4;y?#^Mf8>v6nwbDz=6
zz5IJ{Nad~kK~Yg3!i%rXN9}W$ikjegQ1p+>Z#$VIEe1ph?EVl1n7O2Ixy2$ih6R;Z
zt^pYkF7s;`7s7^gXy5KK@`2VY3*cuh9b^abCQ54K6hUwa;*GgY)klq`Fq#CCl(G<G
z6bMOdDKhs$n`)wA-B9P;)Lkq=?<;B?W)gE19(SXXhnT91yGdX<4wO^@ib$hc5GvKi
zK123SB3yK;0Gz at c0<b8xq6`SmI%M!#cTSzSFoDpI0MPCv9}nUB at lJM$xC98PvXl$H
z>7>H%`Ze%9Mj!GL0;-9_hovs4gR*65AMmiPkVesw=dx~_NgaUvIPK064(mEW^EIw9
znYH1I>}ln&@>5(_iOF_kt0wUco~4VO7Og|kbZqG7>zjK;ZJN;XEM%rA7~`0)y6U{l
zfhn0YBJ6ItU;{){rKWdy;%GUV<~0`$Gj!{)VafEhXncgZ#Inwj_G7C?L^XbN$LeN?
zSf!iBPY_$<J^(*uF`4&@M=kUKj9{&?>&~ZGZ|j|q+X9Q)xZqFvrt<nd<+;EhPF;(;
ztF{!cbssoD6_ at X%R(?||OXk?>u-5OGu)m)Mns62M5%|L80W at MM#tbU{Ett_ccj^$t
z#ZFk>OY+e$oU4Zd6m!Wf>J-7xS{a9NSaGlsfu%@XF!LLnGh_KwRMx2TaieWaLB}mK
zn}j!NYO<&$aiXuRlYodf82JM#1x2P*mSv9Z6}Qa547K at DnULRhrs>mB+Tr3}JK>cq
zQDOfrBj!Tg`j8Vq|6RHa4Y{vC0DwI?v;cqN^4U|%(cS#Gg81E(Awm?4|JHa^SMd-^
zQAki?-+)Ak!@)LnaJ1%<)Wk|&mg5&KPF!|6$~BW*YICREg2>(4*6P)I;HO4o=lm51
zv;lP at e$xMF;`w~!QWYhK*gakFGMGOMU{?Yd at okPik|SrD+HJ6lXrHY47rwYQzcHv(
zRL{DE2;N%JGGRC;yHgJ?SI&MUsLMKAyu{gogr;tj#46HX^{QHRS+^VaWl0F(7q%Wm
zwvR=3sjV_cy{X;w9A<UXY33mnA%nDndX*J2Oi`QVrmYSVQY|=stg_zQxbWk;!CW&G
z7Rp^6 at CV$?_nXV6(JeOiB>7j?&U^Yx;*<xd7+)i7i73j%556k)b%C%0s-+ed9VM>8
zgq~s<_Oa%Qf85RE#V~@Fd}Zrdbht$vFq3Djz=8>TDS>a?jWCa*v}IJ1WOX4IX3gLw
zRzl(u>E^IXb7+M&a{daW<$&wbmxxe6QR17xEKJ=>DFzFkhZrVaC#2j7`hgMdPg#I$
zmWt_iQ(a3 at qJ6DHcJ+eJSGA3-!MX&I>|q=Mqg6~)-umxlT?OYk#u2IOo`n5VxGz3S
z+c`|HA02WqtNIRJ#&H2fm|$P{yQD at BApEMMwj$EHTav6y@@Ha%ZUR4uH`+7=Hh2<p
zpVd)cX(!AetiaIS{L|ba56M$*t+*<_ExC~%Ij1M5aFA#_Y>OW^!jaQ{x>?5yYBZ9&
zrxcJGGT4$Hf7&R_RYjl4n&6Nh0T9XC+t=+n9<BWb#Irmny8%4{)Jtk|o3q~e<EhdT
z?&Zu__N04n)q(kQjuM{4D|{+&Gdd`*m|R1ymq%m6%$nxIoRmOuJ0OwBs7yvEe^5Pv
zZ(!=HvRq)nU`4&CsB&nTO)R+zS4yfw`&x2s`C6UE8oC<Xob%C%e1=xE{Zs)%;i4&D
z(Q7qo2;rOwlGs)4mKKe$`YJ5peptFzbulg>V!TBW4YTGwl3SKHs`AOA>h at Zv3PbU6
zVI=9l29+{jP0LGpE3-r$bqkixdz0uNh+*uo5#-<)r?c at vOwk-UCZlzKoNk!0%<sA^
zbS$-sWHw5VisyppP7Af2Daz_9eigucdNfY|X98J^=Bbv`hr)@LA%jSOY3LH52)g(c
zIUp#_u7NNJC~EIvpz>>~x#lEZnfFow9RiO#!jT|M`>$nKNz8rFCmg0 at 5L-T+4`2S>
zgK_%Kc+E3wX`?$}(uC4j%cR<8E$!<rY>Y1*e^Rc75KEdwuxKBrXan-cNXc~;-Ko+n
zJAV|V*GsP8ce_P&(DEL2OM@$1ls}5JSwePyw`gw!f}72B{y$aQ5oWb?4K`ZH<Xc>A
z%t4gW?O>H;t_#C0-esDpJ+{=gSvT>AGPOk`<(CxpTv>9Rx+K9r<iFKYOu07ch at fi=
z^7J}qN`B3}mA2qIzV6PeH%KBt_ciZ>4-k485y{6>(+TQej#PPXVh-k5C}|WVwc+x8
z0ocKy=@$oD=iEV6Yc7oCl+BFIpk>1`M{P_-1rwOsqymjEWIUUhQk7DMoN{ZD+A}6n
zFVc4ugoJCQLZBQiW5bYtcz5EO|7e~z)Y!UIWe<%~x-jbx6&{VN%XBagA|iBaiG|hL
zArp%A#1j at _rtBW*PBIRZ>lc|!@VUCGRVFkV6fQTBq(P(1>x2LWe*Wl2b!o}grQpj`
zwR?xP)g8Mbcx$hk2(Mii^rVWv{B=i2!R}QRZ at K@?jNHaHpY`s9ASuQr#=@sR$r$`}
z%L!Z=;>22ZUQ#7qWPgBfS<|hoOP at 5>_SV^3Pj3Zp+}>=G$k)QA+~Ub=4cy=H@#<bB
z=T#`Dw)Y1iO1c)?6Efin=3i$ixSG%N{TpkcTH+}7t&@d>D@`G5%V>z at U$xKNMYQG|
z$RM+JDWbMSlGtgMxU)%wT%K2{4uXpCEQgQ~lCev^aaOdz<HTnL=)TvSP2%MJrUj<T
zIBcj%`~sm_+&rw>@uFP_rrojm5y0O1B<T|UC>(Hc2`kIE3coaFjK1M^4 at 6%>5r6>Y
z1OAE0%@5DsNj89C;mRMU-;Zwef}r5R;E>d;bx416lS|Xm{PdH48O=L?GWnC{x(+(Z
zRKOOu$F at 1QIgL(*hY#4s#5 at X&dsNqZzUOeF`!uI)ZoY87r?x<{FQQ*bsCNLN^v~d>
znG~hlsDAsVUFyb*@We~Y_3STThx8(ZsR7DHyzC)3=RVjYoG=~6>za7DX$>qNPEIbZ
zPrneUS}^X`ZIqqMjv=cspZ%uw0UFlgesI;$V|}5lMV21_%xJ;|xNzvG- at s*d?H${`
z7u^t7_`7x at nB5?_1*88FsHJuKByWB4wfn0^oU?vOH5QlISU&2u+WG^E*20$5+TGQf
z>G{NkCb=V0K--Ft{&sn<;)Z<1qrjM~!4AH0S|0pkH`vTrM2)U|!ratjxinRML^o|0
z-7u=}dy2;NBdqnyL9%tPUiospVWnH}WMTn0_Zwbs6h%Ec3cD{_>-bt>d*3&lq0h3#
zd-{YWtM*I%Oji)jxtHb-n;@MftV<Ru_9n`+AfanGQ<f665Q&gp<`7oo*+p6W3J!#m
zjBf!|T_T6(cAv{HmaxDsse=}X(s|Yh5Dtr8{3FLDCL8;{pK|Z5<gd6#QFiq8xMFAV
zgi{zSvD-sg*mX%iJ`R*_Fj~kN?IS~=m{rzMr~ap8^(gle(xh7YJ0wMe at 7;w`$Y?Lu
zoEh$&V^yJ3@!v&Y_5vsNE%}jBlW$<!>IZDri}=0EpsJ64o7ZFj)!6husz}p0GY2*)
zLeUdj2No=$)9>LZUc-22p&KTWz1eLyc_5=X-7`97`PIbaOuPTV<Rg-OT>oiJ2W$JB
zU(fjy&jmvYO%LmhwZqg_i*`7PC at OTkY$*QOp34Qvg$ebK#0C;~79}$Ms6H|$Me*9V
zv2x-iVvwAA!*PAmQEcY8y(I&7a^ytH4z)pvSZ%N(CYJ4fFaC|tuU;#WtowLe4>JN?
z){M?M5Z83z#PoDhUm{NgD6LNec!uKmbhn>bP*<_Hmkk_Rs$pp}!)YgYc#znX;ghv)
zZ3j|OC+r at a9$5E5v(Q0CtTdO at 1v7->pmUyHgeG?>t;_{f?}qg*i8x<b^(6Wi- at S`*
z8Wii1d|)>01nP!ryTWs!b?eupCDx6s2q8Ft$Q+p2{2{_Zhg5-YA%Ye at 1Gh4q=}3dr
z<c^n$IkC-UV7ATl;Xhvdl$#Hp4_bb~#~7z7ovH!nqj?@|%t2Y)pU%snA#Gqn1_%$f
zdQxTElj?3XdTC;Gv}z$~(wV{?=DVr~Me0$G4w3WFnV#VT@~N%Qha8NH!Xstic`D7r
zh~9#@$;)i925bMCqA_LbD=@2~%WY~Cg%BL(mKqJnJ(dR6*!gY#kQz3$`Jp5A7};RS
z#b@(&vWg{}kx+*Q7yxR_Kh`?p9*qvURE+p~9iOzDdHPZ&i<!+z?#zfAkUFam#SwER
zH}|j9STxyHP_^XyfHNH;*03&#(3qIiWDszUxD$xwJOB%+8dLg3y5}pWDaoUIk5j{s
zaKA(Ji08I45S2ca%9H(Zo}9BIW}{o54HZi$%EsvOF*jnSiI#Aig5|xFZDg at zWTByt
z3-WG$DDK$EC9h&YSr*BDv*nP`^jqM at _Z<qII3a2v at oEC-k%8nhXOpyfY7aT+4^a>%
zcETj$Lv>32NB)m<DUt4e#MhfTtjGEkHjXt<RsR;XWrC*etz?j`bjg;J5BQl!b=Kw9
z1&sAPX;s0w<gZ`rj6&xIf>|b^Jl6WR&gHqDelqZeGg@>ZAkD?4{FAN(lHg1=`YvK2
z-(j;Q!%CM`YEnuLfR*PK;lbh=$-t#ouksVzFENa at jxId|Bu~T~%Pb%Iu&Dp-lBM1I
z(KTmrGTZzR{12U}wT^799~n6kE87~oefa(_|8w<;fS50C{@?F5+d{Ve-*0`pUL4x?
z|Ni#=+Lxbq{QAFl-v6b0+rPK|pVRpFnEuyB{xymJeXss~bN<Is{A&{bn#8|><A0;(
zzwz~dLdCx(@vlkzi<|z%O^5&g;1PG<{YcbKbzHxE;oP<VkFWjn)Gs~@H%{+<b?Sev
zdAD>Qnrb$YV at 5-6)ogUd=+~_uYdE$r;HIG0b=&+?S#I$qL|F`zKG~0kDiQ~icUB19
zu1s}Ca}9~c+e5pdg^p8&%N-1V+2e$Z1K<Fji6X!43HeP1X)lpkt3H6|$`0?>Zmlw2
z%j%}LT$!p-&=*+&{m^eyYu6oev3C|Q>p(pP3U{HG at i|DV>%67%IW-tP*14)}?2JL0
zQpbM-YfBA}kEpNTZdj{NT`0v)E8hUlT_hB6n(jhZtp+rUEFl;bmDFbpVy)X9<nkpy
zOfPw&2^iB6KT^KSSnfdE27=*cv^;4q?h<?UVg+QXTG6O5L(*q|fj~{R7S?mF;w=2e
zy4K2t0bx`9$QElXE+gUXTwjf at vq`2X2X~3Flyp#*{1XBCS3O+{?q8R+RLBc{yQJGu
z9a?@=vhyjXa;#twY}a6}OB%ekbn%8r+X^p)1IzbLmCTL)h)+!>-Sz0IzC-uj8SxL%
z6_`ESXFF#%o$BB5b2P(81T;=v at 8B=1l1S1^plY!s=t1H~Y9V|&H5`lSy(qJ)fTU6~
zD1u$@8NU at B{0fAfO?dhNs!tQDl|K#mFG0n0cP)Pl&fns_;KW~Tq_w|G$m&)EpR(uT
z(O1;_G1oxtFXi|!6^9xAmHV+O at Mx7gP5z#@hg{O+j3^>WNI$3wRSgSC(_58$f34At
z%iTl4G)nfOLck7Wq`bbV2=}JGPDU&9?h1Yx)K;ro&lYLeEATfD7O8!EKzFn~fw~DP
zhR%8W at -?s$4fX{xN*s*?56L=WH-WdP65Wq)$mdf(SJlp|=Jm{{yvI?YXB-l%dk+}k
zT(C~uQN*;JOmB^;d9aX6&AJxC2vB{WKMU_YQL!2vp4T*}yg|NFkQby7&rL^0P#Xw`
zkQambLyY*V(RW*DE~bh>vo!uoQa?bKo^~UAqM2SYjP_2oiAW!{w&=3juneD)kxeQz
zi4tO`PuQAim7!K4ZqMuR1<|*fC94~&i|&^dfv%(Eiu_4OyVjwuj;XLR<roiomG=cI
zq)DrUvmZnml6!?EXg|=%S|j}D)h?Gk0Cu>KO4j9*sv2(R^b|KdWtxjj(Bpe0jmmf8
zqz+#@>z{7LHhyzlU<c$}oZ{%e(|O{Z%!qacW at s{m;J@?h`YyWss at jo58IgRlHwE|<
zl%R;qETm{`GY91yno&%OUfeO%S;MZW#?rAptVlINROJ6Gv&@fkCiRMnu~`tMWqFmv
zC<Uxw-?f6q=`B|_`V at Bt5~#m46i<B5Nzcf#OBy5QgGYr=8V^=iffQ5M+dCfMVuPQ~
zmIm!bo6!my&W52t(>J?_R7-NdYDnLC*>u`U5}jk8i(Is-Us>E+U^U_ at QQiDYuf33K
zBe;D&BnogdB at ***@Y3#t{$M%!xMMaN;<zH$5<={$aOU)Yc$!2#wThc}U0o#9m%)
zPeTTEEIei`zbz)xjRmGh3($n#wZwi5p^jc1Wun?)__-7SbI4ncJwKAtVOc<2ri-+U
z|97Y;X6)vRV}@<7pT|FI?(5yB6QDFJ9<GgPDd!_MVQpJOozt(vwsOO??Pu;?;Xs+g
zU4cT+{teUT>KtEv71Ug$^1B+$xE7(+8f4ADNckQLtaDE9Qu&8Gr_da**JQV)pSDxu
za>q+Lh<SZ#A;@2v-QiO%aGG<&5W|K#SPvjIYS`|teCBV~qh4N`{&ZF`?7+b)g_9hN
z&Sp4fCyjtu_=w#{@#yVo&stRFOf#&E;83;$M<X<w{%NnM`CG&4IJ+Qn48^S0Gxd^X
zccK}WT`skEIEM5!&EK8&ush<9TYvwU(W!~C`U-XK>=CSk*tekVjH*II(%6g`eJ6=K
z<1hpzy21a3#+6HPet1~oxpBV<h{eQZVq;nUvwJP;E$zp#&o2(}0r)xc(d9!FRuM<V
zJbhd&MGr6mk9J>B?zS#XUlr`QxnvM^`3{Kvs%#r+nXxO2Ije2fcnNoS<QYQtBbO?B
z?@0<{szZxS<I1T~z|<wpPrO}I<V_Oy>eN&My%-w;=mOyvW`;WId7aIahxnU~WR_>@
zE*SJ~yQ;L+Q^gVE|1!Dnbu80z1f_Y|Bech+Nefr+juShSlxAtHh*4d4Je<Z%utOr*
zMp0{4-8T|<b~yOTx_xDjgRj8NfnF>Crs<L%eM!}&xE<8{iOQXOo5f7MJg~dt<ul_<
zDWlJR<e>2tq{F4+#w0hM9xq|COXj0WNq7EsiL|D7waINYndVVS(>)qhHvNW at IhxS9
zqKi*l7hg&*s-oaWEc_Ghwvp;e&8N4ty{o~&f`%14`JF6>{y+8f{{z at UeYT9InI_1^
zTD{KFWC&JcxKZ~qBvm at x7gCW}=?khB4TS{4CsJCv1oh|>xg*m*Ii6`)bMRVq2uX|m
zCANTu-1R8<l5=Hn*h<NM>0_kr_PW93{NW#<9|F at Y?<Q7$Jd5=^zIXI_iHYFk^cU|E
z(VIwB;C$1)1NG~;J~wg4s+YVcWK8%FXWMJbd<$LljBnjr^rWtg^fT1%hcJI(LL}`k
z5VN-`F)QZoqyyLWMje&4>mg=BhbOl}w#+Vvv7LbTe#YALI0XG%^)w`I31|4#-l(lF
z%-RRU{mC!mMgb$@Pmfi*qb2qAeWjx$E^L+#f)=*hCI%>PrXC7;r?yi>yZz$f=SpPU
zxzXN#ZdeCc`MP2r8+|s$u?c^jB^SqE;kSH(ZLL<8`U-s<Ea;J*UMq{cAVrnr=ErWD
zM=8 at C+LfV?C<jP+EudBJZU)MFv~YR=TT?BrPX{?WBsC1DS%E%1`*`5au7BJXG;7I(
zLOSPTu;_sbTF)-r)ck77^~WUrWR)nZuMfM{=;9WrN5+tbP=#|A|JV=YcCYl$R{jzb
zMr~%UHQK`{gWeo)3huro)OTU8X2%&9{vmXK2!34I!TUUTVF9xA@~J0@)(&8GO$2b^
z;lTVJzhJn-grno#IyZXBc$3a-NusM(+KMn`GiA?K!l)gtt;6Pxi0A}oZNmow92Zje
zN;B#idq1T#FY9ppjqnBT^Gd}`*>GVMC37Z3+u at LMaR4)trncEiaGs}1ibXi!h)1P!
z-aC1EcdhD+cHAeu_)OMz+D^I01HYde9}gGoD)m~`6P);g77|N7d*+W*8SuazOWV@!
z{j+rU723V(2;hCm6HgfUy>kCfxAU1GrtO2?LVIc4Q&x?{z42DQzKE)uR?CR9To at aF
z`||BWf!T7M&HeMB-|=7lK#9Clw!RBBt*6}MS|sQQXQuk&SjE}~reP3xusqj`m5ENH
z+%we4mC<qrLY$fSxai=byC)9e&!p2sw{+|K)WLJ(^1|X|qr`AdwH|HZKmLlB)w%ZN
zySuoEDp~tm&R at R!s_xC*3zp2Rq7K`~SBFgZ-dau}ZtfexMwa(19ll*Q{ysvYKb`t}
z*9!K&sHMM*+`3i0Qki&nojCt>pR-Y4z|ulS9*fI%T87rHh8s_J$qGs+ndzWA0mNr}
zTKTTZG3J6DGDr}`>a>rYEs8TiGWcD2oPl-Opftt;JYs&;8|`*NevusGr|fdkHc}ah
z0z!-cxAq-gvwc2X(b$vtwUge8{b)_wHB at _h*&eY=6?v_8#c<Bb14tLBvb#b^zVX*7
zBmZ?Ujc%LI at EuvLr=>y-tR at b|bB at 6uAHjReyhhImb^du}U?e<;bf0f-w6VH#Hzek|
zw{Rt^)F7VK;?k34D1Y$$-X;B^rFNpA+s{~H)|I_REq%1MLs1pdR)G6fNA<C at 2Y<dz
ztZlMx5&hXfgCvhP9X9SezB12q>dzDZq4 at a+>qE8ceU*z<BZS9h3->-UW*qo;UNyP~
z1K;$mUSc#?rv3iuSHT~QeQt`{;Air4hIp)1UvA$FIlyt$9bioU=lpDDZB-4qmUXjY
z|GVwmA*%QG11 at B7X~erac5*&@D>LP8z<j2yG3QLCh(D&?u^6o%u=TkHTN-wxy7P82
zy|}7gl*W|)3eYu^{_|u-=OE>qJH;<;eT3-HUMnUFZQt&Q6MR^~=Iigmcr15b^VYk(
zUtqAZ;B2)jyE|O#Szckk8s*)IEAV*>y+=Bm?ugHu?`|ehGG90Dzq{T_5&cDQ9t|(e
zgcR#gXg|01xFz4-x>LU;U|7CNW>eXU-_G0jZ&cf;t2Hrzk$i*YC#<OX+P=N^rGI8l
z$kzQMv89O)gF#zi8KI-^ej6}7kIU+*4FUG`zE>8gX0K<8{_1SxN>>|J;#<!^I9e&s
z9kJ&tDxm6k2NLUcqcL4{D2$9Z=q-i~PaOb?bm&E~7jfHRT$jK5GP<1E;(1I39rRRY
zs|;MM8Hspf?@)@lAA(}CF~N%A79I8;B*Gctq<ZPsf9=`GOYi2yXG`}0J;uC``{KP-
z2BL&h$jcLtTXEd at aLqWNF{HvJLY0X!$TUDr_<~GM`D0`1l`l>Y>yuHINxjDyrQa58
zBY%Eo`~ZD;;{4j$6>K`~aQ(<Z+IPIu*d|hw9un8unp%KTYs5ECRWya at g>mP+RO<SS
zTe at GL+fzPM7{>o}i(pukRWzu+%l7ZR`+jJp8&SUB+1+Gv<JhHj85<RyDnqTSqDn08
z?!boz>oc6@=N{l%dmGWWH9Pr-e;+?<SChLv-70MQ{fJW4zO1ltb~u(vG0l*nZ~i5(
z+3LG0cfRR|IG;LhP`#@9?ST%VH_3nxr#=2A4tEYomAq}Ypc@$SzM0QN2tK-ub#7o5
zA|=7e;X}T>UzpnNJ_2_0V2vu$h%hvXb|e>n-Y;~LLZ-qI)FrproH*Y at NHiiw^p<=<
z*5!+|UjF26{5QSXvgW^Zes(VjWvJ at 2wEsom$F^T~%pf at GDZi*;Anm9P<WTJFS=n(^
zOpf@(nVw_QPFMNGvVVHX?0d#3i;(#Cb$=F-K5}Txn%>4diLIOX^J2zDFv^ikKr9s{
z9^c-G5lGE$fx^7!Sc``^KK*Z{X33lN*EqnG=%Iv>6 at JG0G9K~1PW-;fRVd%HD*1N7
zV0go#9#gp4)Bi_buTQ_}L;2sUYw at ft&04V#E0Q;FJ+cb=WRS!!v7IL^<|nge_*KLD
zupvGZHNB#f{4mq1hUx<9-gZ5{%|2&%?K61NP!Ca&{=?+oZ#loEqi+u_jisg<qo at _%
zz(jrH=^nQXG96<O3u*{@?3-IFrlnE;slGY@`g?fe_sHi9j(<pgFjgxTCV%##d03Ha
z6df~j<cmT{tTVR$FzwmMKH>pQ_*3-<_SqhMeHY-z)*Te5-m_D`&F)JNO?wqFJ^vx@
zp3y(DKg)qAh)9pI?R%YPF2X;0yjrZjco>BZdqx!H_$bUbJllFB-d+m|$EKl-+yiQb
zch)S)Z5`r$x5I;XUGVTv%E!I2y-z1y8vnu}pkj3Z=w|EVXgr$#2b$WDu7M-|sU3bv
z?bxnLVi%@$;qYVXpoG4CeFu+AD4r?dhSP!3VcJI2(}rn}=k-G&wcanD7e*?t9_(B(
zQ0f3p(Q|o2Wg;uGJ`URY?)l!IZPVGQhWh=`3ixVhw6G*ISMv{l(Wc+gEY#`lLLDZf
zIR4-e_UycWR&ro+Db@=cc{y#334#dgdY>?&VrCY8MI&b)GLn0qHO(p1_Tk11P!94F
zAoz?+_1;9yctTJAiO(Gy>oAzKOlo^LVnxI}lVztrHCLzB<(Fw*3~T<;{cUX0>>^)+
zH5J|~u(;kD0$8uIy&C#c)yDX(jX*hAS$0<rRc@`y`>`o=uTV5H>kB^rcatsq<{aR>
zo%mf<&z4iuy6 at 7dTg8Hur7dQ%uAuvOmdXQ}dNX8sr at V0R48m6;e?HjxsLgF?E-Ee~
zAl_DZm(t*;<I*Q7O6zyd<p})Uo%(x9*ALAf4n!R&(C&p--nh6oC~VdeCz-8sVm8sk
zbo~3nw%ydfV3c$??yS(xdt>q+_2xmIGLaHOnBNha;V5%`_t1MNj#TNi*zCf}M2(2N
z9rd|xh8jr;<A=GvhF&KoDC+(rT%z~c8pry_-n$gTyce~b2%;b?Wd*v*T6kOx_v at +U
z%&xwKOTyZSp6rQi)v<$O^e>~`a$i;VgKcNu_qnZx&ec2`d`YUbGM2J|{K%<yC3dHV
zM?LS5k2(pe1x90vd4ttmUu;L}rxtlU8!?0p58pZvI>!pMnHOZIq}FbdZI^#-#xA)_
z9ip~<@8Tzdch7fAfd%ME^odcmU%q`=ydfK{TQN7zWA=dmrn?(LG+~ph&$%@Y?}bJZ
zYOrza1g!P4dumNc->U3v=m~fndOaIdA$vRD_pCH3V9J_2r5gsivm7}Z**_I6IqRef
z?CTCMH6yx#O1A8t8kZ&+i4u9&rc|D*nj)-`q#=yG?sAoJz;c=Ps<y$+QUDXWMZHZl
zy5I-_*ESiOr)<Sg%u@?qZJtw}53$i7r}1xmvp2O?jZ}nfXcwYE>t&x)A>tVD<HY5<
zh1$&vH_jZS9O=qY`pqWv;DK-BJGN${i8LeDKqQlOeahcdb8 at brsfIRgsd*lY2VYOj
zih486x1MH{%}w23rykxvIfm-;Zfp2{Hud`@r+2P%F^nU}H9LS!*yu;G3ANToB!Tzr
zJ2YSZ?e``3Xv`^xi3jJcGp#LTQRiQ5i*5U+x&#iKnjUcUFAYiLwN14nDfev`-{1OK
z7EsuquI at _<hKOKtApRP$9WV(w?Ct at syr{H<X6`FV{$~10t#8a9!RgV28}<f&-_|w2
z{%nl;^`+D18#XZ7EM2MeNxv~`OABRA|CZD~9eHk-esDso-SkJp$c{iVfbAkT$<Z($
zeWM3*#I)kEQ$S=8|KsVe9|lFqzMO4m&ENMDYN!30UURx3`9AR6>AtI(v2RLlxP?tL
zGa0Ci%onUMyT_6|@SUX(^hvqRE9Zn~Bfh7ivXaLOYj#f`sgK%afTAlh3zI+cMNin%
zd%8x?woQFl?8<^$&t#6Cpzb|VQ&4YFL3dfWjWSW5eX!|`^>;)%E^Y!pEzE at Np$$8J
zDr&-2hYp8+qq@>Hg}j};L?;;AuFTBkgKAqlpH+djQk?$-h`GYp-N*8NW3;n%*5ZC|
zAOGg at DrY5~!Z@!Te0UGzNb9r)oM5%C-I_VjmHL4wBS<mnQIZ$qO=rMqD_d^QYD1FV
z4o}cZ?5}4^G9Y>lbqkBR`5iakN1c*6g|fE)Ra&Y5XuPq2rbFYMaTgm?9yN!XZ&5zQ
z(7v7WkES&XmT!zMubE4fMWHudH$Q-X)|^*g9XYX16d|s4c#O#KxR)+LOMZvO4&O`X
zHq{<Ml#WzQi6VzM7rIMgQx+4Z!0|>(@*Vf5%uy2~I=&NH{3v5>F#yPU)4hl>ATmz3
zC4(CF_C5LVzGM7c&^_fX6#Ri{;5k#lt=TADWD_Xj*;MIQL+8 at V{nlU{yE?7%>!xuv
ze(8 at gQS)clpBnmVb8}4>UA(XOE_XeZ9ktVUd()eAnorC!L7gqVXqFr}liIhwdmIGq
z>IyRAm1XM8zuJI=*xGpPMRoL{R<_vP)~Y91Vc at QxTF-VD+>n>ah_XqcVu(lW at o`Bs
z6m5dzXYN%f_uMzEA=NC$F9E_}2a|Q&W?Rhm^flXNZQeF6<Gho%>U~t-?1t&8B#o1;
zOYaXR&2GCEwwbG5x`~@e^a}0Ns*kzrcEp^-z8~i~@y}69PPqy0)7S2o)?&>&jH(S!
zA~4SfYqLDtE~nHf2_5()WW8WG5Og;~I~C|v4DV&m=D4~&kaj=Se+ at A4;CnlL{BlQI
zm)z_yHYmC0lj4RgKlb(4eY;*~J at B*b#YS1UdS$gZw}E>7SqBS_NdJD_M$j0aJW)YA
z6Wh^kUC1wd at dSKj{;u)-BIAguEL6H<Tc2xO8B-48UE}#W`@3%4Q?p~dniz<<KzEr*
zpSh<71Scn+>Z?<3a|k#*Cat>#ag`Pgwvj)k(DRdTub`&CCUa+MH~BMrQodSB&j4ol
z0JHdKo9?^}v=bkRlUbK6Lm69UXGiQePxy|qB_X$!dejVOJ_s4c*&na=u<;1VSbJ-O
zCF6|RNIaW2l{YuO)P$0KCJx2N#9rjEzV2u+YDmdm%iq0qVRwx(;I0x8{yt9VMo`}z
zzyEmce0;(|PF}_ at ***@I8tqzki07^J^~5Pw9w1z`=!O2=0VX_3Kyl2;F}zk8gxeXr}^
z?+;RbIeq%udorTOcI&8;a_q-UCGb*Pmz}-tjOPsSUTxg_tyk?Q?{=#Fx+8w=dMEhO
z*XqY|dUoUno%@x$Fzt%!`r}<c^AD4A<}2q4HsO2kuU--a=!Ov!9iBTS>YD&VR`mJb
z%osE*ZC9p6*GS&-M|SiZga(E_TDt%if2!Kd##T|q&9A!$oCEKz<_P(qGpishZ&LN~
znEKY#Z_3wWsL)B&C(7*csssn*o)u+`0g|G5)-dj{9#6)fv5wPEobWkz2qU(6(YEi(
zrb6d4>qQ9O=lIBg8kg_yyPOAL%gDJxO~X*9FE-v#?00=hlZT$WXRR*@v?vG~Z98ML
z0w3&`<TTL!yrG>g)c5~TbRO<(etjIS>W>bjx~vebmKH^*O;XhwMbVnI#ok2hptPkW
zMp0TLiW;T1*sF-0*kad=5vz70 at p}J+=Q`K*oO8bC^SSSG`{m at m+m7QoWWLLwt_T?U
z>S8(hA$9-y&DJJ^qJtNUi=X4eUl(_3c#O;;eJi_}7ft!pHi@?%3E38E<;VQqX3Gfy
z7iY!@H7R{YCm!xf@{H*eM5G$e#6FyesGshQpgkRFtT~$hQqas8(^SE|Z?*aJV+Nz6
z2CH)$_Unu%v#E0+X84>oavH3H0Zmg>a7`8j_1RESGwDV>^2NNz?_D+LE=0@>WNgKi
zzdg(*gcvi%KwepF0vF at TI=-7w9wXGK*nmLHku0{Fqwv5uWjyRvG1rn2w5xWuQo$^+
z=@vYsrMH(Zrjb={Q1XKhzJ~jdQ>p+X-CVYu)~#?L%ehyv;&8-GW-mY*+06ZF=rB#j
zRKPo;B|`qo!wc3^2Yr3d8as7WT>SCZhMIh18toR!GCCA9-b4FOdWC~L%9Bw6UqKiM
zbEA&E{a#>NNe`%5j_}~}gf at X`XyD-FGa%jaiHF_kUppq(7Cpi6JtbYed$;|6j$nDF
zU)1`tM?Di}(oZ)5sg!O;g<V<{+!2!0Nw96<FATm#QsM?K#-KW0asDosXL`htF_E5i
zrjTZe<zV16O{MpeCcxXwY=TALMS)c&6K{y at 0xQ1jg=_jmS6pjXr<KooZY&ZN53{n!
zOL#W{;9LXM`Puk1JBf3Bqv>iMxLtD%w1albGH_dDlfC=YcU)NVDQzl3Q?e;GG4H at D
zVVKU7{1uy2Hm~SM_|DwCcK=X@&byqa!-tShN2#ZPZ_S*2cyh6$ES0s&R77Y^-$DQp
z4Zuzz`0xq8fyQempQl!K-cJMzt)D{g*-C$Ap0O@(F4Zt+5e|G{nD(am>QHrV$h(~n
z^K9vDhARQNwEMwh<LRuF7N_5DBdmXpNXv|;cN-~BL{xkHZVUfCJH7P|9#q(DYJo6a
zlCtZHZ1Ccua1_!K+l_8a9ea~fpyDOn;JI*Xz{|;~$?IxULoysT3VFzkcAU_!--Vm#
zW2JAt{Nwr5i{}Gp$&8+e8ttySNvhf*6G{#+4Nae%ul$g`8Go{nxy1dg-X;}AYP0Kg
zWGb_t-i!(O(Zut+`mdC4+M){Tw}cyCQ#D?2C1Gmv?#7j|yE#c4tiz8ahN^(QD*-3L
zL~GM=9&TsifD&P&Tz!(8#eYEZ6zby8Z;0mWQ|AjVxD6ll69>q#fk8{(*}PKG(*KM~
zFttZN?@@}D{G71n(CriSgH5B_(~wm^4{X@{O}H5+?FKwofjqYIrg7E*u$ct~g0P at E
zW4Re`5ucyIPmrH5`Itv|`{zh>kJiH96}@MOufMG0(ydjAyf&7c4Q-dlF5$0mo^O}g
zj7wNq4zAAUz=sKmLwssjdHNOX9lgRf`JTUfM!tiuCdNAmPak8?@7jy}??_4}>gf;c
zlmV~t;RAv9h<tF_6gg6soGdXQUdp56*L2nxUTQ+%uq^fmDnTx^iRD at Vy4Mn2AOA`q
zqwYLK-vAt6scc)Rcq6#?XBb)dQ%n4D86}rzK^$-Mq!CGTq!g{=M<BS4GNfS1DKKDO
zVI8;$uaL3;OP7n8$EDg&QoeJE+^M{I<=2oQPM1d;WDolp+xL1rJVZSIoU}U!m{qrb
z`{0ae!jQXD3LCX+?zQ at BXr8-%8 at N|Kk at I@*Vc@;9eNm95&?bCQ?M>jtJV5BoRuktE
z<?X5 at wjd;wvn{tIl<&@<z2%uH;~(EIC4G_(9W_l8BlPqsLwf;i&Tq?#({(93JO&7j
z<`yr7XEDnIXM-vh at F+>2^%~uAm2|e!xAe6lo+!e2g)M!~WGB|;&8G>PppQvoTMw48
z9uTJ<1M%A7@=6rl<Fq#+o0i7rEpHG6)4ll>KV}r1y}-rexVw69r4x6c;wN`6r?OIh
zXs^>;=Y}PN+xFAY!+7?8rE`7#v4TU4U!V`$q_ZBAFCpJyw9_A(Xb0Z&=(|SzjbBUI
z?&1H%PV+#?z)Zq>y#L(~DdzY+^DCB at 9C9q~9qm6y5#|bG`JrKY(MM6 at qohjO)ft$%
zP`Z7i{mgcButSlq8{9j*^Iuuha at 2(f6rH0Ie(Gxu*fMPk%qPNFAdPFikM!-kLJE at S
z+CNbTuI-d<v1Kc)Jj641!UqmYljWO2sh`QpwuKL@#+{~u+)twpX^w8Elf72(<RQ%G
zn`;kE@}@Gq2UBo#pYJ)S$?fX#qzIJ2AAVP=(O&RKRBr%STg%pRJ~<*D%!bc0db#tl
zpB-PVCFfJOG+~2a#vc*sj7Y_9qtmZ<iTzr3J|ig_a*8X`z`uVl8EX27508BON3p~d
zxER)zI$sZ^^|ldL_F)+xw{#g1*J0dL2V at p}SfD1QU|SPPA5k(WniNnoOg~4=#F)fW
zNr|+Lny1WfIk|8PN`1yUL}!{!as1vT3&r|}m(g61aDS&|>kR8+2lS|^<MlBbvFzQ{
zaRfvVnZB#JElbVzA3Y>4RI<H3z!EE-JeH1pAxu2-=kPaa>go^b`XaDbnC1*5ER}S1
zr1=D64&#N)A5RIa(Pv_9v7+J&Ms|b{{_*cd+c7r5XD8l*CbXO{o3Tx4aHx)A)>tpb
z4ypnw`}$`t at 9c=#8%RF5XvsrU4SG6Jl~F8(_&pq=YJ<J1vjWGWT6=iZPyz{U#e%66
zVHZ~(nSWkrIY|(j54|m@>ho>4yS(Q&@RRuBH|lqUc!<IgGk9W1&`bystVUj5NzK6_
z_^1*=-kXoQdJN|}5uwKqRY;M?KOhW4oqtN&nvV?yt^;sm#t+7)`%6@))2d-39Eb1U
zbSiJB0s6EhW1Z-e%+kd>DFSNp*@_0#AtSVFq?9rxlg9V8LzM1%TOCg)U4?}UE at jj&
z3x?BQmD|@!Pbf1lLWJ+_FgebBOCrI%KzE`cWoXrPBSEje-PnSU=HVL9nT&|p8gr8K
zN3Wurf4e$gFz at ro#gZo=od~;er(vY~1f+sGUAER{&d|=I>i^aJI{3*s^ei__pYbWf
zH0kp6jz?({-vGy-y9T_9(z*2?ub;)e5?*R!JwClZYAGkX_UTFP_l>6(Ns5(si^!GK
z>}S?~IqR31I)CkR=rOJUg}vOyOdlacq;pRU<TG8p7n`#Pceocmr)q`0#uPQ{vYol0
zN9bJRrP$udt-xmqP6G~jMVbAR&*CEz`)bs`Uu%wF`^i*v6Qk7Ju<{#7&Z9H#<6eAc
z2%tQDaE06HtovMH3Eslx0w6?xn8Kj{0&wu_8vV}ARnVSC3h2rbd^fRn;Uk)+^WP3f
z1LNq}iqZS2v at ga0R8n!VU+!F=0$UJ%E%x{;q$$FEv^QN`u+2vfzasE6nT=5(4SWSC
z^+p#4BbG{HagG%GoOG5Ic5cr=v!*XXxNR_~uRL>X;@ea*#C2|9;k at E`r8j^p8!(^B
zyC{(lehX`vo|c>&w-E31n~9XU?kv0*irpNTAa$;0V=u(*nM_>pD;1#jtv#!ns`eT)
ztjbeRH#9*z-tUd}viG8z*?wqbIY*CV2bJVCRzS#imkDDgDb)S==JVhD;pfVqLIw!?
zL(y@);`5Wgc+v~5;c;<kG%Q-D`C7<YFk=rbpJL88KGnB*L8!^_WUc_ff(zG6tq8jN
z9`DpN*JE6*<7%~z+>Z~)5vgF|sIFs)pm|6=HT_Or4@{1V(wrFAslM;6spxAaG-#ld
zA?>4Lsu)tTAt!cZ6-VVeSzf)5{esPf&8np{HR_u-U*!AQmmfjiK)N7_H5KXRlY%lX
zbj~0bzNu>|uD{9^<H|g+Dq?vBz+w3JoNTK0aV$gRtkn-rFS|>hY^Ps7{FqZ7^ZuUl
z5BCQGOS+TXUSUE8AJN}XO<!sk=0Z*CJ<D2Yx)$=ukb-RmwzRx9V9d$rNiKJsQ&A6(
zO{<++QfnAv8@*!@YBcvlALAX{2idj~Ra%=-hx%+tGTp)Rz>hJG0x6=Gia6r#NAfba
zhAV}`C5RX5xLpfqdQeh*jBdB`$&zSDJ@@R{?;zULSGJ|SjHacq+G13*lYe9XgEt3&
z5!nlS3NB>#92y1q1a~a45>}=H`;21 at +L93{b6EewK^GiEPw4TU<2rbcejJi at HgHEK
zWL;>|{h#jB5~GO+!%}u;QeMgm(w*m6KePu%wr6#3DQ>gRe at ***@9xR0z at N9R65
zoZo}FK&!i!^nB_5XjK2l-hIG|sp`kMIHdMa7vd9`ccJC&)E~n(-(Hy(b}<6%!fCUo
z>kfOKVG%AEN;M-Jog7JNKdWM{D!{9|?nRqG;d2Ou^MW|+doJ+_^1N?vZoHh{owx7B
zB8jrSzo`*_emkO<jS+O$*%&(dY+C;kEqn?N5-;g@)@DZQHMdX7kFT~Hr7rILqSZEy
z+EMr4RB~-<huEH}Sg2zYx7s$%IuDub6$@w+TdRzSX9jiiY{~2bfcDhjnv&<IoRpN$
zW!2q4TVum499;(5O26|lZnxosW6%el#D*vH9qL43JUJ(LO#mx-6loo06^nA+>PqP>
z)uJ8{$_H)pVo8Yd2{y=RQw>e8h~&SrD?9p*3~jv*WrTr$*9b+v&r(Btm%vtYmZ_E4
zH&wT$i=EGX%iLm-CdimwkA~jMoMk^8RGx`nn6*l at GLuOO4FYV*jX_4`mI!))zjj99
zPcmx32_NW4*DkZAskq($#oWc`#@PFr8dngZ>yKX^4jeUKvEqAzjRb28ILWQCOzgiv
zKEn?{@9;B3 at LV=|I;h1zbp0v0A?9RZx&^oTcSL^QZ0*FKTbesQE1{de&Hn2rWyO;z
zHPxmrz3F|`7#dvIIB!G<JBzr+lB#!>-CPjTA<e?aE<J-oK?>;1F3J<b_HNTKr=Obi
zPFN@^cFk+8Y>B&C*3;qZZy3#&4*unD&~Xq7rut?>g3VdQlcv>5*0<`OLMQFFl4CSn
zFXsH#JEW!ciw?y&Hva_ah~!C>yks<X6FTGN=U)2YyZ3%H1<HmH5l0l~ZrjKB<KAo8
z$iJfwWQ@>6U>8{!Z(RH3KCq%9+VL)ujy08!fkc~wJ&_?-Ow`_3RA1yP2zOb`T>l5x
zo!S_IL_-dmFh>*a$R;K7;Wrk at 7t;2GjNN2x^r-1_Z4dxHW4QF7e4Tp<=#GJQRqd?S
zE9?u;jW+I?j+Z6hfNnJ at G|_#;f7zdZQFP{M)#Bbzi^aFSwXbYFRNGe?KhxYd_J445
zyU01-b=5EYx5eVc&@?27$?QE(ew1R<BaV#>OZi)dBjHa{_Q-Jkxp&#_liRIGo^YT&
zn&No at -***@OH#7gOPyEsEU+5eyMUB&oxi9e}m`d$*xsR<bz3HWV1ccR8&SVDUtbAfa
zK(Jvwl9Qhc$NZzbhvTV8PODKDo+Ue-&(Gtg7~6FF<Krb?Ej-ZwE!)&1%5Z)vz(Y1b
zMm}lc)0H(~!q@!?gfLcXrf?Sow1P>bv65sg{BdgO(zJ5k6{r4W+ at O?zvcNBA7s9^D
zU6DIRrvGxwCM(@YT&BT7+^6aR<KDJ8+jEwNq||>|o709mY~8g3D9<)G2T)ncW3JFw
zvg4PB6ie@}y3&cSydqv&mI0)N6I?R-=(=dPNQ_0F#qZeatMUWBFhc37(5QXK^@zTv
zFnqrSr?P<au7K6}09Vl6{eVC5Ac(}N)oN{L;ULT6NK(I{58!ojC2|?ViWD^-&#!hW
z`L6u`+Mt4fKjfdO$K6ltDkAlYUfrV`e}+y9W?Ki(wB}H9ZtMA<rF&|Qvzix;t?2+`
zFHY&;MR(6?y3ah%`tTMX_0e8);oxG~E!1PtvLTBXsMrK?X&c+*Vg6R|oV`@Rq1qJ8
zG_p#>`q6mTd1B|#Z$LV(^>#=^V~o$pE5|~T2|=)yteyHF2b(%MYjV$QXv=<@M^4|(
z3y^X?(&sr+=Z<Y4f(_H)B97bhV{En?Y-61#rz!?y`KS}9l-uE at Tu%csZ{Fi4276h1
z4JVzJ$8xolJLCU}2gT8hO0 at Saun|0br7PEJMRANodCzQXkwQ~O{pB)k#TXQ=DXC~t
z$9IAAjF<c^A4b5Q?+J{Z!BQ4i<0!$&(+D=XFTp)Ehwg)t{M()!)2<Gio-Df at eTOHk
z!jpp#(+SzmXaDAw2Fk*xl1;<YG|YM0I}E=!H%QOctk{%~4vSu}<aK(Qma^Ci=6^1b
zWeVit;APJ*{QHIe4Z!HJB4cTN&@BQXnWyG6WWx%|FN{^7*Jbr4=RBd>=JharlZ^kh
z-Os_Fttc7Y9nbc$oP5bAT>YS;f7Y<HMvXvW-E42zFa?+?#VY5eRaY>Rtrm at 4S_+xB
zxVKX0(vf@$Q=BfF&T}nIW!zLWCeg)CmgdG)8C5{Jv*f_oyLO-VJeO5t<Pl at Uc%WVU
zLUc&>NTRViq{H-xcM=GP$dbLVj;f`w$$|T>L2IGYVXsyOdR4k%+-CMD(zVXA&U~25
zcN%l5>r%r#hzr}>HU>XJw~x4MGG0cHSzdl}Zen>PJ4$GUh`Cdxy{Ds6?`kvsrXKad
z@$s|hyCYV8uB*r1uf$W+aA4xYy!gr}NGyy60RI$xP#YcWC4xZCpQlniqEq*Lr6N*!
zUf>4;Z=3uIKVF(UJ*+?Da>3`F)AkH(Z}vhiSIt#En9RjOULQPrZC@!cd22x)`O)X+
zMxI-Mn0=rrlQ>2!xSjKoi469frM&7QaDVfG%)-2b#7(6C^Wr^8*<$u7nz8OV@&qjq
z^p4g`ln|#iqB at yLCMlG}PWY?UPenuGRiwQ>YF`odj@(<HkRbE&fOoe>h)KEUgiVSM
zP<!?Ml<zVdBMay)g+c7p8R-=8Dp0=UR9YhTu|#b1uk3_PmSS)fJAH0S+X3s+cT7oA
z-T0f&eGfa?^A4OTmZvw4!;Wn|lFU5{O(us9TX}p{&oG|r$5^W~^2NV0uP{@Tk$rsa
z#Zmmfj7<{Lw<C9dK<3h9ZqZmvb@?w)5jl&xNi^q3FfZ5Qe)8*VczhHyuk4I6gXh69
z{kMlx`|=>NFzeMP{?^v758WRYermN`X%7`QisOo^?^{lCiE_1g6i0Vx`c5?>64m4N
zQEa915yvunOMd;EaJQV<%DKM{7i52|FTIpbeWhYz2Ku{7Pq{;8f9G{cDFy|zh!KWm
zz)*6ftIK8mQFNso5a2y|7U at NQWpiEWYUm?dK36xtBp2sO4YyZv<f#HVmoz!xVv)DZ
zfy_mCb-|AcH)-YAmkdVhHP%p<SUDN#my>S%^uKRV-;~d}-`(hP^*(%2wZ(=gzZuou
z#2fZD=Gwum at 1#YegSWiPQiF9&1@{nxBee8!shmT<@`OSQb>+S9zry{Sv>PtA3{~2_
zY}UY3*Qm$C!DaLBn=+w&x4o~KwT-PjgR*@p?XQj8Fm>50UAcE^g)BZFI7;)a#HIO8
z%IC8s^`W^s%?&GW(%2WLNS4uPADxbDL6&s0i=;h(b<98c;bT*9FS-=3II;9o)P_L%
z91hgTi{5)OD~UtEj$^R(NUG^xr)=AF%PX8nEc at Jf)Q0G!QLp&lSsi at Bpl@&YTaW`h
z+)BBA=8<Cv#g+($jOUz6*v2ePKBcbJ=ZeNiRh^;yU4Dg>m$0Q=6JLvx)3f`AD;_s%
z?wMv2Cx1Q=i7hzKd{s9l9<tg{V#$enC;cAHB*91JN$L46y+lankQq^F9LzWxwBp}K
z^GbdjaXxyI=6Xmjk_uoCS=24jFyH82#KFdb1^3v+i59J{2ZB|Nl3z!)_vNiY<Abf6
z7ciYFgzy-RsSDMRQi~UJTVmrgk6aU2DPt*PHCTcS&oVpLa;@)$!B^XD1ETwQnHWhG
z{L8wCUW$y)_^y|BUZ1ly-}s4y7pP`vfvG(2w#(+O?BtiI<3Z47VR1Kk+-)Dos93Z&
z_4df2c|d>&UO~YnSF-zigO7=)LFW(WkVpM-GIzm`EbuCr at Q{u6G<FZ~>*<?}O^5zI
z#{zp;zKZeDuDXKIhDUU at U^>_?=xTh61gbV(sao_2Un9Ir+~GaX7(dKSkgHJZL6`cp
z)Ysw5e|Z0dhWX#De#q5K<4A4tBj$QGNRJ_keEgoS;Gb5^BhsZ`<DWcP*JEa?dv-k+
z9uck at K+s(k at y3uo9+s~~0g+bCb+d_CZPY1))hGYwj;SjCSEY5Gn!@r3X at dq$*kQDH
zXv}AIdXbh7Bfe=?^11q?y6B;UB!03GPJkw(u~?^|NKo{HCDD~XK#aILNLcNgQOzF~
z$ya5K6X-E~am3)6qchAr&y~6UZ>!@8>e%cEe9So)vNzMrO0!6B&Nv<4q*@%|{b+{i
z%{;*EW(WLIpGn%XNpR`t1f+_)GV0K<*+5fguJhS*t~|7|K&9>~vmB|ce2p^-Yf9+6
z_wEUf{=mGW-PMe}u6Zdg9W&Zha}%R2FL<Zcic2v=19&me#a)kLELA~DpxT9SBzp-@
zy1v-7SqrL2ewCh at IjPn0t50^qO^5QFXCZi_8C%b>*flS}yU0aUA=>tTD!#Tc710#W
z4Ug|u=!<o`N>PYUnbS}SM40PrJihYnH`9g-5O&Y7=o2_$fKEMivb)AFmX*@2AB#z#
z=+M0Nyc0T^Lk5*!N@{;sJv>=xjlwTlX5#fHOra-zO6iCffhd@;e^3HDC2i`na}!LF
zle~eBWMh at c$Qpa|bGH^=*@_?JaY5zu+j4~i#C;IWK*;w+x4FDXZC^XI`%<tfY*u3A
z-_n at Mx^k6o&n`%hVsQxZo=}swpQdwUEA0&WA at 0fu^h)h#S~q`>myo*hs3J1JFz~N?
zb(LOMcnS{|`z{*Ue*kjzBjD`}HJ~p?ryjg9(@#w=aF=r<yO8+ae^E6yqc at W7d<v48
zq?MmJ9`TZpI-AU-z+<aer at SP^ql2b<V|ZNISC+$y59Ph^e(t5f-onW=hy=MOSlfbQ
zkpvm)ET&`+yg at I5?MEEZvBhUD?#&x}7v$T{9pyq7nlFM`Vd6RySD%kQ7q(xv at pvXq
zxpZ5P<Lfx at 1+UDAR;eL}0e2>TE*=!>>e?bF!b4#)gyE;749rVL7u;P|u%HqZu~T)0
z$qU97 at gAXL#Q45!Z9M#GAT3*o=f-icN{?1dUH6`H+dUS==_f;xqhdd<t)AoPhi^+g
z8UUeUlv3XDhLKA1Y&6m|Mk$r7gUE5HEcuUr%AT&L%!0ykuSD(4UwwqB*pbpFh+zF2
z=mI<F+Xipp;q0 at qJXar<^l+w}ea6O1e;eKjUAB4`bF%y_tBC{X0}lGKlr_Ni^!4!b
z6-$#3$iWhhY!Ao5&1*2u#q5lNgwpuZvze04yyKp&@!sYUA`4`~Z at D6`X<A0~Voosj
z)}ig8Hu>zPv4 at xePH6x79$UaV{9~<C-Fx#zE>q+C?XeXxd5 at W<GBeaCS=FW{AD&c9
z=Mx>=od>U_Mm0TWdW%t^WKs1}0kol<DO|q&gl2RUObG;MS})67lbO=2PEF9bfE!f>
zpMUM9&o*1F2!ny<n;`+a=oW%4&bv4U-riP(ySdo*nKi9iLPYlKwQ`Z)XvWQnh`~IU
z*a-&7EvIvqe4z_ at AqcH2YP$91fMGC3XL7tL{#+lP-FmV)$Sx#$kd#)T;QqHRx=YTy
zE~FhcK at g2|fu&Zc3X>;?1z*kr?E_~0^g(+NY1P10i)!QY{$!p7IPji7A=7L*#k*z%
z2Zrsi+XpKeEx+q){!%dY9f(}yNz at Bjr`=r~B|M)I6X{R6BsDXXVU-%K6bVM6hx`y$
zD#cMB7HP|$@5XxRns3;oBAK0#t3YJ$?)G$bOgkq=hUC1n>RV63so at bD@|2F?;^3&5
zPJ$pe%su{~8zBcDcPyG)D(-C^q<Lz6qH6rqUROdei2Jl))DCnX97#NgNVmiNdo4Pp
zYZB9_9*2x6i^SD8ML_b2Kk8-JN;E=oUulobpAG7{&6!GPi3h>+dft3ceEpT>*S%#K
z!eVuF at 6I1W7HBx1%$vO}C&tOld<h%sHR)c-*db9PUW&~EF}`5PX)17{i&8?R?i`Pa
zHqB7 at N?pf%X at bXlhtr>k7RVz}?PJl|r(cHy2so_rTo|<!jQtUDjbZI}oU$}i%K+E@
zII42(X59<k(7Vrw-a4GTM4M({ev|R^rqkq*$1NFV`Vfm--Gibcw{F)K)Y)+5nP0zD
z%X`-h&9*qTbet=eGB<wFH+j0x!gU?rbvR)kqkZ6Mq!|%2pPFXqabnr0e<^i2M6Q$C
zBDtWB-d5qMBR9m>;z{oUOY at i~9#&TmPJN^CZ2rb%nU-w)!K|KTPA0gOepMvxNfV!+
zzV8DsuyCmUQuuPPwYdq8sU7p*+LK?Y5|x^2`1oopNTm5^v3kP>zg at qvkaSOWMis~3
zg<Gz1181HUtcOVj%W7jBt_6=jD*8+*oiRAdGjeT4SrM3L9i at RLnACndPL6PPU#URH
zzQc>NW#8;;$N5~nF_pL^47rU^*@YJIV!Gd{@+UVjx;~mOAqX!XE{xuon^bLPC_I+!
z{3>Fur at 9YneBSo+ZIcTn`)kZK?;wMXobp~a$MkF-^K}VVXLP%0P{3SFQP5d*J@>8m
z+%Aq;^{quyv6gO&=Sdr_z~{v!OK(e5HHAsv`wsK;<PC>{E3~wKf#TFZA{+xrZ;lsu
zl<UlGSY(f^_<D040w*9E29$QC8SSQIeJUJkdZ3{O`a>v(=0jRsZVvpwm92+NZ9j1%
z#;IU~9*q5J;7 at 0DHqvK|Bomvy0;#Lc*CJ_G at FcYYDgRRK$3h3oJ^@qNAS6CBF?g{E
zgB}-~{p-ox`L=G1gxur_lq{b6Yg%v1+{vjpwhqU3gl$O+ at oZ?X{RYUMr`3+2erTKT
zVuugH*$c13ps=wwFOs$q>pTt~2a5Z{M>wxnSe}Qpt55m3u+Kdgte?Tc^2%7+GFt~q
ze}$@um!_8qN-!HSB`~PdKW}z$(7SrO<()Q+eND$8`ld=977PBNRT&$6H`HMV6)Mzf
za8aLl+3BntDSo_6Pl39hw)Hi$(9jP;jB{*xYy;A>gDcgYEDS<<kjZ65sNSn}rYWqZ
zW%-BxoO|?CrC9%0J2$0qj3^JzztS7Thg}hT2tGI4uZrT4V)-JempC-x*EjdReL8ty
zW%5Ue@*uC@>&;-7mWoTxIRA4tJ}=kym?-~XfQd=FR=r4Y&ex4Zt!7MrhYs~Og^&Wp
z-QCZ>#=DRE`@5-%<&9A0DW+dw=z#4762c{m2IonB17IyUjFxrT*e((@+$|=}p9d^~
zD6HTxWTx5g4(IATM`dN`fIcR{@n-mRO)HPy*-IQgt+4iPvaBXteWi{tHlboj{Jy7k
z=vlRU;17ZW4v#0*xH5weUr<k<&Mtc7;(mJd0an%&Z4?>JF#;I9>uV=}ZosZ^S!=!x
z2*a^QVEiP!n<x5GM0wl_Q{suiUv{%gV=b3{yN at 0AgY$icT~*0BhuK9WGY-Uy#vEER
ze;*BOASoUL#{E_nlRg{m2;c);=i)<cye(>Lo*h#te+xjQ>zxa;oSb(FB|=`p?v~>(
z3Sq;ac7)Bk<#1%g_mCHfNaea<<1ZB4(Y1f2G83f8A`yc`s|ZT<gjIHZ<5okD^LvoN
z8fucID|jTrZ`DrW4M^FyQnsqQKX?jq9Zg`Qq5l%t{+(3p<@|O!x20bYMLMn9_4|@~
zk7U#3K;X!-Z5QasxZ1fO(o{gm34)e44jy??p6;s18_2|5Ec3Pm5ZmR|!?D3Q!T8{C
zf9kju+(bOO?CkDA;LA~*wJ~u&>5~lX1-0|&HfJ)F;I2`JtoO~j!TNf#i4VqWk_L0v
zLj!Z1(3RV<W1<hd(dCDN#I)wuYtf1t0*9h7(D0GC&D`+c^Ck@>-St&X{7<ms&P9$&
zKXzR8`g*4OkFgKr6S&ExwTalWGTk;TyBI(FW6^73vV?rk8~NVUE7t*x3hbFo{B`at
zZ_P$n-R$cjDjviSEmAA2nT0Ju!2<vqsHgd22uGiPx|%@YDU8b0!0BE6v at l8wwhCS0
zyvB2&Wu`1Tf-vn7?gR)}s4y+IVL2H?zHn`>59BjS-8eYUy?HAjj)nd)yir$$Ub=Xx
z3H!K3LQHD*3TXm;h+g>*q1 at 7cnXN*?={)jRQ3W?WHb4`!nGc!%?Q`J-Wa!7!h7o at 2
zP|!Bs^GaxKj4V~^B1cc3zv7n at p}#LOtp}{H^Ko>s_tkBxDeAf(*G|UqocgA6Ktk*o
z<<68XxKeo#TjQr~h8|XTQe(2YFA?WgpZ3A5CC8stec~$#DK98mpOqoQsW)*mV^7^m
zSD`a2ob~<hTv=)&#qE6So!h5Zntd*%PO)sFhPOB?errv!E1XhpWt(D at tD0wVU8#qR
zG33#ek=fkzD$idieN2bnm(7>z7ERXrG0$h}<{Ovd#%V6DC}dk}ZbV~C?)8e&jD6*p
zA_>Y}cusfSrIo76lDt2np80DV0)$CxP@=!0B46j*pZYdUJ!sv7MB at Yhm`5mgp4pbK
z279DyS99i0{w;(R0N}+Yvq5*(Q+}0&|3Vj4OZ=KeKxUt9M!lx69D;3;OxRhGO)8lu
zp7OLimD0KY=+yqtBZ*`DTjcjM{A7lAg5q^#Hx<T{5nufeVd`&=;L(pr3vV+=kUDBb
zKT8T)#}#WB#a16nFQgW$nkKNLYXx+~KPDt at 0ug;Rv-xHFf*-TcqdatJ;Hr{Fa+9CW
zJeTu7rwu*E-z7kbMYN(W>Axd{F`#O1t}0G4al_t1xy+np1yOm=_Q16CcZqAGN_`!A
zxaxduME04Hzyo05_W<<hK1EE6XeB^Qf`iYl5>^3}^UYUn>V9GK!i%9h(o=~+lMnXy
z3+l8k!7Z(y-W&B45>bWDGu at IetW$GEQ->~q-BneeT8gdSlt{bC!tmdl0-amYA62*+
z)2LD(=hWH=mNrks*zYi3MI3!{cm2^HbXRBHJ6Z at nto|drzGxj+w-^+`{5*t1E$}*b
zK=`0_nwTcT<<)m}QM_VOtLw*$5<_3<k5Ik|<0voSR<d$)Y`*>ImGboJ*Be8ae|Ntq
zMaFc!$YgpB8&0DiWZJ2mllCMm at ovQMzV}fDse}wvbNIcr2+ZVwqsodt at M5FOwizpz
zC3;yLuJ!WYNoESCRL0K3D`N*J#e1)}mj<9jUPkDbC<%HYtk!Fgoc+}FBU_$5)3DKn
z)^H!-XY7l6SD+*8&&08aA$PVl{C(J~7{vrWes9cC_j+So??D+iCS)}``hf`B5i{3j
zf+uGk+J~^h3fG(pH)}Dlghoo#T#nS}nCn>i at w2tqyG>_ei2E7OvXLqwuo5sP6 at vXU
ztEyl_wQMhSfRd0WpiMJbSCC8Hy>HdMs@(g0>rWE=Q)8>-Moa2IgYMY0LDlQ9RX|<A
zpCIi(wp5)doRlV4Hn+h>YWdrn+vUFiIn=`62_$#NqjYiHld&#m^qS61FTRjMXWgm)
zs<cOp$5X{o*NXOa%C~2hbdIcSX8!!59(j#HC)4~lk+3B5Zb=^OMX8AiTs);UfCxo0
zo^{I`kNPLeeRS$eS1xf1ELEkweb at 9;YR1*<ly3}mV9N_=q*_WY0FI7L<*!$;w>_D4
z)I at u7r<M7~?%wvDFwj1?LeZ9AY0ezpcU7>bu-@>06I?nTPR?W;{7`&lgz*T at ix}uk
z8Iv^sOr%F at Cp5f~`lc^3Mmp)>4e6g4R_1Z_>d!Gx=1~q|Pu;43QR5W}Mj at qhDHhXG
zTV+1&#)OGd`KmTeRF$vssB(G#-_ at uukOB11x$tRe^Z4?R>HVEgN`h{Ohf_^Gt$3sV
zZrDCZIOpl+9tvH&626hekjSI={fmK^V>r+I8-8Fh>9jWgzrxcF;xa|yn}n9u?g-XD
z7aW7c6lCtMKT9XFT?9`&iL8~$qcum=>2 at ngMmrub#&{4y3n7z)dqzc}9OMDi*46jk
zIy{MzgdZ6kt6c`ri{|{pyS3fYSuw!&EEF&Ock at e`+LnO*?2>Pagm}f(Cm146s245s
zt34O^kR93?Go`oB4O{q;Af;Ttrc}5q;JVn?a=SIkWiJP~=aadDF#dhc9EITq?M_n}
z3q_~?T*T1U!-j~eD>nU|->=<(f2r*SZiZu84)ZIz2c_eX`d+}7F`nh1*FMOERNT^a
ze4D&6_d;H?dt!^?0_$1N^~HBzntG3S9=__+60)`qR-I1cGRWCOE;-Uvy3t;5&1EJ>
zAqNnEILkZ5JD=P#B~ZO7Y<*U9UCi>~sG=GmErKvC&8^7t0lm(z<XSkDG^vNl<02hu
z$JDWB;}&kXC@$zC;&nRFktLk45~Hr*2Y67ALlkx7yzLziBTf<yn5k8 at X-yN<SEs@!
zLrr#JRuVRAd^Y8+^(2TC0dU{4F!t~zPV!a`m1P~@&jDhWmhzg;Q~3HLxGOxP>qm)G
z$&dHNf{O1$*hrqwub>5vd}k^YR|p{(DGbsf>d_LkgQzx+{IPWt8s?9FyBh);Ay)4I
z7$_8cm?niDnXw%*3~AjB#+v7z^8wa^=DLGRW08I5FTvUdWO}e at su>eSmumwuM$$%V
z9Oag79FMvaAPdh)T8mskSnGDSc8+$gc4HoEK1@%tze%5yriFOuiFM6v9#CEO at inKS
zaR_);$R2t#5Hfc8F*HL+Jj63m`(Vq(v$1SLZQt9^eFQQ$|4Zm_*i`l3Ji2*l7y(>{
znUB52A<~?$9tE3f2awK73iV3BjI-k2$nnZ5AfRLn^_bz6)D+H9ks-{QG8K4;5+F>q
z?d2zIE<>j82W<{}A7aJhLNDLZf2$n=FrIrkO!LOP!}E?D%Mh4iy5}!hdr1=dc;V%1
zMS$jcOEJwEQ-rcB3j<$A^^-lRmr at F1xQ0PlH!t=JhEJFNAXQ>M+0+^*kAPribhnZ7
zDV}2Am8uTXQ#UW?v-`?`x!G`^&rDu4w5fY$e$4)(ZrH*!v-`A~dx;bAhARAH>Qw>Y
z;A~<5Ikzf($b7P at I-8ha-)bTX5d0UaUF_LO(C!pn90=b~$UJ<?5Lh5WC+7YPXUo5r
zD@=+(kVd4sYOY_N8n{L``KcV#VyoHXl)?WZrf6R&3p8-e_#lwWggnOWQ!=9E?Qv{F
zQGm7pdKgj__KeMJ5=}i;vW90lO1c*BwXu(92z<jtrsNkbteCCTwZKvXL-vWy$TV2r
zfa<Ey{$->Dj}@)7c9?Jt6y|;xV<|B#eIq=wb{g1n^w)Vuf^cW^vQGuew_d;q!&n2G
z3zC$!od_8EXf#(@J;<{u9`s1WK<R*c5<<P`nbld$3iT?ocCiMAu_Q*0rYoz~actNG
z6U&15mnt)g&oGakljfSc9f6K;GZz~!PCk3n_LPKeUkkRg7}@aP@&Bf1v0IQsr3afk
zpNk?=RVIZZ4`q+wI8_VTab#1ck$00UQEuC}OS~xj;I(0;=cwVTOZE0o36Hht#f-8m
z!SbiRe8>hx5Yl3?HC`WR71Rxm7-_T1<@pXPAsogk5HLqohX0N8yxF6LFw*)Z&t4n-
zM50H61x3#p-1gMaA9IA%jTfP~n=2j at N^w&3@>zH-bQnnTkJM-gJKq{8G9vQBw06ha
z%(LoHXGO~fCGuz4GO1F9=J)e*bQvc`hZU+LUc8-8y+9+26n4YdJ(RP1K=j`IMda;0
z^(154aa!W;QJQl}(TL&`HKY?-X;YdqL3HY4UWwdLfga=C$syIhIe^zFQBssNrSo&Z
zz=<|ij*engMB$^=gZpvpQ|#jbF3vfwJ|-P`JVo`7L9nlr6b?y<{*u2G+L>5?%!U>^
zL3N96->5rIOjq<{N|aYMFSO~-04Lq;{O=-t at 70Bar$V;jX~6W#zu%X5-eZ?act;|6
zNA7gg#^HG at fpzj*9tJXW(cmy0b`0nKX~Ac9Fz_9&^>15dxbjVA4q>)`-K-C94sO?8
zp{woYwlVX#<)&sA8YY3-JqX`pdhTr_<KZ<uUv$h!@CY35tVj9FiuMpg!^x7Dv&|~c
z=ZQJbq4mX2*UpGG=9i0&y1iaWj7#I3v%6%;m#s6Zwq|E7M?vC8&DIvYou*5&0qupd
zeMlt>aLhl at b-s>6|I75S3VB)#SgN6?X|2)HLTro~%m#SP#`+~<>Pw`2IA at d~jvm7H
z<HWQB!-x2B5gt8qR6j!gC1r2Hg%D<!_oh!@vqG2Mfk()8D8Oh|Ai^yxzW40!YThXe
zz*t~{3y-D$tFd{(k@$i;Ux;+y<(|~Vv?<BtsRng4Gz?j6eB=-jkg2$v`K$TT{Leq8
z5pr!f$Fup~GTGcY?+}-q*mPI1B<izU_#5Fu_f$4=McwytQvP!GNG;%q|9haQ`=R8$
z$>$Vy`tge~z8xQL-TXNFgu#Vv<AE$=IMV!!W`!YvWaWnClqde|c!U+f^`_m74u^aF
zn)*2&7=5x at cTu&`NTYt1b0RplHrss!<SMwYI at 7&;wG)73svl)no0Hu`KaTmC((3oR
zgKK8n6V&DYQ-DGPAAZeaG|9boR=s~3d3OB%Z0;Uv&EEeuI{v>xh~Qq0%-HwMQarI(
zVm+yD=4jskTvlt at FHZ_96R|cW=pCin*_WQL50c*Jnn?^bHwX^3R<~=9K at gT(zXlJ&
zQjh6iUDF}ahob_CJAh;O8Sqp+kMuK66jCxmR@(Zu8Vjuc61a_OtL6~mPXHo=W0Eyp
zznB3EVq;UrIdrCm2w%sq_Tf$Wus|=@NcYoaAb3T3?8C!YvX1DaQvE7mpNXo<6qOQv
zoCZrSJ~2(GmXU;wz&)?_dA>ZCnD2?=8aFHQz(|kW+x`jq8BG$<cxsD%Amfi at Z4xhI
zVnKNSOTUkL`Qk!IPtDJoV>z1q(uPcOQw&k5xK<=xY)9<18aa30F&l!1oX7}k{!p&H
zi<^fGO-r7A(IcAZHiA-gK(rN0DfSLHl5#{=?Vnq83ql#$F2$2_c*!|ja{E;wd&3l-
zMFMsr((~WF3nUm%GVlCAXPN2%?j6Ms+(J7ltCC%74ZIY}ajE6b<zVqJy6%%r;Q6>u
z0Fmuy;}VwG`Q%dSFVelKE*nsmML`J)$>dtrno_!B8SR7~R`~!gW~@GO%W+)`5&{G8
zrN5NB4+k(JMl%^)XSdoL!eC6uVB2V*1ksr2H#{*QaBywr=%n at Dz{<ME&UWfsv4u-#
zNgnMt9>Dr+ZbxmEcZegQz(dudsUg8{^c+GP$7F-8vJ_V)3}ns7Z`D?K3!GBtR+ra5
zi~%QCS`jXg!Z4p|S~T=ca~HUlBl%dNHIJThBzENHOfgE+|K_fgZsz8JoAl3dzTsKi
zMXsrYWb_e}Fg;EuH*;yB#>sEc_YWq!YTAt|tgm`E?rT}6M`^sjEq(4ZQvFWOAm?Dy
zIpC9~4r%jsVKVPdq7mX_7y9@@WHU#uEgfi-8}U8K75lhP0Fzt$g(*=qJ~yvvlcLpt
zE8Jj~gps=(b<@3tBKq29(2 at RusC5P||4Er{BhJNWgzmVxc<|3M_;Q3oZ+WqzN{Nx_
zS}Z)u^VBA)Oha2S_w(lbpXbu!ismeopN|d8qJncM&$b at d0+#vprAwx&N2Zi~bOFsL
zJAG{@fb`nAm)szuHA|R0(?jLtjnGi~&|r8zyu4HVlQyi_UX#=Fa??#u`^`M7H>IKk
zPEw2~-Qktg&0XG(u*WP+6qZ!TmOMK^jc}0N_|NPRnK+{5wXM0L_ at w4k4t}(!Nfs~g
z7Y-az-d8_5mk}zee1Vw at ihqrlMI*$pj%jbG`8)#_`%nv(&XSIEYR5|I`O^=Oo^o=t
z_y`p}6R9f!K`CZn^MU9@=aQd3=Sqhj&%%2!<GkZ!ET;P_WYP4XplC=XK;Qk<6#2n>
zH^}Z&GdDT%rc5}^67ENPeuwM2nG9_3IWO;cmb&%7mWILnXckhn_LBys;9)u+`wy&P
z){*N)^ZE6jA_8VCxiOcsKj{APNJ8EWrw4bpjMn at oE|z2#B|SAyc?p%H#wY3)%Ow at M
zRnB}PUs~~u18Untrz3{HQ2#<j=)~iTU(Ftfi(JZQ+~-;x%sd=cVR(Y`WVyf_et{tE
zuxQ`N#88T-?nt`?5TwKD>7Vl>!_cw$O%<oAlOXDRhmysUi6bzJnS$e9<*wT}YUF0P
z5V5X&R6fl|m-R#)QbD0#`D!!SwGBM at fgVk3lb+9;agP9moA#|9Rnko=&5?ZNkEa~z
zofsSPCrFmUOiuJE&_0Q?s<qx17ngDk(C%O<J-kG+NmK#^s_|8k=%9^lT(e!(Lh?=p
z7u|#*<0R?eoyWNTODk!foKj)zKQIhKF<+TK^m}AKoeCBGpmiP^J?m(Q-EC)&4d at D(
zVxw97JnHN_h}WM=Am8j5G)!lFfK4R6fZeQZqOvrv=Ah$lRIpdCyoGxAA<~`Ykd>XK
z;Oc3ePJYjRFpPaA2_6*vXz`x$!sVVYPUU}ht2<+?*kpZdvbF=RWa-IrbHSeE!<M9d
z%Z at D1#)4rTn^jV961CiHY|)kZ)wK7e*V?Fj3Gahxxk9-=X)6aw$@9aIkB<k@=YsH8
zfv$%dT!zpV{>0RgrtaJSQrBq4K##q5DSeE@^-QWTJpFbRKtIGeW_KY0k2?M6#xoSr
zlt}c1p~D4P_K%r*Xgu(`vx9+y@#McZE2%ssj at zhGkRnrOlN>1(b2%i#CrZQ2ob)P{
ziYe7U*tD&XN5nSwei=lQe3i(T7q3#}WrvdHD*_dH*X`z<RX{kS!^a2qo4+%w{p_F<
zC9BHOfooQqB>_QBBsTs9%589SB20Ei5L33j`evJtXcqZopUaCRx-l>MeE_n^>H_dI
zI`U_YvNqe^&5u-%)`-^P9alMsN8PAc)#mKP<<nBWA&-6+tuqwTT&Qk~lZV&Bk3+U7
z?JuHl&I;6k`Tey1dEMvqQW)Mzaw14(H_fP_iGwGL=f|iU_nBpkdgJ0A%kIA?K4`8k
zK=wZmeUq-^D|Gq!1tTTium^0EEls9e85=x)SM!_F*Ed<O7?OpYpofqv%_2jbcez>}
z|MS&B3?58-t9PPt=!+Mm4&cf|cOG7Phxj{=K4s9RzmT4(XrJe&_NdJ=D{5oXs3e&8
zspno%L?(Lm&r1-{=fzBmp`DIvU3-J;p6q_#f4uwk-l+!~hkpSqNP9P><|K>M$ws%y
z;z{8Ua8|NP4b%E|_S}pVi;rjYm3`^`aAdgas&vS}VtEwOGv!)aN~$BHcpg)nY@~RL
zLF;jJKpVNy%LNF^RkV~;`6=@J?~p~=&eLt>vth%f0ghCiV?-a{ol_E at X`v;671n0x
zr7+|AXz4FK^|j*&yc9j_1N0&Y#Cg8oU9^<`%U->nH8jp=0M{uK42;lkuEaajI4R9g
zx?KND5h5&QqW#3^K=`Z0tOUjlg%Tl}r#T<ifr;cP7QZG`ylTG0ZWy5Hk_LVi33({Q
zk!VQa8 at w|)Qe{eEUYDC)yx%1mSiH7mgx82k3E*#&BFkBHny&u`n<v;s-v)hRmVuFA
z(0RFnCOSJx_~VUg{Zl)Q=HFxP<-`vcpwO__(o^^GEc2-)OlX}D0t-P)TL^=q#~jmh
z1ecxN)9-HcJ-U5kmnnFd(0qx$<JG)I<*02*eg7YZKlndBj?GSOR-NIcd}T!SQ<!H$
zZxg@^RjIuEZyZ6_(lq!g8?E7X0A7DSvtP2M{dea-a$BwF^Hjp3gUeH<RS2C_`mm at P
zj*Yr>F7lNj){OQW5r~L=I_ltV_MB(e*Rs!ZM`bad#br*K(Yvop?3re^$p-1!05jrH
z#BrEdMtpJLh(pL|EOL27bbnG!5l0Ut1lesK#Ck^9oX&rLPt-hiw2L+DnIA@{>RWh)
z$bL1l;4tyw{>%3E^jUC}gmOqUxS@}p6$-I>eFtVO+YMfGx=zWOkbV=+q*(_RI0=dU
z*(xIUkwu(WB~SLkD<3h2>Niryyoq8E`3HbC`w=oO|K$V!xZbN<sRq%;SU~nHFmM%s
zEnyUt<5;m~Fp?R_l#?CK4fka<*~7^DTnbUVv_8Fd+V8K20mpIXcbQ5hAWDU0H?zUP
zm|D=1Ttw3-|4MZoFOkb76 at M&0-CD at ***@V2jJb*k8aS*WLa=KanSjS>OHeBA7
zccsa*?-9|c`{_%Qd7wL&%yqcjO48nls9x7tGU`$DQ3B!#j`k-eAh5S-AlB%XL37)y
zPSK~9C2e-ezl*_3AF4Z3unjv|7L{yfz|6hUC`suQ(Z0p$$R6e`s+NNX^^(363e<A?
zJN{gmckZEDZs=1z0rj}P(b@|5uK>>Dg2+|`{PeoMoTUz0wvJ at S)i5=;J!7ojY8s0~
zmGKB8DhhKRufOd)jy%V>?T!D3idL7ng9`o;vP!IM#+5=REiuYE2boe=+ at NRm8tZjE
z8hx9~C;0?o9{iY)!WV5qEa=3~r<QFQ?0R*)TqO${c<~i^+Q%v?VL|1cnLH7PRSDp=
z&xui9Li|E-lO6}dNzH?8N^xh-sf7mjAT-9ks$V0FkQSSwK)waDIQU5AyA#{&HY@`Z
zLuTrZZ-itwiLG$7H at MTpNPHp;EuE0vJLhSJvq`BoNZD7AOL at H16>hOy?|PS|x<Hj;
zSbDa?#Q2J?G@>xNQ3AnD4sKsPl4NZQ14CxA<4AAjC_jTiA|RWF$co7H&Zvkg`<i<}
zX+{4kw!@vaOAlz*MzD^=$D$;KL+(1LT^gE#l9Eb~ZGzsO89pzn7_ at Dv6GBKYcD~^`
z;~5sl??i{p%(i&uTFRRUyO07vbum?%qL;>Az?yHl!f*;vf%g&WS&)^oK9!)g<fda~
z4y at RE%~|&9z;-EHbhs2Ku=WQ&H(Z(NojVKEmPxjq^^5bs{>g5}o>%S7@?cC-ce6o@
z(I3A*DbKuO%XMACFcPls$PP><k$!<Yy}7EBmo~Geu=};y_yL1I=1sJ%;U_yPoU`js
zy&v*FkPDLWmK5&- at n5<1!S&`)_ou7k4hi~}Awuw(B`4^S>vsLCCjx%l3~lq2`z$kS
zIacK|y3<`A)?#;=Y$gU*6TKgHxidB{X*xvh)vSoIsCf%BWGh4 at c!e79;e=6~IjCr#
z%w*N*79*m5G<mn6XbRd at ***@_3b@&PeD24qwQmjhu1OXH`vc3UuNpD2#qfeF^N<KKx
zDXhE at a<Sz8dUjfE(UCRU6)qPE*{7+UC9YO`_1aG;jZJh8Pj+*8a%)H13PadcO+rIv
z*yiW at uZ7wUgZa7fnCsGq7*!~txpZ6R6qX_8n-)kAUc`Tv4g~&fb>az{oOj^aQkU&o
zZ>=M**&ief+8 at V$uEcl$nv=_@)<Jl86ybjob3<Mee at ***@F|5c=l#tJ{9!s
zPFTTq`eSL)E5D9`nEw9Jf5SVYyo<Ya!bYCog6B4UMgXAU6wP|n at huG3p-IsX7<CZg
zSgen1=#*sEOSj=3O$_+?7&9kJ)+>1 at G=^svgwfRZjLBmAL$F at n{f?R&smU;xd4+ah
zwAQ*2AEN($d~urXjm4dYl|x>Mo+FgR!lY&Futd|m;zAl$&aEbpk_~W(EsJH6ms=eA
zZ&**j^8BA2jBC1TIA_qD1sZ%+^q7yO?JHMpt_KSktq at o2KSs4CTy%xO%9=wJ<G<tR
zTYPp|q?+HId2AX4${$Oq$vcyL#*9Fke2sFqe7Gy?M$mhl at 0+ZdW_(-cRp+bco!4V|
zMJLr7-)}hIUYz?ozkRZD)CvS8ty7};mP?RWqn718lsMb&W;U)3!q#eyPn7l66o+`6
zwX*-PNNZ&qgE*O8_#Z{*;?0Er|M4VNxhyFrb1(X)T$0UwF1eIYp9<wN%q6*-J2RJ<
zm`kZBG$OjVlRI-A<$j<0{XTbw&9>iuf5CRn&U@#)Ua#ll@$5kXHZ5H(H!W7KqQ+f=
zu>YHo-~1ChI1%D6lVO|-;&>f663FM2<uZ({JR0#>|3t~*&Qe_(TDb6T=JP)<jUTe>
zoSS-TpdgnV_<>?VjUeK4 at I6ngNYKBAl9Naxey`YnV&E8@|8FByo0hwmv6C`l_8G6?
zgm{E3lrzN!ubzS2ulFoeGC?Ioht|^dPi at r(B7<8g>f~hXR1Tq7Bd<+OeDmqF=AxGL
z&s63A*?%YYP$qC{^3-#Vujvve9jerd2hb#cNh_(ep1*IG<9EFYsg{p!OI at 8&@w!|6
zs>q1&<&n(6=?HJK&dR(krpW-Py4v3Vu5Tqs#$;t1YvdF%!ld*JC*DTgKTxC)Z1`$)
z at YxInIUgr6iCOI;AK}%?GC<wZqlc?sn}S0jG~52U=Ipq{Qh>s0ooM7M7?ykBo#dQN
zOaE%?iG}x6l~>c3v`%J%i4{4cN!TCHLDjkqG+Ue2pMGNB%oZU%-QHM*1%lw$pqr4y
zWRA1#Z56%}vGneeuHBAk-i23pPiBh{HjFV1N~>}+c!0mE>cB8#j-!|<yXa<jW|W)7
zKT)vm5PJs94XPTBy!%#%3Zrzwu_h>~qXUKs_4-j=2i##E`R9-$uxG7ZZPPzDVH^7^
z5&HCS+!uAVNY>7G#rO88`NxHU7iup#4rA2S>8s1WZM^FD`=G19;!)av9(RUzwqv`1
zRCwq)yNocj5nR~K7Y=H8fctI|hT3O?%$$*+vmFu5<wGtml^ZkFiY4t0dSnbjYP1qX
z4JbVS!u>Ht(g7QsAhdX_PgRJHZ*Wjg!tR at OIRv4y>E3nqxNE)2y*w#AxP^J!R*kpe
z$uZ&f$-4RJ{H&rIuZLJ^1TjG`Q at cAq+~UbZM~}RZd0cnNc50K?dx)wBnlx>=xxPSf
z<ec=5K;dBB=@attWVH;YqpqQ-rUkMVoG#MCMImk$9;RXZtuUoUYXp$Pss$J!GQ+%f
z6<v~`d>KeRde(lJ^8_&~x^QdWBVkyvcV0c<qkm5wcbG}rskreG$`+AOjjct^bp0{6
z+upU2mJevP{gdd<PZ at 1$6&~WNYA1xW^w=KN9EH&&5+R9qYw%&HY%Y>)zu$org?Kay
z?gZfy%tl4mF_WVj4K1eEQR~$mF5A_{TYq~;YqiJ%HD-2d2+Qk(_fWa<-oG^}`oB8h
zbeUQ&V at U1gU+NLBe}6RE&Og#lOhws}oz_EV{2#9vj_Onz=@;{k%aQn;6kFvA6<`0x
z>SCYQ1&pNXeilfxcrnzJ+U5Io_p+DEm>U8H*Tv7e1ZpTJRwbSIJl5Q$o0e|HCNAD%
zD0A!lPCw5+X0UKu=zOw at B;UU{!3;u$+`(VBi<mvdOSVtmvR&Y<mE^~nrz?Fnw- at Vu
zV42L%+a5M3Wx%`&yvEwHT}<#_BQ*@FE&q&6dQgeddSyvz1-)|3GQr-7K!cp2BPGf)
zVR-D9pax0>YNEX90sEYs;N1P@>c3sv&&RY17)+bvgEZ8_#1G7RSzH9`=Y-zB>PbmI
z5-m4}a?(HHXf|o_DBf{M9cn=u#%ht)P0Q?!N)eP>&Gu-%CZCrI?^57LT;jM((vB32
zyhi%psXhFSPyY*fQCIRi90{=R^@{O7?w!bhX{EjG($UDElfM;vO$-CFax&r;>IxXa
zVD((ph4Ktp9N*^mZ*7W+n(_x!D~ndYdn#^iN}^lmL{@WOK9oi>kzTcR8$mByj>4)k
zq??*n>k at +lkkO+q^Nw~#-IaVPyU}*$8V<q$)G`30Ec at 76+24uNS)Zl^d<V_6gt?m<
zF0c%Hv at 7M!{3m-Sx`?AD*KEDk<Dra9focnRFZaI-Y4t6?Zm$pfejPge3TaV9(_X(p
z%D}omRxgE^^5 at Vr6RVWwC4k!#EY^Qn)qwj>u6OhE+NXGe8MoT3llH6HW(c?F>$Y(8
zIFPYg67ar3=k at fS)Q7~*;N3L6VFbKAt6lFPx#1Ee?ht^uj)=cN(@xmnAVk+ZE*f_r
zmA%A&xnmb9KkCBu0&;d@?C52%8mc at xY2w;|@;n;Ov1s*ql;g%eQXm)BV!c&GPjUe#
z0!@ci?*E!rSqZ8ec{LR`=#i30_byaTE!yead0>6bHbH)L5`&p~Q{RVQ6)EN?KCIv!
zS9Q&q(9a$REW8`nBesJQvF{Lh)_0|a8ls+0rPMGqU#tF`#QmCi_($23^1!($1ivE`
zdMg<`F%bG=YguWcZg0S)tkX8pT*^i|#>0HyMyFP&(C}vr+{Ht9S1GifBQXDaOceHc
ziC^@cp2N#tzha-qGuIq{$7Q6y6`K5td1RbpTw40;K*K^`_6OtE>$ZlsZe5Jxs~;7l
z9&vv|4a#2`XT1o0gV=q^fl9+d#4OXR8j)Tr&D`_Ke3?meZwNEIZQlmh-8T=y#Cc;v
z5#S-f!B6AJ%>3w6;74 at HG5#VWr3WW+vT|%sx7ORRqjd)Qyi=;=>XBOE+;3Kn(G*6Q
zwTJgqYnh|nzIiFJ`WB_#KIe9c<+L}g=Rv3{Qnw?i9=!glH9dUtif at 9Ssy<xvHl*Zd
zV?+t$!F9eHNrJi3+U!H|JO)CULhD%@XI*J)g5UMl&!XCu0>aMNCVrkI4Z3e9IW!Ym
zdYbxHRKSmD at eNtH)&0q5v4s^aT1W8&TmGGQV3INajI)2I{}5Vp+^rI!oR2%X3<}-d
zZ#wNdI{le5S>k>u8(PTbcJznjkx2pn3_33(<gAt>a+iBOIyTK09FQUuD+2M3oZfWr
zs<yVV8nbr%w4_>fa#MMH!%r`vA=6}4 at P~#W`U&HPe4%sN;=x)rJUQkmP4irZE`AS5
zC|8J{(I4AlWDaFakaoksC`Z at XQ_Ee~(|jpH!}vn#tr<0@`MbC}Tiu%KIFaP0p^2+n
zKA38H=;(FylVrx!hHlrLq-_xUqJ;G_6?(4vJgooSo3CV4I~s6%hO*!}0jyRkC)rQi
zCnvVhp_j9(MY0(8YbV%@7sT`;|I$+mFh-3PR56uzYvrhQ3DDtyX}>!h at sqb7;1lk(
z`yayE^+4WRC^n$4{qCutFETzHrYo`_3WfH?+tzw#y6jU);l^$&FC10XZn%EhxJuKe
zWk0NKB0&MBE~ah2NEghgB at ***@G3hy3#U+`j8^N{4vxZE%Hu_qz$~7m&n0wT`Uo*
z)f9Jz1b?MpY(!`hX1vV!5xk}UGOavq%8{(D=BC at 8Gvt+***@jvo at ***@YJz
zfSTG~rbPN)zWE8}E58T5t8Py;-2!eJx^eCb at 2f1(j?dbUr?#HBBf1 at JRLkWF-oz1R
z1Wq}ht&_mK_PDxcaGAM&ad|z_d#F&-dSg8GZsIO?|A>@nEc>e=n}&}PPtFf<-FU0D
zlaz5m_dQ51W;VYSdM-|9ceC2#zJco_$)hMtoXNC-tyf=^Kr)nnrQv+Woi6Gez}vk1
zp3Ur;QU0_MGc0d(HgCs;$mYYxGpzO;xk@*?bSSe7)m=0n-NfuvAuIRqK7+Hu$-!M#
zhLe2)33dz>e&$3%ykysHznFH-ZwTa9=6Vhic9L*{J!#2RTD}FTsj=;gztYith0d)8
zxukY4=?h<4CP6aMTXbVh at ZA&i%%$)GBlnm+$MfW?X>qChp0kGq_cnvaX*+T8cZ5g{
zXSv6g_ at B(+k9Er!-CJW at rTbGO+4$nakjIUw++c*d#J}+T6`x2YO127%eDqI_1S=?f
z=N*p=rD^VZV}C_6I)d{UnJo{I47!P4e0sGEUib0&)Z&4(m at KddVm>uPNG;-1Olp8a
zjdW(z9f84-8Bs>@_~v`d$rWeOVdzGuS)CH)M4fioVtIz6r|SS(gIj9%H*hLnIuR3+
z<jfOn#wlrbJE5l1<EfYC at fY0Uzm=lL_o5>eWJLKm#re9F<PM4_>WQbbV!}7qD&uz+
zVs9yY-uQedGFoH224rFqPSZEbC~B0cab5II=WUAXu?x`{-W#pH#8pIjb?k_k`Ef(U
z?UX4-sQ-=j6LE9?*jtC$m>2AA5|-%8oAW67)ZZ>Ma_{&lf}Ho~Qvv(}*<6jZT0HY=
z!<2Yhx}S~uZIsyJsYRJCJ^IJ^G;^q!><1gs99MT^Tsmr!7pAa`4eATW+(mVX5+;AR
zKqz7KOf*<};XLBvfLsDd=b(1Gwr^B#C{CjkR_wJ}KY_IEtl>t8Xs1n&ijE(};F1wr
zytcgle~G6t<<-)6>421OZ}^2 at y+)8)Knnm+E6WK#HzzygG*BxSvcBr{*`iu!s#9t#
z^uViFUH{Y^(MHUYSXEdSUFJakXdw1-y3u(yYy|)RskvUl$P;-_5k~^!V>@r>0Ohhn
zx)WchUz|-kKOKL!_B>RW=qf|ftzQQxc4&lNFx`wyq at -_Tg&KNmjGyj2iaSxUTup$7
z$cHX~2i)>_yZ}ykaAg8{|2gSKG)<H*nsy2qu`Iz|O(amp4JOv)U&ZO at qn4C4vOlpr
zcj{}Ba=&cXCmn-SAVvlXUW$o2%L2OicTw-*U)E9F-0W>q<$%;1UhQ|ge^(?D)AZyd
z?bHGC&Yy49^0kj_Lq0Wha0+?ukMgHN!sR|~og&0O^Nw73`28po8wQE^BD|+)FkhUB
z*+=g<q18`d^tG#K4fCZbhYzEWl_eG>N(%5EPh+Hlr-DtS+bJjUUZb4S>i-UOrG^@r
zoZ9)SzQ9w?6u|^u>UB(p^?(1uf9OM1f*RxF_s0YD at pdhboMeFXS<fBmUuqkgs2}|I
zAFl)0m^|qvdt6OI<A~Ye(gW;U62fBPY3Xf3u-eUhc_gyUtBe6=atGX61rtpd9m{!=
zI8evjkb5ORvrthYn`D3~hJE~wGK!N#=CZ(ax2$xKxzVB%)Ps*=6SVKi^wED$9GA5q
z3gaF0?;7mPqYic1+3iaWBc5weLL_Hvm{EMjW=k$*&Oen}3~*muacGSB7?TmW(4*sj
zJ9-97r1-WD37a8oN#G5(vC$8Dx4(Qb)^0%N-}vFt#<)5|opZkZPYJXZE>5Z9ez at T&
zMgt!n(c?A5tarY-65cNA%qeW#)l^0~?OQdtynNjGtzl>L2mWAlh at Vi5)OP%+kLv8T
zK<A=?Gtnj+--S?t#LLjD>n&a&o|!0AvuS%1exjJ@<FNhkFi}7MpY)%pCBu)5R$W09
zMo<!)!GC7T|4Znn?bT&@S2jOZ!F4~*3AZ-|{fW2IHes6#zSAku8O7~4#Ye`+lIyO%
zz?u6NwNu;FukO at xh8E?_s9E7>r*xOw1kMC6f4rM~7$UFtZh|Mt>oY$S`KzbI(!@|c
z6epL;?ZInBBo$ZHk>_0kqXmDA6Lp$I-K at uef!g^VHH7CRen(4cg%NE};{Ar*AC33O
zj1P+MbA%!{l3*j<-CLufSMo#H@<VPv9WAFXUB+>|D1FV5jyl(SinI)REHVa at m#rxx
zp{MShNV>9<2T`SCLwow(mFkr9i?)O1wdTNANS-1mET*2zVqrP~(q4c0E&cu2@~zrh
zaktBpd(rNVzv5#_CI@%OesRBhSMnDX<JYLc<<%>{J^UnvniEwqg;_^L9U!AUy}Y^!
z>?PDTDKzgRvHZpBqF-1*4m at b__ziL$YuKVu1)rs0 at zY?Y()})_E#SUtR(#j)z2%ax
z|NR?WevBT~k(jtojfn>_@&t|n0;e<DoL}?zK0Y>edM!eGvV8jfKiQ54nc2opYz{3S
z_}`v#oyP*XTSR+ByJrWXs&_!$nZcLM1&&9wa)dOmF<6KZ4q%!2uwC6TZmH|QTR}>5
zEV_~R{>l at ya^i7sWP*~oX`W3g?5?-5E?I991YC!joV%v7Cct+vj>STPOAy at TO=PG`
z;R#%DHC8N=Vh)X|Fd!N;!;;B&UjjgY<MWSv8D{upM{AtNUHIAJdJUQ4LxhO_ISyfp
zz%!7&lK%NVMmh2*WlO;(&7~{wPswM&FMmt=fVgoYDNgW<6Oi|yX$lB%K58!0QR8N8
zyx7~Fls$JHR`S~E?vXA<U&NlVPwXhfWTo^yUFEEa>mJ-|d%f`Hq$M1PjMHTeWw*#Q
zvU}2^bw-}AL>Y46@~+huL1k}v2S^|`iZI~P%VIiqip=la;L<?HKQERkl%jNI5?gge
z0*UJw at f%dtMRP}Y`hWP}hf%1E4bBU&42={b6Q-7)(W8k at NI<8qo6=${?5yV)gDb(<
z_>=91hLeD@<nE$GjrvmovME)b=1-9`pc>_q)XHv+Dz95_{vl&vNovpfWHl*l+^%UJ
z9YI5*Stakjp>3v>_{%%p6Bpt*$FBkzXtp%oU=jn;sMd<}O8JZl at f^Yg9ktNiJJq@#
z!N3*ynA2|SR#SsQAxqeYA?AS&aM&LjY?1BO%CgS!245f>HNvlPnjfQfX|L&d`=sGF
zE^PG^1hBo~<l!|accA(2%0nK%GdSlBL<49WPZp%}@;h&M*A*qVqzvH-QLmH8zsZvt
zWw7TBXFqLZ7V1V~6!W*A><VmH&8V*DU3RuNiQ9WQGxGId$u%R}1d+ZQ7Y(9*1nN`{
z7x~GVOzPVi%j20=Isf5ha@^TE3DgN_)5NWino6{AaB`|3sEfP0k6E>@#l{$3{hYD{
zO`usDIjcTla&*>DmXsRQjF%)?>p7=pz3XBX`)>IB_KFVeQEEAfSK>wT?Sqj5`>OM0
zt*^GOI_77TQkM2g`Nvyh4W%XDtwxr%|5W%klf7*t!{L6Y5dT5#^v|J*C;NLAm)yA*
zGf`@sNnUaN5jG0f6>A(UI}Psse$e}DEYd3h(kJQh4D?2etF_K{;7ooK6fk{f7P4pR
z%RWvxy>p$F$Y)=v36(kX(i3a*qZcT{>ZrLyy*cxh-$GDyyz_&GGwcuJ-=C~;bm?#;
zll>Rj)BB<#NO}5Sktk3US*GaTM#W2<Noeej3qL>WMklDff1OBspXoI|?I_jx>5>7N
z^@w;$0tCDpkaX?73QwQD=$dQKALZ8w|Bhw*c6dEDo;W*RJn2-(>h@}aH0o#0(jKrp
zKL`T6>tlm>R&hSYWpmF>FzUSa3+{<vjEp6q%JxT4&mNlbINN#Etb!for*60M)a at z^
z$A69QQYzS<rFnqU<b<mtv0U9w(K9}=%%7TkTb5=z;fkZ}NYHYNyifaH9NTsAa0jL8
zP(aL^J-A_zf7}sTEOq;r`3Jiv0{F{Gy2+R;;73)O(Oj|?-!lgEhBa#A2lN%*NqN_-
z4mv%7(caN>In=4Kp<9^W9#8R+Ft_wjXy}w2t>6!o=5`P+e-0I_R=5xy?e(yl+Y+HL
zq*0<gVDyYUQ>|CQO1F(qr`OJJR_G-hr=#vs$D8~i1U;eF8ztilcO(Vbsmu7XVOdCl
z{R~L3xd+gGEY}m*=OO=SvjH8a<SKGM1Y7+Al1I+nh!_`gOBB=|9~5d{CdcQr()-!R
zf4P=msdg^qc at 7GHt-o*=lAmSt35=}tD7kL- at -J3y)3&Gdx}KC8_2`ont4Abc6v-O0
z6BrX4OK^72Fczo-v%&p#Ylu*Re-7mS5ljgkJ?z^*74Y1U@`<JUt5 at uLb-$tAfpe%%
zp<W+zyP_?e8sV<HIBJdCwsJ?kBssyqA%H>^Wc>QhwySm`a$L9Q$4r?pjLA}zcJ*Bd
zy8x~*9ElR5^eF=6&!Qc)5#baxnYI&L7<l^IyJU-&)BQi!^C^02j|UuW_zzyF-*;Sw
z3uJ=b)|5r2N4cy7kH2$|Mm;FJs;koJo$<4y!h6DF!Q$VF-+~Zj6|8c$76(t_M`Kwt
z-dpn^HA^#;rR=xk$R`Ht3Ni|O^87JZPq9^EUe)5HXGF9*_L#V-WT&*Cgixjz(O~^7
z5Qu&wA;Xx*-g71rc~Zt25*fz*D$mhLIaT48s~qIc!Wr?+gEJQs8sw59+C9Wt<^-N0
zZ5%Ssob3M;u)I<AD(U%a&9jG at 8LT4`riaqhtZ!&Y1-&gi<eZv=h>75gQkAE~C#c?a
zs6ow>afl%<-typ0d0T6?l^tt|tEL+d|9?~Ld3U0o7Krlo{L^Gv*-oo0NtFO0S;I8D
z1sfLPXD%*sF4rhGHYWjBok(fbB_}q4Q*ZJsa%6|k?hj8xH+iW8{Hc0YHlU7x|21m1
zam`=UYcWd;%|nwtG&`2E{S9ylffj;lLum^DYDurd<48HyGIr7}PqU#Qm9&EVD5o`c
z64L`IHEc9$ILLO`XdY!GOZp_Jk<^g1Fi7#&p*zMsIq*0wuVJ*Rlra`xF7iqU-+s;c
z7 at yPY3v<ayT+2Ei$L9;2YW`|tQ7liKC?9rAF7C!vn$&CMp at dy|<93S;d&X?7FKT~^
zJ3LtH7XcGn@;-U2LQA|ZT;gXrRg9!uMy;BB$GwWA*^3Mt+hj9>gwMR6;Y4R``lFKq
z_&BFrx*|6Z6uH5Wdu|s<UOr=2-kvO34iYFenrWBZA<3g3ck4#di>v9~U=8F+Z29I%
zH3eCrvAMz1UQH+j1itq(eBGs$zUFdHdHF|s%GN~9+LYU)%}1LB;;zNKy%ZU8^5+fq
zF&V0sULALEc6XatW`fZm{hEMBr4k!A>gT3Wtste)wV<@b*(t-N!LU{oV`UWlr9$$N
zL$lwXg6unPenaS`ekDRK`7G>>@y;e4>uZF=`lbTAc*z`UX9&Wgc5N at wh|MU at dA5II
z#+ky*q%SLVsgPQNiAt#U_|BbG336%;*fJ`STAY4zl)j&Y!{58Mn01OK9-Gb3j%-x>
zoap`{t-rR6E2fTNr<h?Wa&kW5@&}H{oVdCo>);ihmRG7q?d2&~U7AOnMX+L1kQ%ET
z_}QOs<tK$BTKUrE at X-E|FAHpe`3mTfA1+wyvp%>KMadBLQz6tCEd$#yy$qUA|5_fY
z@}|$ME!5GKG70?UV%25OiJ#B##(HJYLTZctr0#?FO((Na=WJ!MXk~U&d&`in;s?dQ
z^#4{=g8W4(!sw_?-gtpG5fnnLQOB3l5)kC;o#^w96A?<-j~rtJyQXa0!7ATuOvSR@
zCr-}jmIq7Mz2}u|<%y5kKc3TFZUbo9(5HTAae at BT0(_U|8mA}XqwetCIfqmHo8GAW
z_FjWLB%y5PYhsDW$`dGbJyVPQ;;Ld5x58%!P3OabKwsAW6;?3qY+zt(=wQiEQ{j1m
zPw}`k=DbH#-m=B7;@O>uAQE?4QRvNA9MH2eXFb3__yv*zHOJ0+|CZw0yZR>Y>z4){
z=n;2IdYOjDot?J2J67$Jqy|jInp0hQ<F}@^Tv;XWsx|O7NYLTnabyrB_ZgvsEsrX3
zlLL70kZ~O$7J+B~EL at 775LkExK3oR<*9)wse3iA_1A#0+Ps?ZOi;OD2yK$^Zi7qOC
zQj9MCtsxS>8jMRG(SV*=<tJ#Zvs^}5RlEs}uds!+Xv{yZ3IS-8 at O`_w(8DJzBkJ^Q
zEQm#5H;>0{5ID>jiLy8lfix<At+<$hRpwH?YH at Y_^u0=N-Lts3(pdf!$EnH|KuuyC
zE<3~7FcoKOxT;FCIXaq2*xlOT0q(~1Iw1+ig-nM+Du&;ZVuKuq{wQ(mI&{vzVQKbD
z5wr1(5nR1l#@m}bjE~Y1ueU4Ix#?y~vz at 74OHh>iF*E&?zmxuHv%uG8On5U<{@ylR
zlOp5leIm0`+AXc@`qBQ;0MQ5YVYJ4e{9SeXFj9}xO8!rKahGHAwXz?PZCPo#5=2*c
z-j{9fjDbH7eZd<?Dw%tGZ_({mZlC?SPS_BMx at m3D5o+a#sB2!ua62S6QpWAseoK$O
z`hRGL-xI<GR4dfYoI87^XG(ySHx0HHsZRMUF=9L`FY|3l0$%K17k5R-XD3=L?X2a1
zKX`+-C~litMOJwW;;9X-p}%{6a0p{p<^(Y71V)3pf5i%;5D8;O`u&fkbYCtDeU|!6
zeYnMcp}jMb_D$5l;wLHG>*MbFJ0Y7wIj5b^!sv0e0lwLpRKy<ulVrpM?1EFylyHlo
z3$?oS9)I%s-X6!pQN!SGm_pU;_NU12mjc0|^qAvjx6-!AkXNSKP)lkDWuRsa+4^qw
zrHFu;K_T#ASLcnA1{-dwlbQn4qP&zMC9TJ{hPdji at NX^dVQc1xPo2*XlgrzRnLBeg
znrp>R@`V9C=e!edFarp~Rp9PI5es at B({5f)6Tbm9v+1e*_Gz$N2nv5V65nuOq>!Ff
z;z3H|740B23vh at Cor#9U*9!cPT@?yPl;uZX5iI=PW&Y!X;Yo0fH(RXY|DO0O|4;6;
zU-rO5*wF&l at 2|9p2lrsTn)<7qwa%=jy(`Ju+OO=M`cn4Y$=wsT@&z-iR(Ee*D^5_D
z{ifX6D=Us{KLs+`8JEBaI5zMcqZm+nBeC>{&IZk_px|d-Kk(o}6EDqvr_Efcg4V}F
zS?Aa<F1zY!i|FSbcYr&?rwDR+b_h<(bgHy=LX%87WIY14dRAeRbwQ*eJW7%vMA?q(
zE`O_N4fdgb;b+;~cU(U^6H7P^{j<!+Ve-Wy1D=GT)XB#mbvzBc<eS;x+>S_i)vjV<
zekHqi=75d>8*HP5X!nIk{0No<R at l7S?%CK9o9<zG$;H4H)xRhGhSjOr=FC06%|@!o
z>RH;tWFOy39X9TBDrTodqfoNfODoTIV~!PNiEw=-h%!&xQ!I4F#OPy<fXdvCqWpso
zWwVm?)^ohtD(q{!6I=XSLPwWIO1b{Txp%feYEYblwsoEMA!qZ1A`1#tjMpeU6kWzE
z)v-{BdR#&xrQ7A-OZ~mGy+)eT*YjJjA<0r{)Y!=bZ(hs&BKA?+GbF${?_{{z)UzWE
zJ@|gOAymmlp$sBlE<gUPwP`A0ISc1Ev>cP>)+IO(TjpuVtvJ_X&N@)o;V4-AP8i*2
z3;hRs5*t$ayUP+SF|Ou$uq0sW>z`2Z$7H<s(LYz$L)T5NjGy>EC(y<yn@$=B<)H*h
zm-a?JhTe~gq)IU#oK9tit^OQqafv-rq^+NTsO5s^cH60y4;K%D&_sv)&OU*I3#!^(
z?be7kD)DL4R;E*{_y?W9p-750x}WbbI`mo1x`q<rioDHn!2XI7sfd*^7Z%SNJdaL3
zKKeR~RyY5?Qtp&W^;xY<a8lcFU=iSFm(Fz~pMhA!apW}fQ9>Cjwt#p`{%UqR+4EHW
zx(Jg#VNdgRuz%XCH?jn48^#7}keE>Lz at MXNp(glRHu4Uu#gr&XM&|61FOv{PpmcDW
zt^Fap`pxW8Ji&k#d`o+^WCY5CtztL1L@$~PS<n at HIf=?q$d(bqqn*#+zAsR<yv!q?
zc%7C`*YWOVTPb>VkGy!KYA^89Vj?I0XU1Gnipa>n3aRXRd9qKMOVBn1YIkW_fh0rD
zENOoUHx*kBS&y^0NT)8}j8Nwrxk_qDy`|G!StQDJG3|#zTu8 at Zx5&-I&B}e}es@$v
zQ#Q^rX`el5d-9;0&25NvWmbuZK8VtriLZGlxaQm;%2l0tO~w8R_fjphVybo!>o=0C
zOORQZ<}L)afRI?lh(^Af<8xVzH@?E_e&VRozrJHl$9%3U`73F&vOE9VR=XELV(s9F
zpqG7rEzG{}IL}=xWFR!e0YSV5+Hy#n-})VzB{S3;_Mo<rB?=NANU8`s5$0|WYnwQ(
zQpbw=_#u91t;{aY`W(!W;(h!sZFWbF6hnzG at JiPzbZZA#rF<}6&13SRtKTM!7QP%6
zXM4+F8mgSt(sT$H$BX}4>R1~^XpE}q)sm!$c*S=O;#?;nAmPulm(Y9a9DWUPw3*tu
zRg2IXI5`L8c&x<^@A=Chuo*A2H6;4g_CkXrtg_$-NQ(b$rp6&585tfJX5 at izwXC?d
z(7Hqfub6)jz$=+rdHQ0Re?lA_=$Ap3Hp39<=tr^>8z8cwpQ<o;bDJXQHzlBQJ*!i|
zB#P20Rf?AA|KWYpkP*+QeXxFgeAvif^#(=RccA?)VeIr7EiJUpO}w$Bs+YC1O;3y=
zH0CSEUlD(+s$uRLc$>K&kf<JS``)<DPZ3&pg>y#o3Vt~r(Lo4p=4 at 1;T}nt|B+=!I
z%&C8J*{>CPtU$`B5E1-x6+uzyCoVkP7ueztn%v&CD*)`=k)ylQVo{05`KMNPMov>z
zF%AqO{6E<$kb;)=Bb&*<`WuRlE+Jn at lrE-bqwMy&*w5|4ecnBBmc1u44b$_Z04zKe
zY2~qoQ#Un2V*{R2=8Dzbi}{^##b&mhgIvlTD$UVmw0d<ygl)?zv)as!AJJ$oCrOkZ
zL0|<I+QGJ{mUN_1i^4MB{&{sRzM7^W?g at S7mYL21*Q(tSOUUp7Fa^;d!`Y&Pg+MvU
z_V5?LK_#30Svs6Son at A8InB^gM0)Vo^7j(%i}X+k4UuRQWx|6VLsq#pr#Q4xVsIA+
zq3ArJ=n*00Kxve?U|BZ27m?ZROnh((+nohpPMN3PU||;6UO!ep74Z^nXD489xrYS;
zCl?40x`^}l_g{p(WyQrKXUEZDYRvIkb;b7fRLbA2LE9GUOEC3vu{Fjw at ***@5->=e3;
zdT_`%$2Q>c@!;cwU1SLPWbu^juY4Mb+|s8csj5Mv-L7~!l*iMHi{wAWxM8IyYR+dE
zrCks@!bgv7-mp_#=3tUye`%o(Qm5KN4AD8MXG*N at xDP>3hazQ_R30oLpXLZ=*OHd>
z)KU9HB4FlfF(X~<Ea|^<(5PqZG6Kb^J3Fk|1z>}WSKc{Bd9O&u{Yn{jkNIKmd%oEV
zkB_!&-~|sOnEo$nDL2g1PJJ~QCddeq0|BUBnxi at twR}LO;h8`u^@krb4&P at Rk2Kvq
z{#-3A`Z2KOieS3Bc{sT2+WI8vp11X$)|DE)r1cb4g`1n009SEa*$vGr<RQ0U at O-UN
zoLgbo8H{^+f=JwN_mLI$z$6ZRT^Y%TGPeW0Se#~G(f+bXoNa5HA0W)2Si>XY4Ce%E
zp5$)H^M9myX+%;_|5r3%9-TJ*yXM6wNZ2epdVPPIKlhJloA|xu`gbXTPJp?qGvugc
zd9%;p?0^{C^k%hHF+EuZDDRS#%^(PVZu$Gsp;4H17pD~`%!X6j$~@;M at OIZ2(6J7u
z@>XM;5(DbmC48&3Q#4S0wyteB;C}Mx*CWU0M^>-Z$EPXP!N(tDhLF3)Ik-XS+V<3n
z*6z~3(cV<(7kKP*cwt8XLH;TK3llT>UyRx_-Ju5-al(0?=C2{=8KjidZisCj at qSOd
zXPJZgA~O%PeQ-5 at ***@LV=(yQH}`n`&q$<t4E^1zEb2MFWMRCG)yuVT^xDY6
z*bba<Z}qL<Yl;_nsqDC7b3sKOMs=*=MW&4H7aJEw8g*?nuzTU6X^WN^!sPr}0HOt?
zTvWq-$Pt<K+j#Z2R~vNo<^ii<ma*s9_(Djm6Ox382dqp#C*<yC&#QRe4;=XpP$i%a
zvL<{scqx3;0eNd|84rXdExce&mc^zM1SQ1&VOh#lSOxmpG3Ui_`q+{12B<gM<gRr;
zX0F#l4TPEAn}vY at uIfHBuyg>!`!TL}pxn~&Q{Z*@6IuQd;(Tf5u1Un{$EJ+9h+Ed=
z&T$@TMLj~eXTC0?r at 3O*q~$AN(lPj(h+9h59T_>}2+9p{l0M at 5);361!gOTU<ZZyO
zU9Q7SjiK)SOR^WL7{?OTqN~A|c8C7}f0D&(8Sm%Xd7OL_D`d`TCnoo8^le|QHd&=-
zFRFQ2{Z8$?_Zl_MO)az2Z~g98IB~oZq_ixMqD>i%l`HB~Jt%U)6&j^Wbg9})xc at 7%
zlNTwl?gEUYnyk)(?+co{CipEZ>D>f;P;d`lmi!$QWTBo^pz#Xtvmk%f$myD3LW3yR
zQuFGv-5Z^Lx&PRmZgS{NW#s<v9RMl(@A=rrveP9sPQb3li at z`}@Hz7$VIt!qV7JFZ
zl^UhlaGuD$m6Xiv`}$?%Fn#IWu3MW*`pv9b_oUY!;*~w`_r+BA>7)yrgG8&U!&whS
z!=j3n)t7MzlT0_D0r3v{Y^CdlO{7F0Qohw~H<UG@%}!l}KULp;j9?1mAFCrS>awTP
z<@gS#fP~F?5c()G7ije?Q`Wuflk7e5zAhW&sl!F?_azrZSiT}h&cmPBX=u4FA3yq)
zKGLKciH<t6nORRfpBHs5MWr~tTx<(65Yt$FM{>&AZnFIIpHxojnrqN|-KfQR?X8pF
z+)3f!#pWqxpZEqbaz2|Hq1i)0euO at HJvxEXtiE7!{9f2qobNu<-siQ;4u50W08UM@
zw`$)A3y-p)dxr((Fk1uU_|^+IjGzPYmY%lAb at W4G?p^Nbhb0bbd4B-*q at wdP)8}CV
z4b6XETNJ&dga|)_OaBc0Urw*%K%OClAyw(|Q_mW`9BeoI$$JB?$Zb2q(s8V9rHw}l
zQ`pI*w8ACcb=DKPoEh)#IErIh4A0bZTDN!h#r2oodQ+(p`w^*R*vOYV^v2N|SnGIX
zRb=l~e^bu<V_5)??C;be<@w7YzY>h3 at c#rf{FdSCh`Fco&~<1YziH&~q_lLfm~`O#
zLuCAaR4q8P)_I{>$yuT9URa^Ho{U9!MpqSa*;n{gbiwN6N@^vUucTp($(AlDYr{aS
z4|09EUwm4+7F%;zTE8uAA!36rcO$w?!<rM`VH#RA#+=Ak-7>9+9Hckoa1RY<AdiJI
z0~_zAVb4Stz+Pv)B6l5x=@zGfGuA6d;VwndCh^1Aeub at Ajpyy_g0r7J-Y^K at fy!Z%
z+ at ct~sC!qvURk_DB2Tc5Dp7yqtIW1Sf)~{87Ws0y5xqHeksq~Tm-$ghgSb#g5h0H2
zq^X6y4}|IC?#~R%Hg!XrAl8T7HY7LIYQ{R2sIBevxdx_|y|sJyNoaSw&4vl1UDpDw
z1f`gXb^a+{d+Wu$(reC&5PH*~rM{{#?cAlAL4=bJomM$iv}XFuh`^E8#6gkr6%$L+
zesgAYev>$WQ>8;#jyzF8Ln#x#RxCPNWygm+{@0UB%Z>br=+BxpIG^s)e*rOIbP;<O
zdqprp&PIh3!b=l8g(%l3o8_$me3X-VoyPK$H_p_rD@)jm#@$`doUH?a+zKP<ndR}N
z`A?xH6S>Y<e-$qYsNr$&CsCo#Z*(^1GK{(Ewek1vD*@7 at 1cgE3GHz8(O_qm|T50&Y
z7&pk6fd$Er=%&xC!(|+9)9)&MWyBE}YP*aRKKg|C<{MXlTXMhDwEK$1CI~1iyvjOA
z*9Df-%xx0lI$@w7w(8H5_-^Kd7R4yXYC at I^yx3>8&Q&Nljy?Ff-B^<P5!_ at M3F)BU
zlIOlbAaf!EA8#buz$o`97%$rp5Ea(6=~os^xKjKwi3c%1Q(!Ky$G;@(MA5#~@DQIt
zhatE^OIYC^y*s|U$PYUC^F?1CL&q~s+MB`je7Xh2U4mewu4#5EeU8z&gAg{K?L2V0
z1UVn=fk8`G|1b9N=DgDA_gQ%RoY0jtGiH4<R7N at E?Z&mgf1=X`VQNsaqRH4^v&k at e
zre&d~gMyqu>WqKY5^A at U(h{g#&xa>*){BgEm-u;0{0m?~ukP9s)gad<eFhqA&1$md
zB$H=edLnosHQe6&XJ-C+(wdfUa<5prL>F-5*EJxgT!OP9sT&olr_T}k2_grFcZ55>
z^T*J1ELAu#2_3G~(~(!!VK=CGo3bLA-R-BVA at 5XhfCObTi!;NyAImosj4f1c3lle&
zLY)~vm#ZT`^;S7*2IFr0fp)o6Rzg;2f~8(>{~1Pv{CIo(BKZUxU#?oZeMFEV-w)ZQ
z=4gG|z#D at PefivcCxm^Q3agzlcl=ei$g1<3F=e3O%352e^4~GvYq`1uKKrPzoIyrZ
zJNJ%B`e>}snFa6qi2hh3{I=x+Twdd=uaOe5{=Wm58y?v<xyCvh!!ucC+aO>@`C8DP
z6=PJ)MKpi~Bq#wUv`#nRTUg at xiC9^%c<8*iCVnWq*VQRa at 2i{VR^L9m?Aeav%i?74
zr2mc@?+VA=5OJ#D&rm3e`~Hlc$lA;>Qg_)bfAM2qr$X0KKRcy+*E1c<gXO3xdb(UD
z;1eFivm%EPofkQBj)}8eF`Yb4D={tb{mJAt5sV*W19 at PuCVRB-rRXNODqh%b{&5+%
z)n+j(S*N#mkryMcp3asC5OXL8>bLg#4egd at yK!`xn>W7=oo2lyBqei3{CIx(db<78
z2U~H0)iqH1J at usI+Fg<OP#NKSo^vMbC)4px<r(q%)V>TLw=$46_kn4-($>+=kh_lM
zVgjPVC0Vg}Bp=5U&{gQ;zN=h at XmRk&v)dBCIo<9&cJcbJmLoV$xd75%E=BB_YfR7y
zSU^jjqE8nC>3PX8F8Z#Ch025K0EP)8K(><UVn7+9XuUqS<4?YwS(v6t`!u)3q%qv)
z1Zt-E(hJcqTq%+;h*i)&XOAubIj#h)N!^fN at fTQnDHK3(DoXTC=>5uXuk2p6P~puZ
zxYy&3i7Pg|;rje97mTDNGOcR6p)EZBK)tK|+ckPb)FJ#HV{ZPRjym`4Q}!5+`-wMN
z@@nBg^s<9E{}gOHR4^rS$5y5gm6gF!sCIOe^aQ7m!ops0xQQ3`F$7pW`vtsaD^XyY
z<JYtSLTK^pbii)`-Vq1Q)+l2BmX}z=&w;8wM2qNVadL$+>4SV^3d at Pj2WZVd0eGR(
zDO-b%w-HM<o!Qa2A&TIgQQYJiPMmN$+D;EmVTQ at MV760Kc-y%ol~~39WV`$sqpTq4
z=T!7KzVKu5|A-J*u8MXJmqJXS0_#K^>*IXb at VL&*qE<aMD3P_h0R+>7YmJ*$7D4!|
z(6<H%eyY5JF3-|}?ho&#DJ|cAx^lo%+wE6~Q)HO!Jy6Z<_7qwpo$P6xlyz);xEC^y
za^a;Bj~s0rFtbCr)ex$Sq%*2n4KdvUIr6w4Xj_00CAhWTJw3ckLYn4V?|!*I=}00t
z3gR9v>yQ&0p8%PdVoZj`<Rj|MKMsEo at rh&ZEgGW^t9Q}_DGjAr4$}JG)_Gj3`}S$u
z<j)9uVrP)q=Xj%K>!9*%-@}@ILKYmRnj>!=-5nt=?Odi_4s#XA_o*E7%|d4|8!Eq>
zb5tmAdA;sZU2soy>4v<TdA)#bDfS{>B^kP<<7M95`Gsn649uMiT}-q9Z>?ZU_*srv
zUy~#PMjq>h%-|H`7d5Vf4&9x^FKq(JwEoo;;h`~)_YDu=r)H;U<A<&M$;YN($}xWc
zpXpvkK_TMytIb<XlnM6z>)Z!}-csbF0^{<*g at 3C6O2)$5P_Z)HU-7T$g!d)*`5-`W
zE2C{)3Zx*!olxu{=eOSU6>vq^{6kPue~Xc%gE_x|+Ystl)&gEzR$-ztzwFb}PidCF
z!t&i_;f#Zp*JJT37nijA>(rwq-t7MFXSXfizm)j*!v(C-!OKe&yFN~=;M(zL!$<br
zpP=@&``oOnY1yVykX0Y+@(YM{lp89x+Z4<lI>OC>walTxXOn<{NVR`tjc*<WT;+z5
z{~;p27T+|Ict~jBdLPQ07hZ(y>O at Su-k<#8cYh)k6IiPB_=q)F6`RcXOTcL?&KTv}
zPZK6nW^3$!v?t4+zXem?=aR8cgC`-ZmEf~4lM?W$EGL^Hf7^cYYDt#Jz62x~1)YT0
zYn&o?S@*Mq<7{uoY-DC)0&XV+#jJ=w7}%y%?xD0U;X31TkFD`zQ4B7T`)aFk%jU#O
z(quLytgHQoEwkUG?lGD2vi?WfqTO3RDSi0f*+Kq~O~=2lZYIru<ZpqzE&}L&XEx+*
z!OiScc0SjjbPR*=b6XfXl3URZw6z?^27V0u>Nj-0cHVAyjO1=nu16B94r5EiRQ!ft
zaFve*Ycz8Sg*XxJl(rYOZ!BD;7A02rQ at mRnC64xvsz#V|%pJats#@bOU&Yzqe9a0j
zOi6_vgPDtqE=69*Sy;G7V}(s{u at P~*Cg<e_(Dehkqnpc>%eSc_pif_QvSVlOJXx#u
ze405VN%oC!kAi_ZXU5H+zop$FUd at 3w1=I}D9KZd3)jW6SanZ4m*x?k+%HT}<y!796
zNYA6Sj}4l`CF^*F?!+Fkj>u#>{z>1F(<6}lS#tmA?cy<xg;>HD)aF~K)*IigwFkLV
zLJ+^6BFykZB)@SbioV4rBh2v{Tp0h~q3POlU)*Q6Fu!+$e}5UfaSYMJoRFzM7cyGY
zD|!|2Y{;)2y&#i{gT&?6=rL<&^lUNSIkH7&Xv at X|1y`^GAIVwj_i`Uh;##M#bLZ}B
zs?4uf$U5(S!mRy~?XPe9wxwJJP at cdnvZ{{%B!gG^$$~r^64U#)bEq6sW(VqR=70ch
zmeD41zze;Bqg-G at U<^9Pqd*`peOIC<?&aw7Q%%>^{jm-jHzl~iB)<Oj&attw5EaZg
zmi{GA&x$16A?K8MdkoQZNiR{n2+Esyoe<t$kCoBz$VII;t(Bin$?s=u_WDYn3}P&G
zh21;qUi?c-69^+@%5`jgFk*Rp at ydOv$R~47&pjnw1LoA^OhNJ<)dnEdfw at O=j;>#-
zpDgD_5#n0f9IN6P=8zVZ at Q1m`Z(5*6u}kF;`q(RA3M(VzTo_FI42TxV+x)-&qtFXs
zEoh0a at 7SH9BDMLr-+DD(cp?k6ekFnl1 at U1o63(^HHT%k?XQ8d+$lbfU6UD^^#YL_r
z<?jOf085X-7^*&iWI(M=hS9cQUr*zD)bAYo)3 at 6gRb_u6bfLu!>ao35_18z%l9M&&
zv!GpNrFL1BERmmELmr;5I)Z>Q__^k3ey at ***@e$p%dRQnuDyy#egZE7=z<E&P)lL
zHr=N4nHij0=e;{&tNc6P*ZBWJAq<el0Dq at n>XO~xNVO1a;O?yD?e=ekw)gVkabmz#
zwfyA3l2-A!J<ID)pch2WRU1Swa^<;~+}?G8X)7!l_c>EjVk1G&kT0h&Nge2QA2#|^
z&(&?*dBzb>?+2{g=NMnF9cCUEfA&o8yf6rD6^7M4sOsnT3l<<}a|l(tRn)4>P!}b+
z{3f8&=I3Pjn*YuTA{RLDJTq^V+C5JH{#$9dmn}Qh3s7dalK#82&{CAPm1(&8hx#fF
z*u}HV<HGC8LLNXBj0w8(`f;d6TeVEvQma<i at s9*jEOt1KSwk`>=#!vmp%#zbc!s56
znpJ;vO}$U8xnJK(1~MTuk*<%enI?gid|J$vaDpqRXua3LPPeHv)c!a4(89;A;2+4~
zxC3hJ$I}bH8!X at Lr>vxV<+Q(#oo|<J;H)^+v6g}T*bJ){F++Z6=f<fNGUhN&7^@_}
zb>^o at 1c?6I_*Y9D$vVc?1ZK{Mp2oh2UV3b at Ewv%MXnn3VlqqP|R9pC>3fze|?*s<F
zFX2z6@{A=f)_06E(cs9#Hf>3~Ju^dMFdyMpg0{W6z01*Dv@)HGd#lIEsEk=CNOWOD
zm>2FcIcJoIn7lgq0(Q--sq+vOw}#+K^bJm288co(94L&Rlm{O_q`txXtnbf$FzRaX
zt}v4vh8vJYHvY>uae;edZnp$I<Nv3FCa(0Ohc6J+5c(6)S;ppUvhdAg<ZIf4Kf>Bu
z?;ZYH=asj_u?gE8-!YgT%4|7phva_4MA*oc*uL$)$jM0{#6M*4p_ByD4Krf(;(Zod
z!~&J{#sZ~><Du)hyAdT?@g6t1(*}7!wnO&7)H~Y;(LVv*#Pdwcbd=F0a2_Co$39>-
zyzJ0sfWoDJ|4ewKohv7&&pgc8+0zoMAaieA$>OBy-0|}w+=7lspVR>_D*9`+`9R~)
z+^WI79~n&kYhryCXiOc@@j$@NFFc;C64^`4=O$<DKgNSFG^IX9hF=n{H{(mC3_IU*
zKd<51PGMP2@(Mof80TY(a7B1f8l`;SAO7)L^`Tg2`PVDW!rR{B#BmJHYCxA3S3;mf
zQ{xpa7q*7;JDq at L@<K6x<$~>gu`XE7Hl?Jog3W=bPUL?^)ZqK-$S8IuLXMNm!}gYg
z;hK>KgSzh1?ojU%9aIX2TyngdN$+JW2i$bRf24_OKsX<&W1Z+ti{l~SKz&If at aQUL
zOTfRPyv%9oMGyk7WN_MU6Nd~6eAp};0J^?%Lz}t?7wqR?jc*S`l<<v|WajEV->kB;
zHh&;fd;oN4?byL(zznyqqDQKSmB;OBkL~dtuaQLyt;8%0v8%{Kqs9bcrHz}cLkP>s
zroxC^va>er#oH%O2e;zzo1u51<t_Yk77q^<T!YGROCCwH at L{NdId4DCy|(~O{4p3k
z<Q_2g#_K1uFm7P%t3Z*lGTv52YF%uMAkd!}^LArj^B@>Ir+$CZ%JQ%bXtOo5_nk05
zBlj5pD}<v95|~1>W9e<FD64n+<uL&B9>0->>oz%5)!3)S-cr2)=SG{twgamt14csE
zK+ at _)R+ZJn5$lrYOgqB`a^DfNv3h8Rr?adVGqa7(vjqO3bl*d0Nri+Q2T9tor4IHk
zYJIA{KHq8Hxl1peOmY&?Ftg{}*yW;Pnuz}AN-9OGXGDEP-XGm~nXqy-KFwyUHw*vZ
zD+&P*2xRJ^;rpX4GvpN<eG{rKQhGCTuMY at h(7^r6*Y*>c<{ZzkcsV|Vx;`i2Ww*zc
zfSGu7hl(1>l$jymuFaF}gRk%FEi0kRS5AJv at LW7xIicSk1MDK!oQ^EKvEg*p!Kc%N
z>rdM__lQy&3PL$D+9IcS$=gu%ZT>UcHX1{bhPx*=;XMmd&hnaEHZF+Lvsa-KG)=6{
z5ML+=3~b&P>3_{$qpY=Xcbxdh2ANQL{`C)zCK=9;afp{YdY5$ZJ7t*y_JHA6xVc{v
zfDO at cec0?h3UFS|0I3tr%F2BOr4Vg{)l`d+Ar$qPIO(ZG%=s*@b#%ThQO;vUBpcP=
zUWpHN67q?3<78b5k#3PW-q!4jV*#52R@%;d=C0nK*z*$As1 at y)X_X$$O79JUDbGr%
zFV&~{Z=`t#!~91U&OPVX|1WWGTPS9Ws(W_j)nghMSxqJPQYHs0eaj+@#3D3+LQ at q~
z_QhAD`$<jldSx!cWZPQvS-QQ<d-EaBIbUz4+#s+q6%)q;oK;XO&sKjw^I;<#Ok3wj
zzbyFuK2x?{_t(-yVgs1q*H2#s{0*H$N>J5fn5wXr;2iFqpV)GxFrl{x#;fmeX7{Ui
z>(={2^BXqQTEk_#bp~(9 at YtvZ?Q94F2?so*hc;y*d&Se76{*om>2CwtQ_XnNw%Uph
zX(w-X;^>UWcRTK?Tcr+q3sE$xD3uLwX9FlIgY96I4$QOFizGl4;n-33;P0Op4Ev>^
z6|jxb6bU`<lW&%4^2adrY4jnOt_0-k)}Q;m6P)i{6~;Q(ZsS`#8!WZ|o%3I|4A`{l
zU4hKrkZEnbaMi>{&vW+?g=5UIva3^h6l5hpbquF>uqhD$5|Mc(zEwc1B(w%J$LUi9
zmOmgTQTZiQ^KsSi!OH0RZbO#hvEN$)lI=lF at vt%INc?bRKu#e{%RQ#(#c-RE+Qe`}
z7-=EfgS~0osYO=c>1xV)@_J$?AZ7b!?{j{igQAl=K9vPcj=U)t->l`x)3^RJCjJw#
zDz+B;XX}c;Z<ZP>lWw71fQ12<0S|KyJ(dpPApm_Vtb7&*72mZXdT<w2%7dEmIajeO
zMo)6``tfbu<S>w6Nso2Kp_Dc_7G_PZQ3HQ$Vv42absKRNw9DKS*wT$gXw{kH3OquV
zO(0$9pf0R}e%`CB?Mf?8kD^bPc~c9_)u*tj<&yw!vGDVfGa9<Eg{-61%Jr2=H2X>x
zt{0KWRKA=@@7JGN9|^ri_s!tAw&dB;y>x#B-l`o%x~}}doC;$(lKzjPvwmx`fBQJy
z-O>nxNl51i0Tl_wuXHQnXe0+4-3*Z1q6VU30HeEWprjz9H$sLC7`XwfhvzT2e!0%$
zJde*iUec4!dN69PB^4&JsnPuNAetq{uilVJgQ-z+#Owf(jF7*YZOC04moz02PBrsb
zy=_&Q71ZW8t42D#Lo1}N=(%>nLh}_O>F%_&&8!($Cp~0lfk;&GT-M?B$s}vl=SVL;
zC0AH4BBmm at b%Z#k!^C{3=iXwP!_fHA-t-)`lO#@-Br)!%+V%$@F26l{I{i<UWuvm!
z1(g%x!K345MLk}{boaeEjDK|zocPfESAt*X at w(wCJyxsp?btgO^e7|Ud+wRzdYZJu
zzP%-Cgb2n%e}tg32e>F5X>L;LQ#XS~|C4=XDq#$}xJB>Ew!Q3OMJ*juza$2V9as#~
z&--0grZUf&3hmXqJwIi?Exs#E9Dns|fKHU1-(P at ***@NAEw%K at I-RDlZ&CKRf1a3Q
zy_7VjB?v36wy;?@Rla-ZF3_D|T8HT5B}_^AKbZnZ&P}7hQSXah&)3eljRu(f9(jKs
za_0s(&h(6G9qbp{-<{7>`q`^tT6^_IT02O0<HO;Xov_PdQW2kA09s4 at P?`VIiN2!5
zQD_kTfX2lHLjtlb#fH_0daZhe#l2s;)o+zrJxBsfnw0dnw$dOIidEh$E8QKr+=FDH
zu)4X!Jl@$X+PiZHqg$09MB#u$gvK+-l=Vpo%6aES6o5m$%P{gpRg!PE<?34!^#gHI
zbE$s)r?3HJ4;zTmX!-Nxm$XN6GV at y8nx$ZOSy|b^>QcWLt4wl7Jk8oHc~hb%T_kL{
z7`Uew{oRH@^w4Vy!@bzb7E$T1D#1L at M*-QCB}G^cCSy&lr>-z%b<B})y$d>X3OR^L
zT|M#7Q!u#QnLR#-GyO4QV}wYDuZY-g-$_KNY_+oO|FkZFRczga6ft+9xmzh2j%7&q
z78AH|M6m?wWpyI9`fHnE^)%3%-0&C`^<b?3!Jd at v*jDGOo~Sk~_$6iYMxl_iDds1B
z8&!jw)^e>V%JQb%gfA3 at 0Y78^{zEu}F76VZOR(*Ii%XmMPd^=b5HQ2FG+`jwi%6Lc
zdW9AytF=QeLb}b)e(Z;(I#1TznMqqS$G-rumG>;R9BVhf*O^Hz8mJ7r-?J5(r!iUF
z%}w4ElO;VJ4^MzJFawwl{LY)Gk^_&{@~F4qI`1k%ww+!w*SSHAZQRI}hs-3a<4Kim
zZcJHziQPBmo;Q-um3qOtx#-U0fLYtm%=3|3w~oyyyb(Pg6xfy6-g%LB$+`*QYn7}k
znp*buT6S8*=9Mer!tBLCw*uE`kMXN}!4YtaV2%rQgEm3q=Og*@2M^cf>S2qU0=h+g
zZ>D|(OV~We*iW$2{fp^l1|Afg``@%kPnMfjx at uz^`@Ou1Gul>b+wk at K__5)TAju8f
zlu?jC5VNL{?gX at pDbQZ`Vvz%`E9PzuHw<bG#mNJO%~(>p at a41-***@YYEs at k7n
zEAi55EPYpR^QB)Gk2#c<7Rry`#5sIjLL7hVmsvym$h^+s8U4bxfMsLBkM%s!3s9-!
z=CUFybx4t9ArrKHA at _qt*chOk;ncXGL4JS^y0id=3q%v39pNREg>XdTsif<Gv#p!z
zfnhHQp;&_3@|B{IUhLDSrLI|%vU(2no#TZM*t>fr!ZHU{*`CCiO>;4?$#!lo-`DD}
zy4Ux5`Jbbai3+=**U>iLSj&wuCz-y}HNO?5OqRXrkfC-n|2NHTG}-HhL<NJYA~}17
z5I)?aWyKw`W!jP~J5`XXr<_H__Qol#?Ved^IsIBF%sHL!WFqY5WTvqyT5SPB?UQ~^
z6 at Sx>H@?Qq(BR&7qkjHZVh}UZ*@p0MesTeB?Gb$uz$C5sH~8h9ug0>BS}ekoY)2D5
zC%+5*R-ChbKrPLgp)u{iosu%Q0VHELs+()-c$x1<6U0BkMLc(&%gNJ@$fsz7u^DXF
zN&_5>v?)qM`x;6K5rfL?vnqX-6%&7T5+VYk*juF-^$Gj-MTxWNg6AJ{0Re0~l=!C9
z?we4(r{TAM^N3tYx)OQ$14egEVCTo`1Y^1OYm#VogTNpACf1U2{|=x(#>Pwxs1_fu
z{|@O6Jm}hQnKd^C+j>{$FY`G5N&+k at kREVOihJ+d_vqTarL|2!MM|(kIm9Y^zP+h@
zJ343lGDD5NE3d1XziUCXo#$N1>#9^YDRx(TSIM5)H$rhi19o*adO3Gdv~h8#akZV(
zS&A6rL!fuDSnr!21&`&TlX+r!+5?{He<-ZSoQnvIP|jph$wyi0C9TrJT2!<NCT<;}
z|KBn7-q7)bN0Ikpg~!VKI at ax_Ug}H`hGCVI&Rn5;W9-EpYE<JYOQ3%6T{UUKuDHf4
zboM(#4T*5_gPJ4F#47GBzcP}yR(IrW#GkhAIp6gb;un-Hw=?#${8*4THx~=|x`4^Q
zbvlr>f!xK^$T{;AZW!%55X}wtnTM~Ta)L%6Ev;>JLO0tCmEI3wl9fw<({%-R45Wno
z%Xp+bG=gkNcl5OU1WV38wPa-_L3kNO^I~o;h^c9MgTjO$OPp4s#TiY!F|ArX2wrkV
zebF6Rf;vIiZ6ShwuCP`yk69+$sPE#H(9#CIb)9rqmI6tbPN8Sri)6qD8%au6={4fv
zVY)}RcJ7*CDI}Qwlj{5NNlNlPMx%cZpuiBz^anKAbZuJ9D3;p*b+3Rbm4f2rdn0n1
z^jDI7ePIPY1;EGdZ{u{3IvA!&(OR-LYSHe<I+mm5tSxlV@@#Omir`II`{)+gh0BKr
zALb;UYnD<pp&q(aJMX at 03*rE at Fo_}ZK*k^^2sVN`Tg~`sdfCeJfRU?L^+f*k#l=#L
zv1fB`+FO<%Z~uc;L_KixG3sr{*p=&S*$vJkV at fg}DxRWT?xZ{)vf*HET+OZ^ndjey
zF1Em)^WzuU?|b%-7Tf<b)u}s?z4r38CV*B2pOmSR!~`gMaV?~zN4UsrzT1S*#UL!M
zdx0UJ*=|cNtJ(lXQZnZj*x%gSSIBzXhN+`oEHCmgW)VIUa}qzRF^Nr<han!l22Vby
zSC}M|m2!?T;iNX^fBN6dp at PM3B~CsYfUIau^0v}4D(j*qvMV^WPk at ok8oBaxl3GYe
z#M5F?8C=8e0{<!A<C?>L%d!<?KHKeB0u|dK{~@^=iTgv8!kNyN%m;m at 5)p@*P;Y}U
z at h^LajNPn&EMbA>EsnY<-!Gh6-e-h8k%`0e;KQP_P*()<dl^?C6CkSsdC+(~=Dd`T
z*lKg;4(48W*Q?El+iJPmX%6H*Y(zZY`I)VbAE&f(A;;z)))XzNMk>6slOz@;d at I?i
zYx6fKnqf}nlH$b#=S1kE*TKGx`;(4i+}xS=4Px5(ME!-L at Iw8DNZ<+g^LGY%4r;7{
zEb}b at BbUOjzf-***@rxG2Uh&S|rCuK?j^0VD$vTh;4h0H0snUNKqp~J*%l%Reyzk~2!
zz!)hw54p5od3tdC)MW8u@?;|*pE at JoQQ{4 at E{fRCmYL at E0mBC3Pu`s;4QnA0(uVOC
zH83CNW~2DlX(Rt(X_|eOIsVp0;P2OVqu(q at -ZgT$uK|#|qEzaYwiC1H|H at Gl4#<D~
zI@#ZKx*+ at _q=V2I)JELkQ9lM6*0YCpCjO>$KI3mRm|IX!h->|ZirZOEu)G at iAGe9r
zPX!kX`oCi6!rQTSc&6gX78J21s#QaL%|O<T0rJ}78{v|B5M1Lv9uMikJkv;#5V^~a
zUKPKhpJzpN6>Buqqp<I at GUI(GTDIt`a-JakonuVs at u`@mmOh}U6^dxJuI^48+s2%S
zBf90`4e$<44<C_;8=&fSEz=MdkMoaNQj}l)eoQ$@14c&f5h1GQmZSz+8ad8-;c4Dt
zo}!zxeouI$tp&9Mg}81g3K%JZTQvv=$~Ol;E0}s%bvPN(HsTu+6UlYf?EL~6^`=0U
z$yQ0$Ct4eA{2SMx^wbhCWt0Z&Z*Zr|02li{wnviKcHBjFrF at 4RDfCHpR-&Q3t4XTH
zM}I3#)aq0t%;gT*NoDEf!KSsw41awXCa#+Q?nk*%UTD~!3H7YcJl_1;n~;VtA#225
zJMr9l4Y!JmV1j<zh_&i*MWmPaI$L|n7d_TWPZHpalQuN|^cDNyuctBV;iQa{9O<C|
z=(R#~dWUNjrhsDcp0TS>JzGTlsfznxODr2|1*|y%%^?(%7WFT>h>KIu+xMX(;alpU
z{MU}Jn}3?Qu|C##wT`vEt~bU+X<z4J`=E-xd>n9Nj`fe-rA|~boEbFUI=OXDqZA?0
z at V3o9R4>~TGTrbdYY<V|qnn$A0g1oT=l6DXXc`ON-*1iR4IJO_5r2okA<H~!<<BXu
z1x+_R|ED$l_a$@ctBC;e679TBX2%^a&}AWkvsz!p?J8&gJyT??erB}}?4wj~kHHyj
zpHTv+D3W>qI?}ZJ)~ZM!>}*EPh`6@)EA0nbBMPv#fsJ)xR}6K*0Rp6-`hSvmGPA%8
zYET at ap>=tgL=Ut at _{Pc_sG4b`Om89g>N4*5)6WT7b2m+7zgc+1qhL1ti>b#AL4$Z7
zkgxHch?#6!K8d7O$kv1#P6D at ibYcR!k|bVnVN at 8_MSTTMxsc7AW6ZI=G4^8E=aY5T
zd%v12kqJ$u=L;h_Q1Z2{6iF;13U*5KKBSaegG*%vtuvsGC at F&>;o3ZfwCz at pHe<rL
zRX+I=b!XUtX4_0;s~L`^>9%G1q1il98j>{G!_~Bku~G+i^KItR)|)h%G}^mKfRKI@
zotNuyVT at 33`8wZ$yL-mKXM+)OcJqz$VyzvSn9!zB1Lr@{&I6VZh?cNkz-jBoY*VXO
znBUQ_!1#n^hdVybJK9EsrIKEZu4Fwl99C5JC45{XY)JeB?S&tfJiJ4cx0=2kd!_xl
z*mPNk at XtQ<1v(WutGI2}q7vgvgo4c-2jia5+g|$h+)=ZMe}?1rPef(>Cm^&-cn*V4
zVL{ryG0LX#|4UNlI~B^)kIEfM9UR|VrJ>iHo0jVsox}Pz24zcG#X9xSL$**$Aov{C
z4gxA20D1v%e_{=w-@@X?wB8c8Fxalx+=~_Bx(`Yg6ts<RGml_se$f(iQI=IUMErE0
zZw;h;LYHCqs)B9}R6w`(2p at X{>t}o{17e%;f5;=oV!hrlLfR%!Z9f5mDB6>w!6bd&
zgeg8xrU3!*OgRST=k9sZEtPC3e_0)_jWwWKubY{1Fda$V(&N7>{5y3|a{Iwo^m8#*
zq%Wl?!(YD9_Dn}dvGS<hU<#Db3~exu7VI0Qmq|19o8&QI<<TG@=MTBTKbh1EtOf2J
z!HWz?*}3P-beOBm0LS^O9{=^U!|W#)_{rA;4fp<zDfA9anDi~2#^c_N%0-8W)5#S-
zjW1vupuwldMIZe&4!<LPcV8Sd&$i!@9_*o$m7e{8G at ZrlnK|E2QRItBKwqWJ%R7)b
zJl9`;D(#x%-=3QjgCNk07r=9Ili0udN8sRVqS1X=&yp?=Lm=8l;Oe3RYvdmm?7*|U
zSy*DS{Jq~}eNQxIKWOP<D3PAqeAib+e4p;jUU?n#&90!xC&U9B8K9gh at 8HH}VJST(
z+8b{45mO0Zu)^5_4+`;3^^_t%x7<ICb*GaoU;(=k*?5wO_UrYYJY2aOMgOqduvGI*
z=zh)~fesG|E+ckVoD;coqhYn?)t}+hZ3+6}dpqr>q;iMy|9yV!pgLBGkq#Zs5Q_Hg
z_1UIDI4~P>5njemHPYzs#?;C(iGHpCuK;q_9=Qx86(!ZoiJDFD+lQ$+{#I2BRCAyM
zoJ&Y>tlX+ at 7(QQ;&X)?85;ey6#Vos<mR4POZ;gsWH>5~S+r2_WUR<w=QFc(ss+ZnQ
zobvj<o`F(dI1sTA5}8=eC at DVY*tK87I9F#OIu-67bm77sxvFGM8alsb$3F3AOCMZR
z{N33_+$A&|h(Dy(Em*I1jHU$*k8JcF%Jx>HKcYQ4q!@Zl1~_}LYBd{<dQ7&0cB4a(
z>hh;^s}wWG1C`L1J4Jiy*k-?_uM0o-OWwT;eGD(qwa)Fu`MgJDFN#?0cKTxfb#4Qh
z^)+klxEVz{p^L2~$#xmy=ef at Tbz$%le-LR{Mf{icHWzZcITbj6g{%D;tC;y1JOtvs
z(Ty@}xPu~fhjWB#7W0!Iocf~0 at LwX%C7xD at f8BcTt+OUi<OB0W{ZSv8ghUOt%%S4O
zDXUO0ZYgdxR~H1?Uub?$giR4&AU1g138wreYgHmT>2CRJk4_%>r~m!5pG;B7a^w|L
zQElU`fgipRU>)|oeSbB5l1FmT8>}BKXO!SQzz9fuyMEkp^W?aQhUFS-K4 at alpr9g&
z;qXPZ%p*3lEdGPW+sO}&EDkPNPglZhlCF0qKYnFu{Jyz8`FdvsZ}H48iFt}n at ntj^
z-fESd at uGSOBr^Wu{55$A21*bzwK)dLDV%E*T|6=#XnEsqmj4V*#<2v>9l(mzh~oxH
z=J<C7=~QQ5j=+P0xo)BHA21Glz`YrU+6PHlz5_$mZq_4TPGhLcJ&`9sB|=qrl#36R
z%h!6Eg&`Eadmgubz3js_J)OH-V$@HCr3LtWfynmIebPo!y>{L2H0FvCPFTTqgLL#k
zD&qsl(G)GSAtb0+H4phQPky2zFHK2$T_5>pqok>UJJSQN?%5S)9<js9ht4IV7)IsK
zz3D%tB^C|7(hK-KNwO_y`_es8R0iwtT>SyBgdckz{>e;oxHm3t(ya|*(*mYJ^&?9v
zkV1&qmP`C~M!4ld=PtwwnPmdFmL2P-<`h-dQMPa(zl~Vh@<HwqT!QOs4qXwW#MLDz
zxs{P@!0GCP5>uWe=)G8Zb^BuoD9(tZ;(r`_#aTzR^r*Y{IqUb!ZfzERRbkLvrY9*L
zP(FLCPs!QnFif>VDGpbgvclS+V$_k0c54o+A6p^$)?EeMMih()T@;N at p<>Bo)8$zd
zK5oJvkN4o`rl|^_S334w6cmfp4<0KD8b~_|IHMXrB6y?hH+~>iB at 1rhqg<J3#AhIY
zkB9>mFp%5?n^=+r&eMQ648Fe|cs4Owk{gyDPI~4F&({l1gKb(+b$x%8bw%ARJXv=y
zi)y3k77B_yAw-r&o@@}C+N22T)B*$|sI(S7)-=%o)|!c82GbCp_pD1cKcei3>v5F{
z<=ld`sc1^&O#G6-y1)F3jSABB2}Qgo?2}X?BtLgsDki+K0A#Hu>M(!~5Bf;uVAhF|
zxmnv_dKg*>YkG3;qJ(hBk7{K>jVP at Z95ExIj+H|Ib?6>Mgj6yQ8nj;6bkV^*6IIV?
zW%lCUTs_H^muhX>v+nzGC^23u8d9q{L%WKzU$ymuTsUqcPH7DR@&*<s;o0FOMwaJ8
z<%6FIk*#e=>}e4#rgfH-q&m$3X at Z+rCjM&E0?Fcy#2E`dT>bE6=(&7fRew}lbTZmP
zRc5_CLuBTNuWb7Me!ou$f7G~7B^{HTr<Y+F=#(}=Y<xkvF|~l^rjagCCxI#yqERa7
zE9kGw6F(gl*dxn>6Yr^v)4eT8zgM~pDC}|ENE=29BDW^^%|&(O$C?4nQmo(n%?qG+
ztPApZU~j4)xaxbve|7*yV7jNP5^5nAz2LJ~<Yc8PO(xA$d~F$I4t>0?!-(3r+xfP;
zrmZ=8jI at I6ZnQcc?G>KR7D{wekKdtk{X{z?Jm*ETmV?)EZ^F!mH!g^zWy}ydz7jgL
zA=yy|X^0Q6-`~u~KLv3R*_tiR8lp~z4#F=;MijkDCPrN}0!legN}ZtcvDRpvL??h2
zq^gqC7gmMEz_hwr2FO%MK)m^r+qbO;b*hSx<x(xMo<4$VCzK1$+d4nb4z;aC8lcNW
zYB?{6%+CiRyrp>X|A<otD|+~zH3dxT$YNIAhacWvwU@(IhUs4N07N1d$T1YPi$Z<}
z!=o9{QeSs&)HY-zHX>J|?#rRzwqTgFt-&@70WyH}m~}@+0BYf3v%;K@@9PQ~Zp2}p
z26sgHNJ?h<4&4p0%*LH_#TkoD9bNzWS;F_{zdS?f%C_#2MNcqsTl_ru<Hl~04L`+u
zhV<5!s`v8BjtKJZ8>bRGzcU9A<;pVL#K)Z9d*#-6!|Ds at ebAxLoo3l4=iIe)H=FK}
z)*(05K%<N3qcTLF$}@2Q==M25f}*EV<3hlaL_2?r!hbmV-R{DCbr_ODTFo<wdHf&^
zdxoabX0~nU{8^R(j3-#ny_>aQ>b`rXk1coLr!Dj&X@!;?iJm?-BwT^8$)PvCzBBx5
z7aJ&!Ef9PR^Hl=Iy{1>=M!39-A1iXmRbCF(cQ;5Nefhol#>kluhNUT)cL__2^IE-v
zcPl#&+vFwc)plzrW!F5AAclPF`!*0g&hMJgt<eYE2ho;0NaL6H at _G%DlIWV!v3Qq(
z13`m9OrO!ASFDNQV*Io6E4BczRC|JVFb65o;(&n*?Nc)zSH+1hl5)f+7!n>_Nbem7
zN<{uzk6%-+;vW?qRBd}5zfueJFbwil;-pQU{v_7*xQD;k`3H)*YP`i22i)xei0jP)
zJpg1qAO)1)aN%Lf20X7KVbCJ9wak5Hl#+uFpOCahd0i}TpIi5L&}s)6JdAbRpba5x
z2^zh!sp?;T9i#r8{!Uxs{aRzWd6q)FC7ny8oWshb at lsLtjrV^>{8p+UEZ%8&kpVjD
za`%p3QKzP8=S3BCWpA*l&025#Pn^R*ZT{T0ch!;t^Q{*}^`=5M1!Rt$gsApcLtSI%
zHT<Ls>+W00efFqmoOvB}5+e^wM!|B<^<cmRrR|G`j7RfGw?8qvK?)voq9*KfZU&MD
zO45bHQ7D8^EI19`L<RGPKN6oTY}cp74u45J7qSlhSqkF>eJP3P4zIbR$6oW?i#vDu
z1lCu~z8WCDQ8=n1Xf~vx)y++}`)l8XWaiI>dV`XDo=XQ(-$huU!v-*e;jg;H<(tkp
zK&J{+OcKq~OAfk+Fp<tvrn4&dkl#`%p^&)BgEmIDCBofS>Xf|=c8S;8x+(40Xl-`&
z58<21oJd~#e`paH|B$O-tTT+b+2S%6ZgaM);pG2R`!ir@)YyNk+~2sQVj^^YRZFgz
zD9JWa^G>Uy2N@}Gx5c~QzXJ*>`3U+Lb6UKzMjRssV%yH5iB(?C$NlOjVdn+beZV?v
z{uv}Fz~f{-J%~$<tFMxBKzmQsj+6 at 9QmG4A36)tn{f>Rg#b0UQP%!ewr;TyYcJcQy
zEjAVzV}k%`aechO at R>?^Hd7PuE$EGttkRc>dS?9ZFj`QKp3PyFzIdfY?Dtl4bAKdu
zT at _1&R&f&Sn{Y&&kNtVxfx1y}udm)E!hzJoo%r=#aYsL4?f6*!CwNut{NKBOVi?H@
zv9^WiFMt1zsr<{z_vx21C+~_rRDEw5=6SYb7W`;To|yjOmrk)=_C$t7FqG{-2vg9$
zK>P4NqWebQ(dw0pkQS4rB*F_ZcVYiO#P>8RawnH`UZ0!;b?z%MlqyFH_xN?kUoq;~
z^Hsw0PC|EO*t}@UgbnaXhwU#_X9h`@GQhzV#W2OwE655nHqIMl_xC?xz|VoRnhcq`
zc!0*{d#BFYC|RM>k0+n%<i{U<m2=YkF+KRq7PPoKJQGa5o!#>dRfr!{#}OULi!oF)
z%U0ySCN?r*HCqXX#Lhb<!PkIFzPLL``qPCqvau9hd{?hZ&8?SwB$us0nSbo>Qo62X
zucv5-${+ajbue#H7-$S9B;&6*U$L2PeJY(Z{9c-GP4+O0#Cxx2ta4R<x}c1(DVgCc
zV%;kHzBx5YE<Miu03PC&DDvF)Zb53F4rgKybv5 at _n1#SgKwYJ!i2XalNdR7kx9o<g
zbj%D at Uq%!hH>|RXs at HUx8Goi1F1YMZ%eS_=?8bm#TTtE#w+C^B9bH07ou}fwq{cM`
ztS}%4f at -SB?l*i2wH;?D;7UhOF{4dY`UOi3==FJ5xCkHdc5Vn`<8bx6Q%6}$BG6tK
zUWG2rjm3E7ghNOHZrNY#wwLe1hU0H$3JjSIA<n)LR?x7J32RbcIAy at w?RzD;nO!B-
z#U3K$^g?U^<S$}+1l3a5D;iojks at q#S0$~P$Z1!Pi*pivl~#p8IqPjq5s1V)S-$ku
zGUrM|j_y0ZZ)kmSCF*gT)3<LmF{Wg)3UgP)`wr0`)P51>UAc62M at r$)$9)oI*x>Q&
zfkrFu)N6&f**d-P{j2Q~AM<!(>i#8qn!|6!(BC~CyEkbXnMl^@y7GbGd at P)<el!Eu
zo#!V0#wILct_*9FI&Eh~FBXf#gd4k at ***@mBM7Tazl{O>VafW!dU9c8iLHA?J9
zb00qG41M(c_L$Z-eTWu&?g|Z87hjc~@4c;}1(J1FA^jFSvbvp9Yi?2C-1H*ZETpUE
z@$yXcwa}Y7|8rz?R{d0JJ)Ze~w{CuYDhHBl;@`}@?aQ)4v$zT!Ld(sQk8Ny_OL2wZ
zJE*r at HQ~;Xo0B{WJ*JrvOS!X`uG%8c4SiIM`%K!M4 at w6{i~9bq5vdCEb2&T&Tp<&#
z9a{0C8I|re6}9TsU+1+KBGJXIGa2k!L8UU!HR0o`9oe5a{gj`t^zb#oSSPjlDTW*D
zbtQ<M>ca}1WFgOXc}&X1=<5D1i-c=jC*R+{BKTvSM{g%xYjrh?pd^mUZ~w1JPn<J=
zElvlcqd!`ehN0Jo45XvJ-O`r#G{U5E{VQBfQ@=)q2p0NLyrjZ<Fd^7s;t8eN2rRA8
z<-n4r at q6jKU>kE!2lx~b at 17>Q#uyW%Hf6Atsufg-JQasA6n7y3Sa at y^0qEA>t+?UO
zJ!}b$Zq;(KfZ)o}{?s2UIy^s(H-w$D*1h=ovdq#=`B~YMQ)Jj!d8LlhcwX_^#PeL|
znqnEdFV|J~?VhdlJO^L?G>VyAtV at ge%>mL{8@?;*s+q^B(#tcfU&2!)-TEz?mT3x{
zHpL3#y-?oJQRaF7(E(|=`O0NUxyV=8<(hw!0dAD at NT=~DlUsThzN;y2!CdXL4`?x~
zs%y$ov<!&$0!U(zO+UGay<VBILNdElqw2$7ix8pWHb`qd at l@(e^&Jh!dTFqhMolWL
zW=~{Fy)97S6X*POv2D_ouLK0<R5aLN<YVjHVjYUW&<7&!FdejaMZh(+blvym55fih
z6!qvrFw%jyYQzlaKF%u+0z`jeZwtMJCFlhPwHJuZ6+oR4=fOiGt^ZPzvXZ%Qab at e;
zUjE&#WgB|4bluNdR$lgGV<lAw0td{(40%%2Y*dVl5{984b(FJI+0;)&2J;y2SLiDr
z!ftSI+;Kw at g0JNxX}UEC+8hq+ewJGaT*8 at M_RD>eVF#X at tDFW>5z49h_0lVQ9!|GG
zL2W;%x&mF&l1(CCNj|N;ObupBDq?T$anTohfoi(;$<UC!_MlB~bW>APjMVNA;Zp(<
z*6$(apEAD7zuUEi^*_sy)nbR30EZ&ir9&<MWvJf@{T4j61pU2=V|w~j3C>SG!-m#k
z<IBSwnPUns=9n3;R6 at toe+lKf{Hjtacl!M?P78ge+A<y&c88fUCn#aGjj<C20M>1Z
z9G_P9%+3Pu4ANQZ1Mg|>Dm5y`y~)v!sD;E7 at HgK9;ft+ZqiR!oe1-9A?aop~?%ex1
z5}gqI?!2e6w&%#Qz?hRKEz~^hht5e=?!VI?z@^8!#|Qg-B<avTisk0{LM%(nzXYE(
zUGR8M_}r={DQEj4I)-B&38KSCYJQEI6a`oRb?Jy4uQfPn at 8Zs_AGNM2$GWgj*_?4A
zO_={ndcu5HW9*hEb0Cl1ATpi$g?8}oR6-3SgvFj;w2FW0^hV+EnbGtWV at UkOp?(H8
zmVJ at 0{Ygxs{?{8*JfUq(UfWECk7JBnuYOT={mo4R(Y5Ro#4I_2XNLx7>3&$lWk(!e
zqr<JQ_9nM+AuVAXZor=IkdVX`SKa)55rk_z|MxmL=ZXF%O5X*brR~Y&BK%45p at d0U
zvcWxvDLV3j?sX3xkP at YCnD0AzQfGqdlB`Dw?gFA^@(7#ch&7e|w=djw0{}~DTRu|a
zC-4%}kGE(;r$_8ET$bCUF9q$7a-znJOTOuXu`K+fF9i-5e6GdOy&3j4iW4%WMT_^P
zfCTmok>giAG}aV_KDzTv6v8B`q>AI-V*Z5h6n1xK!JF2o$YncL<-|?zcc}-ue76VL
zWj1b5E<M)}funB*IN7(Txe&!to)BS+E}KlcGXMB-pN7}&<lSGKt7!?M9lp+NQYY5u
zCpu$cS^zkIj?KyderfMb#7#imTn at Y64?p;AM~kUn-Yl`!igNLf1Ss- at +IsgtXc!E{
zOx#yKqn*`1bP{Ole=<u~{Z8H7!>PNzXYB9E0?GS9a7(NY1!~+9oYB!t at HKO?Ernwv
z&w<@A`?xoHYm!^1{r_y;{;rBx)%t{W&=b*`{*1LtwDk%a>IXrcHIqai-QqLh|6qzA
zrED?5clN_~X6T3m at R^njX8OMy2Vp~7&?C^*09NMg)2`^-m=a^;ra>(6c`Q9+W79l<
z39AvRw0lDvwAE82&HPNU)o at j}t(3UXG+LPKePZ^4i`kL(S at a0!udnc%K{;v4(xFR^
zz<c{)l2ye~`ri5>SBQsX!o9h>s<?W2H0f82Ii*^^t|iuStn^RuOX{@q<&yB;bQ)5^
z%erR#&p)eVjj<WggI6d{#csb3{~hz*G1B!>?$*jwlj2Y+ at 1g5KH1v2TDqLJ>nc?j8
z>=6PgQVpWTkGPIUdeZ5(O1jfz#y!!^jaELg=com%?0ldVO?-yg-EPZ^eQ9Y5tFD-{
znKSX{=N~jz^Kt|bJs at goD++2xy9=P~_usor#s8FEO?`#puBT+eM5>zR|B)Zy9>nAr
zU=O^qcbiW9Ryt=Zzx(BU4{*VDKZNuDNl!Y&{3La}K(3|P!S&G0!iSmApjD>g3Rprr
z-rm;f2O%F-#nj}p(5s(<J*;7$SEB+)e#hUz%kJybJnh<hA6deQc<lu2#KmTc$VS}!
zGPxd;0~@2C^FK1*!6zU8&isJ5s8exAo(KPF5=UQTs8eeLm8ELs^uCUuO1z32UV;B!
z86bF&RgvD~cR}>()cTd#BsZvNy2wu>!>y~HtV@%zC&xc>DQ9jqf!b(9f*4Qsdp#(-
zTx)uM0S@}IMpU|&>x&_`F!A(k0jCYFm!HE=idoI=VXu(E={yg1<!zrOvkf-7_0>Yc
z`A!BQhKzr1Gw>0gq8=<1v?)gT%=bu4rvxKzCR4!&nns;(q0X3dSH4ppt`(vF>rea#
z=op_t64#6w(Xcbz%Fi^~bEFA<*j24(14+s2A3fzfx8&YR at -3cb&unP${E~aDTo7{&
zFE0 at ImWPL1%ix+v`Bbn8*7$ZZPr_^Ww*2sop!^BXU5IlWHIk|d_TD%Tx*!ok#1S1V
z^Xw7~TA30FAoDu at uV3nt6^8<a43T}D-f8eU4*gf$h35v#hm;wnHv)}TOEUfm!Ln$X
z%>^y3D_1NAu8X-dFWoj$b<GGcTI90X7IoOH!G+(>0blzW2<p{wPzCx(xjhLTpftxV
z0`~Ztxk1!WOT~V)a|o)<!}sOTuNQm%qV1d?eMsXQG2-4F-XvZSlyi;|aR|VAbMGod
zId^;EnoTjdMyEx^)c=Y3q>bOyj-2Q(Q8}pH`w8|l*(ff`h}PQ{w=8WA68R7Qy24?k
z_)wtLZ{Hn&Oz2{2KE4Rg9RZ0|{cWBq^x=J*9(Q&c8oSs{{lIpx*okkDiT6^@L>y@!
zzE)9B^RaE2n=iNDaIK;Td4XaRVd<RfbX<Jw!ThC6s3EV?bV4z1x!d3a0}w1r&=!Vv
zayU}-%G7VLYATY+7vx<M=W+vPquU^FAiXs57E)*O8TeG0rpR5)^Bu{o+t>~bh;<XC
zqab7!B&E>Yq&M2$7dJhhfiKL?GuC5<{f at 4$H?F at JeyN|Ld2`NeEaBqzhT>!h^gx>T
zeS`16&F3#UI~Uqok9qd?7fW^ID1S<6kReHE{W|E_8<!uLU}-h6z>iD)X-}D3<>%Li
zQR>E9Q(sKlnL#*unz{aVd#S^rQu_|VZ}NaNqwc4m^gU-lv#G)%fZ%gS%4UyFv)KCT
z+sj}xX7&$=vuo~`1NDx2ec at b5hh$>OpF#btiD02y5asI{NWu|qaou1`A(6setppP!
z8RCLhnqd|ys~ciPF=&j=qIzS`sYz at B>`=lnU4GpT^PH4}It1uRn_ZQED>CWGM>){N
z at vA~pMy&4$r2`P2gPJ^c->~r;XMC~F2tHgYd<9JuofsmGA<v1V5AR`rLx#a!rY(lm
zKxEDTZ{HgADtZ_0Gq_EVMBr?#(kJUf%twqoKdHN?r5}k8Ildq_Y+%95mk)FUL!R4E
z)e5&>g}$x4R}ba2>B`v~OZbM=eLr?`d+X(uZ^v1)JQos6We*fyc^qY%EW$Q*`~H)A
zlc{_%-_0_B%$91Nz~t?SWE$MpRA;#U;QJn8c%}tlE2 at NZsf*Y?F}EKV4U5C|n$Y++
zaL^exc&Vwra9a{v0`$(5ifDyDqAoMAU{2o;Xaz?fNK^h_95ta)ATXpDvze+54!I2~
zX}MjhKaWqq-x%I8SPc+Q`MlVavLZDafEz!7nKZ)c0`y&Nbk4Wfih1x0&x0p#pZ(AM
zhQpxFS(m|aNQREv<tSDrdR24t3n;4z$79W|($#IX1?B-K)pZ|)$1OKu<PX|>khRak
zOA1ZbX2pda4nLXdU5U9G*awK}+%_9BMrOIl8uKUfX5BIK(VN+QKG1L#1sLq|TBy6F
z<&EJ_y?9tYH!eBPE&9`SK^NbP7hn&T&U_kDdz?==xC2ghntyYA|GQP0!++kz4q?K&
z-;^cjQH~WV{(tZxvW;O?cB?%J0ON*NZu>pH&#HmGLhfCR80HGdW$%78^9jiRK$HXi
z13syx3n|<G8=jh*Gu0b at u;Ed8%4umbS at mL&Ipn_cx)0VU*5zqoid8gCFL2dlMr#Y0
zBzBA)4Q7Y-sUvu>p4Ick<aMc7VeQL00n=AO2Ft;_ZYp1Van{&)*w$%fyb>gR+nSyK
z_+sOR_ljm=dO%#D__Fe@$wiz9+MBlMUd7b9(9#f3*(DNpO?7vihQ=+LW{NCeBKnsX
zp%k<Gg{E4f at H#~0QH1{1dK7%%BNOm|m>PC1z0eA|UMTCMQS(?TZJ%A$`bEul()viz
zBE92gahsa{miz9V<6rYmyTJVnb+ZCg<I1ughfh$_W1ns32|`nA#Gr%UZNd=K^mRX+
zug{q!@YLXNMdxG!wWrB#w;+abgdixdxc5`6NtS at Qby}lIr{JHC&A|Wd*l>N!?xMt9
zuVw1VfyAv4Sez at vzwx`kauH+4ZFAjoMO%WHsZw*LayM!~0JoQ=qXK?tZY$%s=A2d&
zeYK50uyqXqpK~YemD^t`(6D*DiQKx((W{ND4Uf63uC4DeKV+~q4oc^zgE3>L!Q322
z`mThFKybHg?zrdy30xI~_)L&BV<X}!eKAKp&zAe6+*nQIm3REgv)35uE~#t`Lmh__
ziP{Im!!RZtIHUMH4_DWgzH4N054Vb=7wrX^)DGWp{B-?_7sL>Ds-H{H9E-yepb=wW
z1GtPvZ?~@ApVevdy at W*E-RnHIY;SKn8fwVjsJ$YmH#DMfh36<N!R)rpC!_fU*sx-O
zyv^uT2Jdc$;Jqhrln3KwOU))_nA6SPq&8iv;R4V~<!y6pN4|cV#{UjL(57_uKq3IL
zurHHz#~fkSZ3y~K>XI}(jMYz-TI%M2BuDFm;YeY0*yJ2Cj?t`cCRT!?6lL7bZowkm
z at 8oPD$G!IXlAo1{4VKJtICF!OiBZ%|ok2#zh{*d+AN_-pQ$|EnAimcX-4G3|Ir_w4
z)lYlOZgqNfCjmk^uS3tjj<!bU57K{d_F1#}O7Nl0XFbbHHqukUxSlTJOdqcix6YRv
z6!5NE_dE=fe&^-HKtk!R at BD8WW?-sqLS1x+e5^HaVcEVQJLySsv_=Q7^|#mA?l%=0
zpC{OFIr*P)l|Iq>2s~TWc_5?DW|c6h#l%(NR&0^I;Zqa6IKtX&UG+cUKJkG6zbG9B
z{FiUtFF&~5*t7NuqAR&fe?6F5TNG<nKf94z)J!2-D%T*VaWkl6;%S2$LgVg{pDpI+
zJ<Pxa;~Dm<x~EBOuMfprC?xAL=sc*dVl~E3+ypezD&9N%79#_D_RRKMv4m*Fq&D>9
z at 4~+DDYKLRKvQy$IeJXoCANNEE1k#BJUgmZ7A3#zHxHxc^iw(x>eJ%El(oWBUBU#M
z8)Nr|DD8gMG8MO&MsqAi>zAeZ235=5p89OTEl_&I66&#jH|}z1*G1e$HOWhlJHLP{
z-qufQX)rZ(ZTX!-*@J6(kOqo_+FbYejcjFhb2`_I8i2}k!Mag-;wJ1Rlj>~-Z3W at I
z>Y)WqtdhD?<&P&!eBFa0s_mp-tsXw9UBwj!ovGFqJ0ZiyLZq<D1Q_R9)wi#9_PT9v
zTI;OqZba-_N_Wc&xk!oCWCdt0RS_fMKA?eF;KF6HnEhjE22jI*V>7O;$D_NX4{^49
zC|yz0;OazJ0=wB at 4;ROly73a4^`;V$5#1ZZKzl-LHY3rWpj0Os_vAFNtFkDhx|D-w
zNoP*oqeng%x6!STk42xx0#Mix5Wn8pkL9JL4Z`Mfc&&@!Y)Kh$pDw~pp0xURa*Tc>
zIKU5CKYaG=PY^ut&hTJsN)TUEN>Ca--&&sS{p5E at q?ZORGPNO0$)%wOf<KRxT~PIS
zc%TE=z%albi=1h>y7k9Mz{?lDjfnTp#dj&GtNBRxmGr^(5U`JzZiZg_U+Yw;Bk}I?
zJP%@bN;?id?7<lj7w6{2C^(`$Z=Y{;-oql4kSf4F_d6vi{Li9c$M97yK5#PSI5CSi
ztJYMTS$QGq_$ij3F6Ugl^=ZEJ32g$5a%@S%7phiI$N0{uf8TQNp8UxM2&*Zv9xg|P
zlJx+ON9YoW!#rQu7-gA7`ByE{(i9a_ at o}eJwKbo$?fTZemrZ{=848*?F#Oeg>`kwi
zwa7)ik(1?Cp{W~~d4Z+B{>ge3hdgY;6f_seUvQ@{FO_UWU^C%-Tpi6@@rez>A0E4V
z7ffYYh{ln)CU0bCFs~=uUutAI*VP_6O>t%3do3Mu&nrI%9GX%&df=&cUiG<91HND&
zVVNs>xcYSn<@0Q#QO(vksMA&S4AX02b(mB at xD2i?Bdw|k6ccw;E~?{BdqDE}U^J09
z`|@tXv_F0r|2IioNX>vTZ70Yk3vf0~pU@|EuA55xC%aedm5^&0;(%c_4`#l0Bd-O`
zYbuZUU|u{K-YRKQfquPTU{WD|(B}orY#PLROZDBbA!aAoh%sdM5Qn^rIIZ_$CGf|(
zLXc0^`<wqDJHJmJl;OpaiZX*V^Jf5pOK+5F%fo0QUifa5t7;(JHXnGFTzxBUVHuB$
zS*e}nzm&!pCs0M{9|lSq8saPGCC?pzM>HS8w at mWf6r<17tn(|t_Sz4LFwR(w*}0Ft
zs|m-iU- at l)GKd;mbC@(ua+2ua&S~&stnv7in+tYL)%*On3YkPljON-ZK2~kP4bbjB
z^ePC6rdXP+|JVA8{t7qls;l+RUVi{K1o>6LIYF$-<4C5>utLz8hx;}Aai9I%^R^x|
z?djNX(%1j>4qX8IoA@#DjceJ$)DF{S?%<$Skxl{hb$iLh`1QNQ`;DnjK+j>cdkgBf
zh}K#f@}bhU at E1P}Arknd+&$!@vrEAb%3o^*S9b;O5mf^F-(iKI1Q at W`7goodN_RK|
zBa-nT2m}&j)B|^mbdHfa!K!VSu54w at YP51xo}2RpO)nFesJi-EbXU~4q&3I8LJWdp
zd}_}ZmoZLkY6q5vq16l^-a9-&$>2a2faqka5&=#QB+?Tl3EtEr*JH<3w;=x#XJ7Y~
z&In_}-Y(WLGv%ZZxgu4qbj?_ANL)lsEko!22cxH0-n&}z<*%Q%G2=b&*0tO(GZx<2
zXZGhCVDML(_x8d2Y}YSAnm}CMU&xW~gRbqa5uHsCIc+WE2}#|~NZC}u#DG64ae%#I
z(;-KDbj#tZcDC%UX$<SE|GsLQ);FyXJ?U(^0n=3FLU+OM7In1OXRqrxN3jTm=#4vy
zZP1w-3eX8`W?bhwTQHg~+weJ5&b4j?Y6SOK5KfwO>TN!x<ndlM&ByNG)<}_cicuA3
z0qOF8i=<(hUB+;i|2mX&k?%6YSAnK at I)f}ACXSR#e+QV6I>XuDoW_N#!(;pR0v9&L
zDI~tR4Nygp_+G9xpCZ>x+Ne~kKu%%SAVuy0=`xS3wY&aBGhmRJwM2`p`mu9r>C;Yr
z*x;2AQ*mC+LH5Hwbw8Fh0H>&P<l_L>dfaHiN#8BTZb^NTgQXy+a!#|@aYtaha1tCs
z-7$5eVv at ***@IK_pm2}kkIr)b$6cq#&b~9e4Zg$l*bDpl&Q)1#O=b441)2=GeGa@)`
z9^LbQ`e=86Hfptv1vRD~mD<gS=mwk*)gI6bO#GfYi=bKNbMrMA0SP?XvfHZuDf>qC
zESr?}wg9dz42G7+*Np48+Ho*m<UMHB6S>b-`tN^WuT7GaIC~CTYX%~4bm`o|2y=e=
zQJvlvXmy%;`VT`&1HosKE$JJ5h>W_ek2jt4r*FT7joAJB at ***@a|+Q;@Qf
zP*i4d5Ml<_wK`V~^>c-2>;S_wicWuic2vTeSx<!C05`*#AF|h_1r&%Yf4NgV)R(rO
zlzLJ?(nvK|penCG54xarRAO8BcxyKpg~N2#pS7RA*N at 0SX!u-Qs;^%IqH1}mO!@1h
z>fgn*Jaby*_P;j71PGnJ81(%^aG!n8U%@?n_?Uj~-1*kamd{odia{o@^g{?|we-aK
z at q=T8iKNy=V905&;2taik2YVZ3>zqZ-)Vn7y;gYL^P$LcKfbI6r==<$l-e^&Yer%m
zJ2c*7yyN92Ek$z~Veesj`Blcro%<EfNxA7&>|FXrLZeTv&%hzOHI2bG$|^<oOg>HG
z-w%<f-p}i{IM7FepZ?@3t~Y5KlP;FeoxSdi7~wxv)oSh2exBAgFV!1Se0tL$0s=7D
z&;!q5!AfwPREiTU2`%XE$Djc-IuHy{qsz$(y<3!S=vZ_ax#*n4h+`PN8hybj990Vp
zAxit_jBCfC#v0xHFnuEk0J>2;Z{q5+f at l}k{C;^3#+opld23xG{72MTazdec#>q|k
zp(}9^*DS&dx<u=&yan{<GDBC{(p{nYHH-IW6fy at W_|*yM#L(l8zF~X-=q1u)$q!Yl
z;v2!`#J-i=cc5^uy|r->eBtgXIiM|rrt8Lnx4YAsmRVqrP_=2c`)^<oZj8 at izCRhW
zvWkw^0RH}<cT%?<nT+usGFi~oUb|_T)(rD|C69X7uv=xXv&1gWz7tZ62RX at N8?2h6
zFZ$j3B8*{-Be(BQX8z_9zIxcemiM`?JGqM`+(T!T`dFwsb=9pD`Ug8*=3*SAtk|0~
zQnJ45NUs3AY!6Z={Q`$gPHz_rxCh2Ki<jzu_}A_1rkOlRZU=KO`%BZK9}7sAW#+m@
zwW7<Wwiyk?S79VxcB_*?UKO+5AtX|uWl&AU>ga-abL)QKpdL)MSI#WMwC1o+iW(YQ
z0<$lt at v<DGO)1z*<Q&ItR-ehcWg9_b({l+51Yi;|PJNhFb4^KYwzsEj?HsxGgL<O8
zh7}mbUUZ_cKq9Wi9A%Eirr?R}Vp}%G&9s-*VK};&uEp9VP3BwgQt7>}+o&`^)Jx9Z
ztK at fnKF{uN)%sU%Xi!pYqHxSZmedn~kFalYw3=DTOlsj?9e_EQUx_2aN~1^B+cXG<
zxHbg>REBn{@S-eUE7Sv(2A2&?X-M!nxT026yuk!{7^>SyJg4+t%&PBvwKd-J+p!q-
zp&~9(v2n;cO|{K#6913J3b7(eyDVxlNUZ!Z<+$o^Asyl0xms_`OBdN5(SSYau)uyI
zmUFcflCT%Pv!n_TD28kliHY5PMmh)Y52r*-{zL4yjPVBF#ea+Q;wCZ>@5+ at wJJbwm
zpX)fRe0Ehs+{f2IC8^Zh_Ss=7g%I=l(wKBKxijLRYjqOF*H!cBfvEcDedNZuQFU5*
zJn-J!*x~|xh^3{uzPZG^Q>Ptvog{tqvxBdPa&7KhRg_5bAF@;)<ZQt!=wN-9ocdQs
zEEW!(80hYn*s9MzHQK4!koFXL%8_$cea1e)5cGr_F;)IDW$K at X^8ruBnndwp8uNZe
zqSx=EUC?(7YbhBxOF5y{MJ{g-Fu&wHt~~xp-uE38bF0V2tAdo?6PSS3D#VQK8;z?_
z6M)?|oIaegjeFU%%zn1&_RJ;xR<^Ce{B>AvPvp-nXzB##af^BHbDl%padENSR0{;;
z+iOX&98Naa?{F^@x~%Yq%%qQ3zW1I>_sJ at h%ChS~X{Qa}6bPGh({ILgITY$D1mS>k
z2QqS65gMf{eL at WWYhCT-V`T4-gwnmIy063Qy1NN=5S+O?jNd0>{&58FMR;rAY7%Ii
z2+nT$Pbr at Dcg9+IrWn=W5$$ft at S=wJM}PNQ2~7G-w>_4w82Y%^zK$)l)Nh8m^F at Fl
zv>;~0v!ad2WB<^ACiP}E;zKQ-Jc7_ikspa1n={9^C*G!ZtnEDvR#bG3>J<F1)nS|N
z8u;;Twa2>$1rfrm4fgg!ryLClviVh`gYP}}H}6jK8_8w4a`=yU1M;oK>er-fJoYOe
zO+QjUF*`Hc9-=a7G7nSkP4~dO3=$ZKhuutC9fa<QzkZ*mGiyA0>gx)A#CZYMgIbjf
z|E<5yTDo18nKWdf at ***@svUuf0!qZm2&S$uMVtH6MfW{)t+%X=BoCs(&0fj9YO1z
zn_L+Wuxc0lg%w&{ac}2%u(GrjvMEz3zug*X;?|u#OBt+V`Dd14ah}5dDSPSK>px9}
znl%xJoCf_tB|%#Q4g)ajVJvH0lGxhkkO);Us~c?~n$Z=~){BKU5cWlu$aDev?|P$s
zaFPBXsiXws`3#sbct&O|Nc@$USlIPiO0-FCUv}3?`37ge&LPv?)hDuky`EA33)vDe
z`6b~LETz~N6eU>9Wng#gDQQRfv>#I9Az2^=f^LS-@|68;9P at F|)JhBCj<O7~xcwIe
z_JLkyQdRgYe{cUrb#V8;=+Bt^!<;H6%|Z!TVVb1||CkHPfRW2&cTDx%Eb at 04vK~L5
z8>hqD)_ at Pxjh{}YS^B;!Bu?`uFJ7GIGG^#&qqCbu7qhH>&SBtPtXZR(#$Qo7CED3t
z=Uol!%2T+Y)TfRxRe3d8BC1q}4c`I(EtY8ptQhbrl;OFhWUU6RH7}rouTZDjF_z;C
z;VAVlUf#1?zCAl(FN0qmLjC8DMG!(5Q-4$E7yjoSUIr(l_NpZCvec|-uU{Ni at A<3>
z)GL$^bkwV~Zbw9LA>(9ObT>3(Hx at Zdb48ZDQerNb-g48N8(C(ws;gdu^*>if-5 at rk
zrrGKM!GXE{Ti<YV1m2eTaevusQCyun3G$*6jT+WRd`M&HV!9&!v<pUGxuEb{I=3`(
zJK{(o_D&$VD{4**93w#DQkcSFFAvm|dQ2H=<YIHh5Xe|FTE*%UqwFTU7&6C;{VD!-
zGp^MQOrIp)UnUpEM$MYK!z{-sP$X?A9mY_m at ep12FDQEBE(Z+qK<xhjlR#|0-#6Vi
zoSV&?$A;OY7PfEDqKZQ;c)Rd|gYed7dveaAGn--;n>f2CXzvk6<G^%u3JMN(<8Mb>
zRMOdewX}k~_U=aCPIr^fz1?uy at i-x#@Gf>SCK-0T3%CGp at B18I!`I~c-QgZ6u$Eqg
z1J=yi!$#T%`+*Db4GZm&!A6RvL=rJAyMYi$*=KyC!jL^@<DY?Z9ITX$b)0z>js7)u
z_7I67#>zFJ>^p6Wy^3$e88~!SBq1<PoIO!yvyftJLAEFlVK%zJ6+DUOD|Hsd12)l|
z=;v7A{a#(W?sJO1w!$o|01f~3SO*0CoOzwYea_Y*c)e at F>U(O4q%yH5F#pXeKhF}?
zjnK}Guk_b7oybU{b4{DQYp?9zg=ui4c+;B-I5rbj>K1YAcpVKz#U<Q^<9#5T$awtR
z_(qP4nT*RFQTQm1ZiYOzpWm;46GQ>UxxYMKzw3pIyC|&CjRLO$@6Q5`Yp=;Q6Klo2
zVm{;j=OfO^8`zwf#t#w4!QUSbekKQtTk?JIpqk1{4L_ji&nNrWH2YvQ#MNAXMXwL|
zr>o}$zF$8lo~tGwJP-K&`hC2A3GF&(m;-<n^BBK(`PggG_dV<&H2W+A0Z>B#Y&*Us
zu-V?2!+>>A=b=r;bZQ3vb^JPpyCxmtS6UBWq7hR3j^fjCEM#3$bx7qGf0G3+l7q6y
z`bFe_V%j+t{yLWTLBVJ?Dh?tps{Y{jhza4rLtOm2a%08@^~cPMRf7p5Cu*&(zuq44
zk_~2WEYI at cXtI~)Wa3Wq!A0!n>Zh-5fBBx%Z|OVxFMYT^c?=((_>lqrv7StAwl71U
zm)dDIv-T_X<<#q`)t?WoHdf7Ck-DBW&-AVJ|I<L%k9!H92vp4(nwYxC`asm4LOd{|
zKGGfzU~iW&j>~Jr{snV7?U48P10~kA+F<S*-j14482na~6%D>>LEwi*@nF&X*YSH!
zz^={<wu|jyJGlNnJXj3BR_?Wr+rI5<@3q&-qmR)3SO at E2PZ6_PFYAtnSo+C(?3?2_
zhc&_*uFt*TnB$Q+gqv^`{mEFHvE}%f_0w7(EwxZ-q4SwBweyHGt-TIs*YLNtc5OcD
zvoPu{>2uTRvl=Voe8xBS8QLtHp<QRX?19v~WoI-Ho5O|lYx<Nri(w61f~V2 at mM`5C
zf_Mn5_whA8=K-X-2QP?0xMJVtHxKhc1iBKMtF^I4>Ol|mthv1p*@2FAEi-y<vK_cC
zT#BJV-FMNo;C<TR(^~Vb&wAq~aRs9TFgN_W2sk#3!JK5ch?{&2?TylC?McO7cgdte
zVP>oe#=m#Gfv-=UY<h0CHrm8Hn%{D^i)uvF`(;mGDMzzkJKBx^SM`|_F2^HgPPP^s
z3vURG;6~I9ekR={!9MsnPI+ at bCWc}A?dZqkd1-UN^|*FVZrmULcz_UVBQS(HI7yqG
ziQf=F?Hv)!Awdc~Hl4{%0<8e~lI(`<hUk~AL-1u|3x047n-|}Dp%Zow-nAk}Ye<_*
zNXzE$)7owCcdEIvjU8;ZV=rvXJw(ODObD%k2q8!Xi>@2?F22z`mZ-S^9YSYx5j;ab
zW<S>`(Oiq$6wX6|Tl>hO>7-y{?-5^Vi(d44@;|2kWxt1ox>oqWsQYnWV`{^y0bcJw
z-^&TSSAH)02HUlKkELj=wR-&-XElg~UlC7Ru}JYyaf3#N=7_hm7)ssgaly|HKKoJ>
zIeh^3>xehvju^<|FJr;6Ig7vqzXN|B;CR93JC>t()%CfDhkv=|T(@KU3&eJ;D}P=G
z7qeNYCD4hyb`@=7KXd&fiOQC<c}dNhP5#U+_=)@w94TLqI941uMwTK;F*ck1ER1?_
z<EPR7`g;Eg|7`Nz<Ti|^d2PDgocG4wuZ`yv_V*tO#xUUFVB16AQ{U$SXLjjmHe3b)
zV+hcO0h?bs_F{7>G|%+1>tx|fE2maWZ3t}?tXHl-X6{{!&(wysnS{r)p-hgGV;!%K
zOUEKHLi`a!#M7Qj-Ec(StlSBBpU-<9{SpOh#NmuR#~r%B{YMQ`u@}R1VlVP)K6vOg
z48wz2yR5Zdp!D;g^|B-OG<yE&h<xCmg>fxm&r9}&YoERD>AqMRd+mADIkE?K!3XG|
z?VrQVv?q4$&FgM|`+(!RzH`2TKMd=of2X<V#{yr&_m2T;`8nz;qpcwt=Yo&pT!Xds
z^_}ISGx)q%N4v+RHGsH(o#Xp>Z)t<x&}Xh&I9f5X=7zP-#=q`A0`fmRSZeFy$qwER
z1b?m{42?Xmb+8^d17BD-eq?X#-4DO0Z`nV4B?odWxeng32d>FISSLItMx4v2+0ZBI
zI at h1neJ=;4an57?&(qHIGEjM~=eEdi(%XTrk?%6+c{qCs)@f^XTzkLghF!C}UdKS7
z at -^u7tRF~W7i%)MvJOlQ&iahFKg4{CcXSVaS!dxPz6&lZp79?80Q`qP;Vs8R9iwyT
zgSp1wWbu*v4XrGV-1X6Vh^Da*Yasgy-(SEyPUoSAg+2tBc9`4^8)$8A{JsA#Y9F_D
z((+{X8~RBD3~32W0+K)^2!psXBu2%+4z^=amJ7|rXJO_hYiYC$9Nm8RabRg)`0831
zql)#q=e-fUbK^MS-QoCs5P-O=u+_f4SmH{6vgh86e!ZN|=QOj}$;~K1>;imGo)~$G
zQZ}ScoKBiMA>J%Fu>~m_OpH#1>tGUfqJTY#a!=nMqyVO1b^?L>>zfDcDWLs9sQjjZ
z2M0+m2N)B!j}at76gJ{eHWk at OU{h>MQix<ByPJRC4i4t~_y8U*_BS6LfMxslYAvh{
zUb1F$Gi_eBZgxKMvvISD&oTfg#Mi8V#2Dd<<^q(MEw3K}vT&`Z(L&spwRl}4Hu7Hp
zwlI#k&>rpEd&{rz&pu^X76RFP=^>E)XkWr{H<aC{9f;{CD`^|!{q4PT<aLc`2o2po
z3xG4^8Xbc>cz=h_ at ipT5wLjmV^{_5t9lm8zt^!5L0v?_XyB;jP=-|EhOxSgVYhn}c
zm$k4y>`#-BMNV?sv4^G*i}(+5M_a5fhTk(dE}(Nb*NHK%TR^kmL62*|8Un<)))Wmw
z2k*sa6C6*%1yQ64>mIg-LcFBlf}_M~&m$zbOp>W@&LfV|D2~90#r0{(EReF%KP!;(
z at AhY5GaCK=1e at k{Yj%5sOw+tK;%@41hi5mOeSTBy_y0rSFc<)}U+;alOJHgIH(ScK
zd-Kn~m5{|`{u=?;e*<6^kxL;7(9Y7&@$YMh8)w7Ov#0+<KZU~p5QwAXlip-H=FZ~F
zakb>iilYxI)~!?4BWqFDAaoTS@{n#BxR<Ux2ugFvnbDk)S3z%7<LP7#+zlP$M)BC7
z at uxN}e6u+NtjBsDnu$)AhV6PBdKOwy```4z8gYQ_*X#&<j<4ao1tNEWT7zwhzIIKw
zp7(l${n~zR1gHtANoeNAw-&b=(Hf7o4_j3;OYT_g)NJM4mNrX-|IeUfBR>IOr!ex=
z2KH#qByvrcz~>z2^T644b3gO`k*l at FgYTQ)ofGWWcZ0KB03sjs0n^M0U<{TNqr|H7
zgL6do2pQ9f8RG}kc~L71d+o%%V;G=yu};<u_t+PEW&hX&e}74}0DTkO2%hLC^)0->
zzSxX&um}5R&+L)=a9`Hq+?Gv0IZc`dO6M-+F*o3Q9y7+^b=TsDgLZxYTQFVAFKc+}
zH~R_gu3YVUH}u*A+R*8#&)CVj%&^899KI=yunxdOcuCA)dq0dpH}Ms58~*AVsn;>E
z!EZGDI+i#f#^5>E#P@#i4S$2X#aH(kVD=fEo5?%!&g?npi;da$cFZ1lUdOx*&I-OS
zIm!>J`TzjC5SM5P_IQwg1HjEN0_H~8O)z4J5g<27h!eR0#URGU=-h;j(}2gOW5erL
zSe$TisHgCwp~B%pG&&GINWUVJ_&l#SL6aat8HI+|L5xFKUl^kYu#F*tU<`!X#XWl-
z$y7FhBmlw3M!b$BDL6rXR-%tBu at j<ztq69KJoh5`hw$nCwi}pV!<!CdsA2Nlb_ft;
znuI#T*?A_9g)eMYb_0Dtz}m9#Nuqo0_iG=vse_M(<^2>m+BfzkDP;1^<Us)LHjYB2
zcxUd}#uPYim^lCAx(>D_5DD at aM(MuXpS8r=&TQI(ao9n2gF6J+;HUt<Qh;})IQ4G;
z82L?ro1>qb*Ufv}j at uFJjoa*#{USn9c*+hWT109Hp!oO++3wS_Aw12(@w{>6^?*L(
z7>)(-9B_X4q!l`Q at jyJeU;r^3Xkb0d?@?6T9R1u&==Tq7Yud4&cQ&wa(E}KUz(p57
zqwpziX7Q68CH`IL;-i4##s$#$=1K>#CZG`k#oqz-nU5XVuhqbCjQbHU25SHe7$Tl4
zru$m^@9Q8!Nl-t*xKFJE%|JU6=Y?FxWsA+yEfV60OJcIcqH_hYv=7@{SY)weoEIY$
zDfut)x55cfEP<uysfM;Sy4MW=fSdEZ!S7A~|896qJI?k4#-0n)9?e#^pMWiG+wsIm
z*nQ!`*3JE1AmZn)m!Xx#4;M*G9kA&opiXfU?>LEg2=4E>OwFZYm;6mE_lBKsppB*t
z4G_q49*`P~esqnoMi#7@*3Z;a^xBZtmhL7fPSIo4AED8S2aVEmgM9im>X%;Z0_9tp
z+;7$3ohH}dcixYjTzMIgubrQloH5psPqjZEYpguMUTRP56B}TUGfj<#vS1riOC8aC
zVAOeBWBMTdV7rs2Vm(?H>m#QP+tr?;7B2f>2P2*cmMyTQ_fMXj`(?PhJt&I3%;q?9
zg8;v%nfAP3ZCx7U(pB^x{$`ESvFhs?M)PbCAA)Pms0Ay25@)q%#hEbcOyV!$re$ci
z;o1f*Kf$Q4E at 0G5yf*w^dw-rY^F`=|H3QU|ZrVHG4}62a at E`t!Pw)utzymmuv6At@
z`)~mcz)}2-pJ~eO`+hy~*S)we>zFyN@><Jh&SPCKoxAcMo1IN~*WNXMU4yR_F8$t7
z*B;HkF!lX>cx!DR1KZjgO~3m)`z3ppe4ypV7Jf&aBim7XU`O|G*p?W>A803WO-x69
zE59(L!ynP;7Z~t)c!ypQw`dc-!nbbpsipBd{^#DTfwe>|2}@6*buaxyaqaK`v2nKd
z1RV>ng{24Pnq at 1n=e~u*!X*y#4{qMVcx;- at V>A=lBFFC#`7<W6j6-ura>Nl_7$Gv5
z5fB!E6Kw=9oZw`0 at fDV>Xp0G#emd!2hyJw at V;HRhzZ)owQ-tcqp%_?(12PW8ilnbS
zMgvueguN%Zm>@NBiAW>@l41-91l~(x(Y*e4Bt18;*qma5M!AbWYj{UB0{4k%*wup-
zV;>FxH}Vr*yf?J-TpWSr8v#`$0oK8K00n-KsEQ=k{yuD_eXyTyuMvz2tZuI_%Qgff
zHUdtd4nh*=9)xhM2O(=3LCE^U20aK{0;*tf at WBy8XXlTfAf53I(Yh)2a}W0c6$7lp
zyxloV^K(y3veS<%XVV|y3)u!AVE+_C6*(lP5<%O1#B?PnxXSyTr<?;%v41aGM!_OK
z#~=%TluvpixHNzr@>disKx>EBhIwYNzuOftXMn#Q=Jmru#mElFPC&;wo&xgK0qwKb
ze>XKK(O=JNMp4$*;XQe;VWYBF+A(eG1ZlXjd6#^IpFqSeknaZU&*oQrJpA0=??~UL
zZsj*_n*Ui#`MdkJ`^@{ZP2qXOaKv$c+P at 6~9MeY2FNPDTarS39J+^N$D2Re9imfcT
z{HFn at h1OS$ZBPJcq6;+CXU%uVS=0W9gzs}*qd%JbzQ@{o6o4QKz)Q{j)W?y(<(FOi
z(CsJyg*{&bbKcE6+zVb8XCog;tK6)ki9LtA3C~7wHr8&g$yGV<OkH%|>L6zY$X^BL
zGeCa(s`NFmy-$5GKD&UM9 at 7!^hcq4>-t+5vKh{@ZU9pG0FCq3?HZXGdn}dh28Mcez
zL^k(s at T2*aeX;Z2<l~FTE0J5~&=h|~j)^>z-#EgTeQ-K7Y11L2AJf74{o5DjM)D(v
z<dY-4k;sP?OEV!`VaFw(mW}z0V>lK&VIS9i*n!~&dv-ph{(Fzsg&sS1W`nV6Bn|nj
zZDxZpG;nBMHdL21E_H4;V|$FAA->jK=)*g|o|wbEi{P79x at LdRx_YJ=w?pn@>h_{B
z%?4R(O|9vAbFp!f#yFqiAN+*R;0rv#r*MO~!0*&lIULI0dEfOE!zg^tw;<qYfAXLH
zRo+v+Tl`u%Z1>}(92L0<$c~Yl>Su4#t=Bh2KR2(L4ZfRvqp!o<I`sv9(7uNK1@>(F
zQwLDzQ2&L-m%d|vVi@~l$9SL^F)Ga|A2>GGIyYkz&9kNv%Wn3G^Nh)i$LKSvp5fm3
zh_ysL+3FMW)9R~4_7+>M!T!q*#`I&p?!WKvgMRL~ZeZhe*|hVT96IbOUFn?uxb}Su
z0j6odm`su}6iEZ)k!Ua)f)9}qNyL-JkEF|m2o#7+A#CG>VFVTx1_|V%ZGhbLBuppK
zouZS@##@Y~`?HR00*}ETM$-CSWV0tXz6f&^7$lJ at E|~sj!l01IA|jex*@|Qe;W`Oz
zM~Ldg5J^Gj?@57sL{fl^5{o3`EUa<h+agKy!g_+{y~E9d8wSohYZ$V*uO^|ADSjqt
zF2$7A%f3IU^+y0|FOejxXkwor3JKZ5fyZarWU9ee;9)=SnR~gpC-CtBjXi?gITgbs
zfn*n)YJ5uHAGs02SjlFYls0i&gs&I3@%p^z1^pUE7Q%V2k>reRZNS_;a<={+s<_HP
zpbMpWN+C at 1l_DvBm7hpb2%HC2_yB=)aR?`S!GizrBSoAGmOiiwUzNZ1!4+5=!O1J*
z?E;)j?wX68ySXPLL{}UDqd^2A!pRGUdTtVXVPp{JA<&>i8oY8~HjAlIaH=qVZ$7yr
zv~$tEKwgvk1?v9c=RmI2`eei~2;ZwnVBgpQy>hW)E&%IRVh#Z8r;P2?7!UAb;3>a`
zZ}}<z at +UoseE$+gp)R}^)U|^fjURw at 44zcHcbFpq?FF6Mx$+jH_C2+3zPIY#iraDR
zIEYBw_irOO=`Y;D&lST{kJcwPAd05ag%?VP0!=>_4H`g$S`)sZH|p2n?A)nu{k1UG
zG_`Cm(w%dMZi(Yr;MG^|Wvj at sZTQ}Etn*I{GR2S3FL7$*n#!?z!;Ve?bj{8BS)<-D
z^3fT#&(KBCfA61Pdha59|H6ZM?`(}7?1y~;>ax#=KBq<-*rGSw*6nP#v$nv7)^Pv3
zIlbAA_^o(dVm4y+HiO*;eA$sPocVmlo_rs%H)9n(ELso5ldkt;xPL=%{6t=d>v7$<
zPu&}^Cf3F}&Bsym$qv}WHIVB*?2D~O-6#LxR|YD52;=<PYah<TH_oZppZjE;*Xn7l
zmAw!@)*SR^ucP;x$Mp^|yXr~Bcg1~ZLL2shK6EtB28P$+>>8lo2b^ls(4d0XA37wI
zUPfJ2d+mD%uBR4V3T?`K8+o?0DQYU&I5-10iWB%C>MHq!IB at fizrz32Rf;)$if at T=
z_e_A-yazAr_t|Xv;otf#>h62T!{EKvX&zjge?aXUZuC4f?Xud)pRKm*=+~InU2I$S
zb!{{18SFf4J^wL3_QlYHJw^-)eW*M7t+M-ku&B7h_K^c-zd<eQ#-DF2eIxMu+4$=?
zG!)H5EAa*Ou^(>P7w&1%0sA8SP_el5A=GM%53oVnf(O|z1!c2|wCT>->#+ObX#ev6
zu=}hZGxw$j+Sb8s?U6c+e=PG>pP(50&ifGEPy7)=ixfo^!4igv$<>de;ZK1QFhVWV
z3*R at kHfAn_QnVcC{z^+n`~wvwa6aD+)_xBgE({jNN(_<?a`Ln_gN;Pdg}?=Mh(RQT
zBqc$NZK6P-IN3<~wIJjq<5xsR5<f$N6a|I=*$i_H8tdL at QHWDeb3Z3#2$}_SO^l6b
zx*F<zj&TFvgvPac@$bEGU-olo at Wq2Hv~phv8++;CJ at bY_CHGc|uK2_KxIgQouphxC
zayqc^2h%L`XXg%_iNq!z?1`->G$)-sIX&yk- at AI&gA>pE1E60IJUei__aPCo-aYZP
zWEZ at yeNR459>Zbt7huC4=)|bGi~osVgf4hXAtOJ#km1`s_!(XTd<gI-U^oC~5ju-e
z&I9nD>tr#yBl#4?X#@O7<a(k|6_!F(c)uFa9tZ3v_^-XON8*(I2B!pyNQ*Yj$4H*C
z*LBI$-$1g+ntz>x{~kCK`8B~hvF6$>@Gf8?p`u&bcW<y5w$M~#C*tn at rUTd$ECYbD
zxAlO;i$8XRuL=}3#`NboZg<?-wW67UD;swJyy`srwD<=P(I4}&^YydK>v>Ed&g1-f
zJ#&_IuvhkOZep)|f;TytT0Dnb_`$_oG&GHm;|YR598)mG)4M7nf{(?6m5a%hGalV3
zI`7Q+`E<Spkizm*q4-9F5?oUQ<)<}!j*Ofld*M%O4L-7e at B^AM^`$quo1YH)l7j(r
z!F)M@&k8>Flj9l*uDS9ixpIbF7dbrhc&_mbzE&aDPXU^F-+TB(;}{5@$!2HGI<eZD
z^v=0e3sVCY?hQSh4MiVn1sCCA)5mzCHFPpL(fN4_^QT^$!yV?@%Il8K&BPghjpOn2
zTK!(!ds(aYGHSu5tCQ>P30mb<?7MQ^e{PpN&!PK#AVghsRwt1=@jvI_XMD@`xVE)p
zsg1Ng=PKLH`_H;4>*G-uReeF7aj1u=PXyO2XLZdV0;hFRtBv-WXc-E)CaPhi>!RoZ
zgiH02eLj2*hlTFn at NG1r85^#ds7o_nQa8^$*|m)LBu??2Ykrzb{Ayok?Oy|d-{wGo
zCbj!N8`9K?{w<NHg${Wp>vhL{_F<K4YDmud0re02aSfC?XU08z0 at z?`fOTNigWG{~
zxrVP952*Z*qJVwlVTIP^+61s>;2IUMFE{_LO%~hBF4!JBp`XN=?T<~dEjGs1_#g&x
zo9&57at(Gz_qi56wXNN!xYtchE!$#Kafbb|-=UvFH&aU%y)3P{z4j%4`{%&tjsCT+
zYff|Dr5-H%V{_Kr`v7bk-=x5vvgPN+xm)kiFCUU|**u0v*a(8r<g?-0C^uq*-jEk=
z5t?5?Y12m#f>fx$cCcHd+!VPn8i- at _zbTr+P}ePlF!U!CwWeJd(ug>x3j*X#qrE{!
zgQV=8A`YWrj|WN!Xv(93Dk4%yd`3k2oCx(r5sL=@s{}k#K;f$*AH;)n6gLzGhz3cY
zg2Y8-kWV-?{Q~zU(IZIU9Xmn at 1PB|zhj}dLLFPT6W|8kAKG(y3KCSh!PSzU<EcR4l
z_Pc+JeSJm0^FDk2T<wd1^q$No?#cSGBi}rLkk}YoV|U0K!6LsnAndc?QS&iAH&=Qx
zdzKQ)GXvjS at ***@PUfq$%@6My$5 at Q(veYd;r!@dWi*KfmMY#&%DGbs77bK_ttzKPSlG
z|DF&d8LoV{h%AGGmi$5_RM><_SMtk3J_XslH}~NXJ~W5mXZ#xv#Updcd;%md1RHLD
z1dbPyYg+>-&LG0X1Pzyq<7gBpoC8&ON0R`mQ3xSVG3T6J%-^H6!hiPBIf$;2m at MQ@
zeDE>!tvHDd&CAZs9bNlU|FTF~Ab-t&VK=qPdNokj+V$(Mwub53V_~!V)`{1Nfc at uF
zt{es&^ubU3n?LQtt`pdK^;I at E>5D}AD|HXVFiCm=To?zWBWUE8m82=2&>HZy(oo}T
z($z at ***@6&h=o`g_X57l6*DvXj?Q}9mP9i>`CY3epc?e&^YX&fzNtzm-kMtW5cfZ
z+0dod;|uc?WZ_Z8oeK~{e#N(N*ob0pL;pOuP<)t$SPss(&nUzy=FJJ`JYsq+z^a)K
z8=b?$6z`wd4=uPZ=ZTMf&`lv0cG<vt2FEx*hE^4)->qwM-Q;#^Lh?HI!#ePZ_msTO
zH3N8UZj<MM`TZGCpZOSm`dqHVzRfe at hWPoYfDJxeHefwzhiL=$Kla?X;BUF$$MAU-
zqZHv?!*(58>ou_Ii!}%RNnLVH)$%VO_uLjOPmSO8^DFH$*K)$B^R9s#MAwJ=@B8ud
z`h5*RuiJjyOkS=Vw{PZ!-tOOSnZvMIY_~yJaSe{a2Y7-u3_a9OavAYLOnD$cOb`S3
zpZF(!xfdGG{a^8|AH|w_-DDrWKzmtyR(8Q=Zn}Go0eZ6z&T5l0tmpBN<#=u1(|%ig
zbmkWjJe)ak^-Ifzf@}IcAA)F1$%k(COZ!~oyW#J-FlwA74`$8ZwZb}qKdlMQclh*>
z<F@=pQyQq>o!h_|76F~_+{U$?SE6|>UETAFHFfBzkiA3d31HtIRAY<&%{sUYM!pf?
zU*w$99^)+UU~7K*7~&(Kb9)Y&d1(5?g8|kyauO(=$4~tshQBp7wSCid*$6**xZCqM
zb~X4t@^-~y=B~1 at ***@G+cAU<o2EUxEuE{we%P#RFzg~O<~LX~o;z}A;^WG8&0f<+
zvQ62AJdw7T-%!T}`~KO_9B}9U9 at NiUFHitIUqSU86{Tx4mccd?LrVxvR4ux0%nkw*
zQ@@-59>n4V`;@R_h)CUY2#D7e!f`I>2*x7hAree+%J?!ihK@!kh*wj<5(Jz-3 at ZWn
zR0Tdk34sW3idLFretubjOz at gi6c32T$K?<g0Ur{vTmVp at M8i@=KokOUEQF_6ci}Ue
zfB&AvybGXr=^Qs~E`Z*vhVA`zAMQu-!5TiMeT)Fn`dBAPiFJoyg&@@+L%$!Ievydt
zDQpP3*bDp6Ju`XzJObm8z$DB(&BPBqfdTxsOtOn(PG0Z;{`4f|hI(nX-Q<7qyR&iE
z&!-N2_cr*4?e!V@@n=}?_q4!VOAZabTLS}w_5b6AAwk7R*`de8jE5Er!sX(oB~fCc
z;v&D6zD^bae#>dE1*=3&ASqlF_Yg%l8W~$~0%Y>dSTnar5ikD2qxUgv5U(N$SL_i-
z```_(5_cX>WfPdgHuz})=bBu9ax({=9!zC1?IOCKx(L?|1F&uAWZ4>IAziwOCY3)f
zf#ZPx#x8s&^!s=az}L$>1Ym9USNaM+O-*wGakDq=zS~<`A^lkkpG>CMJ(_<Z8YS7E
z*#ETb>*6O6T9>x}g8X7Fi9)6 at ***@b*32XRM<IXbIQy4tSdSuk3#qei{8MkyHT)mV
z7eMm_wC_5^UUfWL&H3y%3O;H6Yy#(Axj*YT>@k3T=DNLhA2*7-T7MLH;&c`vMm3fc
zB!z4)Yfbf&H70V+qxrn%_kNxJS?s;+HH*u&z$A{Gqu@})uXqK&Mzbp2k3vX*hs2l*
zq12E&L7r#5ISey&zt9-nKZ~Q88>6@{J=u$Ua-lhn at 8LLmPg_j89&B7T3e<VYpS%{=
z%qD;4ctD=d;(XfA`Q3#i`(Qs|JM7kMMr^MGOApbn*C?<w_=5Aqz)4N#rfsR|&Tye-
zb3Hd|JiW)yHLv}zhS$Qd{Wx%soLV+m8&yGe8V{SAZ9|s@=h669L1}UhX0y1*pYSzn
zOn*CX4hmdf!ZBi-CM06AxCNg^ja7Lp;;pzsoH&P(zxyC))>@Mr&RhBI+ZrC6apMxU
z<{e~CGuP5i&XK;a;U}NAA2oWfM*#e`JzvGXBF{P3rEP~sw4B$q!L<k4F!SHkhsc4E
z2Uo42sUl{r83r+(ur{v1m%y(>V}{Ng;rwdfqc`~9!^Lde=8(ZnEV*N#K8qZpW3$oA
z+z}kowYd*#U`^Jg=slVqjh+J=$yV4bb-fJ>%D&hc-dW#!vztw>(Y3rFEt~b^CCqDB
z|04(3&%*FCs5N?sFltQsI`V+_$6nnmI|tYY5qGlJuy@$}w_#V?-925}IPDy^7S;z2
zl`8;#C0Bs*HTUa&H?qdc9Gw~<)OERjhd+<}uJgDadx2}=-|{Vfb&kP4`0W9`zV&1^
zA5T;h@<cT!Pbe&nSHZ&A#nP~-C%$(gxHp5(znDw}i}MiZ66IBZR^i#jW{UJ|ax5fK
zTojQYkPBrDh#?UIg4zW`5+=z4G2A>e00^`~m7>^1Y80q)AS8*QfSkwmA~*$x1KbCJ
zaiCrTpNH`1oI^nqWJ*HjI)x}QQ#3~5%9;zjj^RbDw+%09jogEEMIji)Ob#AQu#u1i
zf)%?W)|rs9sqzyEC!>*wdh)5HYyO!7XB;~W00Q|m-cRSF`3__=er(u{y}7?>!+$+|
zPv1YF*kcIbH6DiniSvO##Z0qJ#K;~WJxN#bhn=HYE!$^|%;GT;vf?C?u at i9(2j*ZP
zzXsKlumyTa!c0X&n8gjn)Z3d^8KeLJ|MW>jK~%(%o`ju<BMB?Uh_m-Fv=YDIx8uzM
z9gU}W2|q`}RShLE_a(iDSQBUPmgbN1xfa7P?h#Fk?oW)fHrC0S`A7QL2m4}=6dbSA
zeqT|%MLYIF8(3rhP#8Waq#x23>r;*&*Pky<yQj^M&Col;zGY+CA)bnseM2`E&8Q-T
z0z`JqL?@JXd|tM9;nADlT}$xCS7?A~-pfbX_|w$$jiSWb^zZQJ6P&~Oz8=^9vhK6!
zF3@^dpD~K126*Iw#U=RsWuW1E6vm!+cuj at nyjq{{;~e2U0pL4+Akjy at 7`Y+`ug(?t
zl9-`zbwP(NyTNoZ2QT0UL!l_(gx3f6XQ4(+I|k;TDOAJhregn^V~dR&qn(#|+0gZM
zAL5Sq<NkZ$??2lM-q${6!QZ)`Hb{MG#eMM~^c*_C?*;Omk7bz7xgc!a><yxbUhF<?
zAB8lyG$cVkqu^C>ETj)sKg_S?rylKpZ at M>lGq>h&{k-`HnJ;cy_bnLp-+6xC;e58{
z?UwtT3k%MVD>8p(E}eOO!Ey|*&#uEgbpL=}pXA=NJ%FfJ+Ylk at Q(+7bmi(Jdb_{pR
zKi2x>{u~;_lWXOo;Iw$+Zx-}A)XhukcIHQP!QlPmZt}J_ddbh^rZpj(yAwW!E=+CU
zA15aMQX?2}<dEYGah#5a%Z9I$FyHeh_X5#OHn^S$^w&b<yHljbW&P2>XUltaoZr_^
zuG!J=7hnywu8y(h+JpBKd-6}-ug`pZ-(T)0*K}<&TUyrhc(0S($VRhT^}chNhtI${
zhg{=f0oO2pta-iG?*jsB8g{g;&|~kv`<sTJAtv0gu62aQfztfzKn*l=f|1vq{98F^
zj at jO6>*PS%I`=bd9r+_420MQknMX1QI3Ey~e%N}3_`LAmpXhwP`89ILy!Ol?d4JZz
zn!?svCp;atZg$?k(MrzFT#-4p=ZM$qm|K7IxqrBN><PNKuMPf0e)akicCp;w%j0}4
zPm23}4JRQtHqqRWs4T9%!6}Td5EZ)M_C|-~iSS~iAXSklzZo!t6hlK2i2n8<MLNjE
zG)|{Thybjndlb)A(7DK at LFok~zdJYq$5CL%)Tw^DD7+n9m~+jzj|)u-&mDUIi#nzY
z0L5lB`wS%{0wkCZXkQ@!A}#x6-|U~@c&kWBV~1_95w?0=kr5kW%V?rR#9pwNgkTgY
zf{T>!qkSvvMM>w!<YMR7L at zehf&)~-k0QXyf8wlI7~m=Xc#?m6?1jv7zw!HA+rI9z
zy*Y;V*l{5evGSE>OUFnQf-^?W;)9|x3UlJ4ntx&haY0;DSf`+dn3j-6 at g3szFVT2D
z5W+TN1u=~2xeFM at jGwqJjc4&XI4v9+uZkUb&#|2INu6u{a((#A{hYv9kNMjhA`9xC
zxb6-vUr1JnYytbM$R`)C{0>-;1;^xNyVgKOYv{=;6IHI)_9YPy9je5_UWZ*}0}laX
zip=n&>^h#<%XVl$hqdTB?B{^ctL;6ooQuy2i$)3AFlRHL0|T1;Z1yj~$9yF)hYepI
zLxDuU&p at qV*WeDX|KffMLvum9M_<Ff7LMn7p}#8BLVs&8?7>xXSOvy`!^PiCf6d+G
zY<}YkzKzBm4XzkBX6z at rCI?C@?gY-gzJ{;4-YauJUrW~=YY&ACd&oFh3%eyos-X9<
zG2*21wPOWXj{+{hux;2kZOkzoI~sX`+|K}$YXj##igoJ;U_JIl_#=FhesLp|g>Wy1
zSAPXcOU3{){AZ+{_5lE}UAwJq|KZo>D{{f<U;xx$fQFVl>|9Jew&&sj<)%x60Ozxw
z>zo54H&))IslWL*_HK`-Y&bjSrpUp9*61}0bBHkabzSa`+PB%vIXj03*gfr!Z)T28
z|Hijj#Rc+94udlvI~K?lGz!iWnIqJ+h~FbeC@=QGFM89z^>hgwLr#frRTVfNaIKCQ
zqzQe12B-mm8>iH at 8G8|bS~EJ=<Ig!eVzA;c2Ny=gpRmNAY~$E--1V44S9;@_F_#0#
zm-FWqj=dOoX8aL*9mL?B!ryoRaouqrq3*wHpMBl6&$So!h~`x`^RUPR0{nrm at F5TN
zTvtVoa?Vs=K%Es2Pz34)j;B6bdV%tjzx~BMxp!(|`ruGUZT22Ir~Mr?4qUMFbx2K|
z=g#X9FBvln!p3RmS+^x at _nTtWdpeKn<#o6F4dhy_;Rc*I>iE>~uH(+DQ^TbdyLKB<
z|Cf#n^v<u*8g4!2vwwee9gf1~W@|R at 2Q*Q;glOoEN+^btOrRD!7hju+jp_G&qXU`L
zY#ea85J^MZ=s~1%R0N=$o5ecQ%ocb>bO#=yltPulg_uQAu7DwM5JH~rM^RoPOMto2
z*$eWeNZyLd1<}x}sBDEL_>vIUsOxdvEHu?9MX~8-NyR2Xu62D_$b$1%S#WCo6h#z6
z_iIn=jUwo*@prKIK*w%0KQEUZ!=@F`o#<zU%1-VVR>S&yaOQ9GVxYLwxYRjjL=giv
zPM&f0CWv8~G2%gSQ~v<rb at 7xqdq2<hb at zLE&2IRC_Z%^^*(#p`&6wC at 0iVQRtOPU!
z&ioff(_h?&2csbsN8kzx9sZd2Jgw}Ur`dsraMDQ#9xqLj2UR4c;&L=ggU6G at pZJ%_
zW9~JJj!amc%fw|A_l?tuEbvKYOOXK--!}p0fZ2F-<o%Wg<j1)#)@Pmgpw|AOD4?>a
z%EGJ)FzprlvG3H4sU0iovpSA*+*nfJ#ehWDji<;IYM|`pB8|e~y#niFaKl<>gLDIM
ztPssrU5kAtFKVxXb<z8s!=M}looS@?anZ%bogMMHj&-9SS}537X`{3gHs;>g+?<Lc
z*9e<U#F{~Up8lG9!0z^${l&e#2M-PmuaDzcmj_zh3wuQYCY!>c)Z^rywV0<%#3;FH
z(cseGOWNzaX#Jhqd&Hhw2kKnw%C0Sj at 6TGmo^xYh7Mhc~(+7?*7}Flz^v}U##bL!?
z4(c=R1{8b5puz8faZC+WnoW;`!OU~fOq7icY#oIy&>q;wf>9jq(BAbkn~em2=gnul
ze>{H0xUTN8e`dt>U6AgDY31cW`DEqD%9G#+kk1b}x$<u0*UC-KRphTV&z%nhVgOLM
z*%06#)YM<V7u4_v`uhw4`tKccNYLM#-vqqbHv;2Z32h%aD9F8C8uoX)Ossi-<ollE
zM@^iux##tWwTQ8dGx!ES9be<W9NuDTJPlP`(1>Sq&XY^$D-WAf13he>n&*LY>7IbL
zb?{!#=b^#623pE>U5}>jZ4aTeuE^6ZR;f!u16_}5Z;nsLWyFIU`;(e<<$cGrsrBuq
z=;uz%YxjHOtI))%!B}r-qHyR%(8A4U)E?*?wj%f1PuLXOVrOhV1^`ui at tVAp-v-zp
zq+~4+jepobwKDnu-FxJovim-OMx%Nka6X9cII~yc%)ZybImvO+e?R0fffx!Xo)&HE
zaLiTD;a=6Xchus<De<b;j at zz>XK<Y#Q2ZO`+VD{EPgk#$jc@(cr at wRcSD*g-t4D&*
zG^qK1lzu)+KOcQM2oPv$YSBBoNEtTF@;6l$uOVO!Or$&X-uS!OXkzkjoChvAvpXB?
z<XFkI24Rr30<Z_)C`hUp3DH#W#S=OOMKl0ae7sWu69vDDHiR>a>@2!zxIaSCsGy7@
zzY1Q8(NC9Xx?ltr%`Z?W-T)!6h0lVz9 at pj`pG0gU&?UGfx_t<M=)PBA?GH#yqG-~d
z{3PVw5Z<4~-j^b2i0}G at qZdaZ3PLYh4u#1jjDlsG5Guh1^g5o50DM{gJi|*s^ZOZY
zCrk%X5r&8eQ6v?I7nu8jJtj&}HXP%pVGPCmx_+;9^qAQB at 4dzZRW`;i;VW}~D-xpU
zmjB^F6bRx590{I_GtuBxaquykAr%GiEgPZaBpju=_W+AY^c-gWK0b5v55^#?&^i5?
z;<by2$!()Ib-5-tZ8wF_8`q+#4$xpbc5{z_299;P0J;twn`>X!Pr~+^Sp)X$F&fP}
z$+;SIv}SzEL4JAr4{DepUwLTfcy+NfV>aV9o165xWA_LbkR4~o<#o`4rHKQ&H=5Ch
zsptv3LPvWO$DRhiMgi&pLfXZ?34fFyY~RpL!Cd;{#;f2Hekg6U?PEB4YWJy;*dNZb
zuH|Qa=3<%S4?_=K+iS+}+ at E#0SUy{06lgk@^T;1wlMA%e=^WHzPir%F#|Np&Q;T_W
zan#n*NOa*EjqKXWIq_t}*W$WDFJMzoCRZ3LF1&yf#m&iy)Ef5V0o&Vy7p=k9p5X}j
zmf;>;IRl?@+!z4(d|m54 at y#~lp4^}HI5yUXe}2QQ=d;UAetllBEy#&Rw+l}x_n5JL
zb{m1LKgw2)A*1YO+a<Dq2mTCjY-okx>y7*_*d9BN*dIQJ1MtGRGV&q$&&9NIn+xP#
z49B3n)t7FH$8caY(Qc~MXzS-$^Sw6d{pWR!`|UnILk=f;qtCj$&e80H__iPWD0p8&
z-z(^LID*Dt;<~y!YVM^zpf;c$a7|Eu4k#b3wQ$9 at W4dA)Zo}K;Y5VsL#D^ZQ at CPnA
zK8ZOG4*Jjly+-$})94#IXP|$f$@<)Shh9=Uqjy}-Igk6G3EZ1CuomYx;s?HFY-OxD
zUVF`H&FlI$xxAy>D{Xd$ejRHi_i>#CtPR$KjQ{mXKl`wKXP=Q8h at MURW`1#AiJa2x
zi%p#iGoRSDnd8V$<Sgup-@>k?3ASsu>Cgb|SsGwl9_=^l&QU7|50i^vt&>{~Yh0|E
zjr?q>n_E0MHXJKmgE}(4GTzSPaK>wo<wVAO*8#BT#HpU#Df)oaXrIS at CgxhcclC1F
z{?=c7>f2YwBLd&Kdc>!{bM==o7)bQNz_~cdP|a{*R2#e;Fr2eHGn`(HNfE*X*#+q=
zpn!`HBZ4a?oyS7N#R$z!Bw~nLaNs%kJYkEZTVnF2_=;f$Ll?MNoT?BX1z$G#6lfn+
za7B|Jg=rR;pGMdy=8Ou+hl*&18qSWn4sl+siM8c`APZp{9rnOp)&YS;IK<+Yv44uM
zUQ{7aqo@$x5+Y*Ef`tOZKwu{J-xF_c at B0Z2z5#CresAFXIvx0z0>{AT2%X^qEQ&Gl
z0`ZFh$I>KaVvGbMxY&#0s1nV~N*v*;Iot)ZqYLE_Oryokb?E0_7h64^Msgxvw0_4(
z?$5CyJCtoQHmdlPk7sg99#Cw%2=G(ywK<v%RY3gmlkf==fAY at _AAF4X>JU#IZw85Q
zKwQqoJ$da0{zg!u4Ak$wmaiSnV%?v$^mqa6$$KPrqH&KR#)VAAkOysmqJ|>fF_eY*
z9J+yCn46panq%kUn84qFgPki2 at 6KQ@?$BqQf9BxMz1#9nNPXV;SA|h8K3yE4JJ}>=
zQ|PB5*c|&?oADbyMenS|)<g=WT_0mOK*1!xFPf<9!Q1XzI8Hv`z5)MUpE(B13C`y_
z!SCYozCN#up+F4BgwN}BtkLUZZM810NsMuS3S|!m;FOy at G&A(C;(2Oaa>>B%XXwY+
zFM+yVAM#`lO+S$j$fc<lTT`!f-mmp~cn)mGZo7kiRGjSy-+*@P;wN3V$6)5M8GAkM
z_B_Sjc8t#>Cpp*UHLQ`7qq*nQN$oXsa^<TLT4Ig}tL~lX-EDBDllgmckJr1Vao at rD
zuw&XV>wsxH_Q<}mL-0!6$b6Za<eW&%TYIcEqY<b=|2Q<rzrXi??|ZCE&*7r|63))K
z3Fec#T2sL5%r#$nVD at m)n;F;NuE9Gz5IEH3fwFb4&!a}q2N<r?_dn}7)9<0($~RNH
zbExHpmYfw&trZKdrQv_ at zBmuR;2b>M2fD!DWKGSZiOqp%=$_6eb|S7F)0IzWJkMBO
za%gB at Hn?{OXEUE>v%4erHjy<U19WR+^btVU<sPG-5K<db2eE^jdSZw*TmOi!rLWK)
zbAaM+RnFYN147{Zb<7JHw-K|ljdQ{wUbSA<&%W?s)(|shXWh{1gyPDfkuRPF_Zla6
z?w;{G<J|EjM9-<X0}+32(l0mb#vboW<6gtL(XgwDjzME at su$$YFuq;nZyEJ(8u|Ca
zlfmcpTHt5LlP<jXB%KrR at AcU!>K^-jJDv)(wwK5+xBmQ-YW~3(00=bz7()OL0QgqG
z;Tr)*QR~hB5SAt;Lr8{zq=;BRC`>~@LPU~udjs+sk&>WX3JwBm3$8!~c_d&3*}Wn;
zL<a<$i^M261V24knt6%{CtU>{NiiFO6rWEiz-XF7m<YHHy{XRP at i&!Nr(n_Ca1R1A
z#p_pDEFxf0oH)TUnM2TwER?`I+UpLE;hfkPsB3Xu7o*&dg2;Py!xahN1%TEYMM5<|
zX at d^-*D*iioCC(w*+do|N5r=iu7%gvk?*^Zj(wD^ZSM)~8&rWfnloegz_w3YXQAUJ
ztr80&8p)-av=US}8KPRk>I4Iiojh(gIC$x|6e9 at ***@IjhNwh4Aebe
z8czo+HX}YWMm<n-oW8pDGr%5euV6M0JXOmlYrvleB9X3`=S>U^unzdAQ8u?Wc);UA
zeP~7b3ZEHSv>WNu3BR`=H_`oXa6hlXL#Dpod$fM`#NOC**skn|U2S8Am)PB3?G1jM
za$^>36xNxX_XI7t(B2cYfwmXA-ai!hI?JD})V&Wm161C4LG9tR_|(4723N_&v?tua
z-uM9jPz1iM236?fUVNe#=nwi8`YtVxBC86lD6)hovV=Z3Mc-1prtY9MXzS9DmgWTX
zIvUnpe+Bd`)}rgOo=>UxjR7)i(i-9$4Zr>U)t3Z*dNAPp<06@&k?V!#>0W5vY=8yn
zn>8*9!_v4!6{n|Y$JKe9f5<<wae&-Y$o#W5x~z>gE;cAT*cO?KrcL&ogdbvvUBB-+
ziDNSt&Bk}+3f(t-*8J7iS8FuvGtNnWO`k0}^Kk#3<MLdt(eLS8<ou6K(=W#Xh4tpp
z(1f;3T^Uep#J3sry2E<A)L4S!hkJz1>Au|Gb<|Qrm2cr#)E3=t^&a)rXw+(dkzdFD
zsxi at h*c<ouzA}GW8)xqH-`?^d=#nNHZd@)Q2ApS*9xc#&=+gjtwZYBwqHQ}$hldsm
z&jqEELytkz(ledySQ at ***@fU|3Mcum&wq2o=<Z3pbS*Z!&7@}c~PKjB~S4X!aX46SBR
zko<yMp&8;*Hp8g{=-ha)R=OO}?@J9{@fNX$78W0;7Pf)>;G>b67j>T at p1PmNSlD!N
z(L(naIplMUI5t?%)REFSt$FMX%@@#k^!`D<IVp6_=i88+gI%}|*W at 0tH#DU7^H#0d
zv4yR%IdSiLgLuL(exmOfa@@fE;P(D?dAM7A=zQ&*8T_J;jON|=-YNFx{m{VQ2J!EU
z7&Q0>PtNu8^eK8n{8`Y}P<OZiU!cakH}4%!e26%^R!6`8**Y0c!~o#0KEo6Kf*SkY
z<b(0=0etQsuKs%ahXNm~8{t%(9Kqh54=Er=kz^^>DAWk{3iw&5t${zD9)ti?K`x at Y
zfhXvCU{PT7rnWb<OEIN at h@?D{aTW<Q at owY+f%cga4}J#fvp81gaIOnIn&c1b`n|An
z;_gYCbt7a>YCUPYIp~SoNjn<>V<tU<)XDEA$aD6oCD at XF-JiA0p~}`6Y5nYjBH9H&
z2;~sFEG8d_qAz_jP_{7;L1TX(JK|4ch$WzyFl74=hM=dv5m9`S0}K~g)Bi^f9C={)
zeUL?EC6e+#*M(o^S_~9wz1|D^&ZP2-Wq<%Duw#G9gsn%hQ+&vR2QJwE^^YtHvl(2Q
z!fXtGsJH_u;yWCh9sT{~co$R!3alNzFAdpv-SAT2HPv<dy*tp3+ZAco!RLGUF^j+R
z`x(ogH?YU?+F<Y7>%~_5zTxb?V6J)Hi;GXRbu{sZM!pJ1>GCKVThd(;ukcK8A?cna
zTyU0Lufu-+*}W3EroL8iC at v4*B+DWM+t_ZlWpGq{i(%EsH5or>U1%KI7MkW}CS#L0
z?Lz?<W)zOZJvx9kxFCzcfQm5i`6|X}&Z7V=EIFhw^<)L_cldbDcOhtSAKyO)0Z|nG
zn_dgQ`F*U%Yay4#wRBDH^YKl`Ld)EY8l`JS*V!|S^9qrB!HE_pD9UpkhP8RO3G42*
z*b%w=1m3&z`u=;ouH&u)zBb1DI*)skL&Byi+Sx0%AUBc2(0_`5G at lxP{E60+^WmWj
zZ#Wtn9y&R-A~c{E+iI?&LEK_|#`X73vB%?C%y#&=vupA6-A}m>^`NwgnCy*Sd^=OI
zc-rU*b1;|9-l*+lJJ$ofSpqqHnL`-BYd+&x;JPAmuwt6nj+%`8TSJCEypLf+`DV?*
z`9wJDv1{@$xlZ{l@?7oRngp!v*e8bq<<st0`&O`TSO2a)KKEz-`GLRsJDzSDqv;X!
z``Q4_&-z!119dL&HS-B-`*R23lsolA*ZYCH>~r=Jb5L;Ljckm~U87PX!5REV!;MeT
zZ2XP?;Q~5?mJpkcSF|!<ov!zZVKj#0&+0n!3jSq{pWuFm>pk<;SZde7-FfZM$<oJ<
zF_bI~wDz+$uir!8902 at V4gmC;{qQ+DhE8$~uGa at 05eKTrJ!pHI><0JWEZ+A4TkyQN
zoxIN4t#cV3M@<5UgU7|;&g0_nr9l;3hyj3pE<8Db`P8xU{U#7!_0zmv;-R58|7%=4
zJdA%|M9sLL$mj1282ouhem>7l?AJX<#c$ge`;9*Vc${u-JYF|`yiNd5&;iC1Wi0R{
z8SKfzQ-r6=S;o`kG&cei_fcpefFg{)V()?rLfs=`ji+*mzJhmc?rA2InD<Mh-$nCS
z;!glMXb6 at J6cr0CNE|48lJ{qy{N?X5L4yhoh5{dUvIe at x`vo^|G^?372%6cvu}*@g
zCy!{}gwf0knK<0MIjAzQW^heJljP*lng<8nIb8J4;`es&bpv&;xG#PTU#1^fU-~lF
zokIutlt#4n6 at vr*8#Vmf;pBNIz+N3Zfruxg7r=cw+O<5uz!x9}8G~~x?`Xu$J$#Hn
z#_(bkA0^!42wa)Ptdd3WuobGsw=?jWkAu6Mn><Wj!|&jr?nmMX{$1qW&#&Hc;9eCj
z1>4ki^^<q}HaKa7U-?<D2hQHR49C2=0?heQD4F-)`cWp9DwaA&d!f{ytQ?Zf-U#0q
z+jR!ECKI%$8Toq^Eel9`{u?y^%-7EaN`xJ5ZucVZ43Q`s;wx~=SK(G%mmoa_PkgT>
zi2B-_u_clvx%A@#YoY;h{YtoJ>tKCz%~{lXf8Mw4LqWXw04@|a)}}uPP1Y~xq2Q*t
z4flx!w1GGYJ)rO(I-nRU9U$i3)dtJ&QB3wc^dZG-7H-whq619}i1q8V;HHS{D0ex3
z?T9Ac(EV8lO?B#1=D0wumvy`F+`+ym7W3!+{`y{^uE%u^v~1k-0=%|6MeOYaY4?uG
z^YweT7xls?`@pyA1Q*wzQz88YzDc3Nnqdk*`Q1Yl&Y?JGJ=g#~zz+rhf<S%0yzqva
zpf~sAN;nurwDPRAEwoHr4t;1E&|^4bC1Z)0n(@fbEF=w{`t+wk`PAs|ub%L^KRllJ
zIb9p*`s3+Sp|2^wD$82=$MN!C&}T2~X^H<W=Fv^Zd5>}G6zUUlh~t_%fOzf=p>uf*
z5L*7mU$fCVas%+*M{9^f^Ta@(d>lTO9#ETdZE|qr-x?Z(zqJnXtn=Tf at yK&6$GLeL
zxvcU9I`{12Lg;+xqU at uetDdK}1}B0St3F4g(EJd<Kl&LcUv<9R3C48_%YDM<)9)a2
zi+!Ja*!ADKA9 at c5oQF&6%>iNveYgLqKk<JKky6LeaB4WTJ2V@=OPlaJJ|>2VWt!$3
zn*LkF`R9L=agH8%s0Sb53g at ***@9*2L%?JRrD)aonb*=w at i9xp~gdz0Zjr2fY&5
zM`%{TLtlmg<c;7oYuCNFuld|-OCIDAJJgf#+5L-$lRP{mpJv at Q`xEnd)M{|ryfzxY
zp9ADy;Fvd@|L3;?;KuC%mmV(qb at ***@Hdx`$%Lf2up(QScU%f211J6|K;
z-Fm*n==pl_g20ciUI^sa7ZqMC(K7A=a{NmIKVI-MH3lyeK_E;ora&}TA{9azf=mM=
zK)44Kn0^wx7gbRp1o=gL6JBJGDSd(8dEX5c!NPf*9|5WBA^O~dBF at c|pSZel^19#f
zPpx4p5x-klnk4OYHZwoYW`=-3-~oYAI6Uoa;(t at juWH{65s(Ep^P?CBwN58bH}p{)
z)8N%UDUzeHE?c}#c5x%kWISz__8YKGn{5GnV7kaTF;$nH-Jo_`zgG90cHV4k`+~4-
zCDVZvqTAWmpU1Ibr}EKeC+_FQVc1CPf(zX)?16 at xy^(m>_h=%-H8{5qvfv~GCX&Du
ze)GLJU%Yn%Vep=l0Z36#-p3Hj+z-?s3+SHQmj(vJPyuL7#NiI&#dv2uF#+tw*xz$(
zzaw57We0)y$1eNeB4W>c=sXDjSHcOur;orMOT-DuXBigsMAQcaG?8v3BPq>BJ)XK0
zdXfSz%64?29>TxidkcEP0kfbxA}7`LvkE>JeH~E%f>v-{hcQX^)Ok#wUBsPyX4JXI
z>$(WdwZz)Sn%8}K?@pHacYSG3C#u;1d_R2YCqjUDb)32gBsSp>S_PlrRSfzfCVw__
z(1^>~;KO-h!Er&HCNf@#olEdBQA`=Wo<PGu{Lfg)`;XYrntE*TjVj_}<fw|1(9+V;
z4)n)h-;O2gb^pD;XG}fEUU?7TdvgCAlBTu+)=3`q&@}97lzq?8bpxApoe4i&2W;8w
zI?(N2IP)DEXx()IKDAfHc4;p<OKlOu0Gfk(y7oCW2E2#vQb=<?*JW+&8T(*2Y)run
zFX1RUg+9Sy_>A6!o`hax42*b>7 at l#QF*h4E8t&eNKi>H4IUcv+Z~p+;uL;iXJ<!(K
z*Unz{W|F<GjbrKv8q&36=tk2F>}p*<YZl2P<nb5)DtE`QK>WsU at ***@J88yce=68t*y
zD|~SMd8{`x&qnOS196;KAYR4*NcY;m-SHCX7i&Y)f)|yadh_4&$KZz$dfzz`JW1PO
zL)$d?0)jIuZ+3JaU5B%C^V*3V2-W>-JziV)>F}#?^y~bFK;#1QK;;7Rx$^)uK=@TT
zApI)+$FH(``Zb3DXbw8zApkWJ at r!TqC%puXvIl-K1kh_5YvSF0r}m10qWn&+HirS(
za~L128te>i_CX9w#UE=>=n#+=g&yf19srD*a3FbTUb2Td2=G4UK!bh69$0_WjJam)
zfn9>XvJtf&93~gtEBj$b@&cMRc>E7p54$d-7RMLP&1l^i0>lHB)IA=m>~+?ttBUi$
zwUjZx8L-C0M1Oz(><oF_ejndIp!KjeYCx}f)Qq6&N at AD2!pXf?dx`t7s#*KP at wLC0
zz^>72EJ*Db2p^;$&R^diZ<kMRy+wi1@#Y^UmiI)4fD+uq at i^n&A7z6>)6tV{B-|o=
z5Iu-3A{U82Re{!<`yO~7)3G1XIUfqa6=`*Ck~;-KG#?~j6(bZYG at OWlN$ZA!M$XOp
z%j6717zcIYx{+9#2;uogIsP&xIj()LT^n$}Yl$>SlnI1Am_R`o?QdyLwRiUK;*LP}
zFlIKVt at y2?3E%BSk_8Lfe^|Z)7A*U+13!JFno=X0Q&6JAJ at 8)?Y at 6`7Ib_{VpgAB&
z at _Hzcew<H_yB}W|Xuh-E7eTrKy3ase^P;ctQ}Ypg^B}{)$54qq**}M;kL8<p$~P`>
z at r!+e4Q+Sg!g1t;u*Xs)vTNYu`tkdFz%kiz_POsLuWMbIJTs2X6F33CD4^IM`-G1%
zIH-7rvra<6h2jH69JYk}#K0KB$?lPmPGTE>9r++1*8m`rl7*jyWK at CxV~X37jhk8E
zV#dhEJ at GW4W_~p5TOoIb(WnCoDH`;6ZOj7e$@)D}1+|K>JAKO2&l%{~)6a2FuSIZC
z7pT3t`S14V#XEL%;>F&PWGm+IlVdBIefbtYlK`WDkJy<7e8i3PBVuOJvG$~1d<#8_
z0*lzm_%S|8VN~2q%~Fw6y7d9;mf+kIe0BcOz2R&Qw=$lI>s~w^c{_D1d7C=cd7Io#
zt#OVB4x7J&$G5}H^z2O2K;)o+ho!k@>zuWY{bXLs{kfot9MuNQ<Ya7t78+=L<S(Oa
z7I5qf*t5e!41>Y+n`Ha-L4^Dw- at HvcnHsC+fFZ=le_6ML#>(gLfI=G`LlYSQFc9E(
zG?!yIp8OelrF(F1)(cN5@~{{744=vV(cl&Di2-ZI-q<<Dh)Ei%*<@`^SvA>i#LpV`
zzd6BUH(YvuN52L*yI&s+fMpl}wmmFOWbL<WQEH8KrhvW(*zHtXgsv^oL`Do)Tec>$
zYm59BHIsNlJi`<668wN0=mOf&n=lUrXs*x>Gza~GSLlO>0$djkb06Y^xN*D_gB}D#
z{uw-(xn<|c$Puy;+U$QYEI0#-GsbTF1!ul8&W>;B_vk(hKjOc@?S0sD1N$fcuEXHe
zs at ->?FVYo!_lDAd?my~F=Y_q7B9`&rjC03&#=Gkz*F{m+7~TK%)2{>K$avl0^8$4(
zuDe|O<oEvmj`*yu={2x7=QG#dnZHu=vfj#})uHYd?vXvC?v{PwYdnaP&9mlC-lA_y
zUcyhVspPv+PnA#Mv~jGbK=J_2pTS(Y4*NO2=HORx%o+i_PPAh3P0+sBpYx(~Aa?Kr
z2=mYV7kTNd_kxdackYQA|I!198d}R&04=!$AG1H?>+p4rkE$-Z^$vXi-hM;eSMYi7
z&`rVpy4X8KtOta5|NPfi?@{yjUXkwozpTcj$Z4YPLDY%*AraLiWucK=TSH)iV&F)$
zRZzH)>ckuce~~i3hFfGT97xDlGY*8gDcZG!PIQyZ_nkyb!SBTw>t_9TeIpA(h8671
zg%$gaCQ>$deG at zEljQQZD?|v{F$<a!yAlW6eh5YLL5PLGz=m at vqVY#364$5L2KNVk
z5#V<Us=R-$f%7<j7hX57+?zEd4}PaY{I{7zbu0xp*WjA$i{g!9j^YlXk7O!ayrvSW
zc|a46?JQ6)5{5{D;6(BwxsgF{;F}f69V4C^*SQ1Dhv~<>w?%`d^rhuX4+dUcMe*<_
zPx9nX7q9n*Xry4U|14I^rs10$tWk_Ibg^A+Py0FIjwD7x8~A<0{+U3+D~#85tuqWx
z8H-<Ou!>&-MU?r4Xf3g>y*k#HCQ8UbP{uv>LwvC(VjK;Wa92xAZk)n5&FA*9Mc?u1
zc<o=)a(rJ(K7K0iujtMKZ5C;U3)zGVqX{?L<6nR6XhjtT)@`BUuVXe5^Y{IjK%L+3
z2QCc&=KgBW*kEh^XA+*;7)h5{YG3m_EAD6<-SiXl+4QekM?9bvIb at c;RC5pay55ag
z0OIq)+rd?9P!60w$N)gs?iz^B!PEOL<fYW4Hgv9{DRuoMH^~O(W8{dkQF2ij_FD^^
z&clZTU$5V1#=wPqR%>+(StAeH7_oQMM|_PP(8;cq2QYZ3*v5un48w_iAREIK=g8Dn
za%JXAG{ePN>TDHgrL*wKI!hj-7{k}jS?CtrfH&4gI0MfZ4sk4;fRkL0>vK=m!TQ((
zdkh=MKGq!Ti+vf|5&BUYL7Y|m5tF^CTbi(~Ve1X}S(6U-X8sIk=NbJTU|+*PTj$a!
z77m)DJzuXg0ydJqT=xy5<nXFDYwfiT99?(4M7|1s$#3wfH<$P|ih4MsxQ8!pE?wh<
z{`C5$09W{oW8e$9+<f7hu4lO?H6LqXO{|Z2nw&{J at LuCvBf*)*o60R{wz(7h*=*l^
z6X-tcKQ}*i?AKg;DU2b`7rGB~z54(l{nmWe{MCIm>Z;NK$36CoTB`ZVwbb5xdGH7D
z2emQ{75)L_lBlhKazNnZ_c*T3>3DzD&0Lr31K*FF#r?B>rsgrK*3&v!EA=kA#M=4!
z*7}{F0qGX?a6GNo9`j*I@(F#5d<0|<^bh-FGoLog+6hff-dl5*`~+nCrGF~_fQ&Kx
zmT)eyPlKa at Ss$%6Qu224qVwc-*stUB+iTymbmF2`2ty}?sT1U}w8Jt8DDJtI5AIQ?
z6!)-ye3P!U!Vf8|8JBt_Be-Xt70{24^Y`Y13$76lFF?EYCw0uNdquvEw`xIe`$;zW
zH2kB<7m at GRN!jH8`s&>}`8^W2_x|Fy(d2(X1=9zV96u<0sDa=4?0q_hg6hLMhhmCC
z&A~wPh(RE83L(ie#gGL0Y9(+NP*L2=@Jw$<Q7>Xrc(`a9MN2t$5-<}*5HHXP<kw9+
zE9p$k-}~_k>e?n7Py8;E&4Dw84(vil(Qr;S6Rl4>Ay*0;_QlcB_%p4RFDO_(%U7EO
zieH*En(zE(MJ6W13PL_0-&l}b<kF0CpJ>WTXlPa`$^pX&e)1mRbBpg=BvAO+MLWW0
z;dSB8I$X57DF1X7TD-?+a0oK*g8{BP3-K(#5IzqF2u|$wN+CtBh6J)}3<{d~CC9R0
zLkQv85&k at nU5ZzleK-6<d?P^jOyBiyY*bOIb at oBd()2S_(H=u2ED+j1{`yF7a>`yi
z>|+p3jqI0=jr?7rfGuZpGyRWkGd_EQ5=cyf6H)TQ$US7^p5Md?Zj?Wqj9z>2OWMdj
z*_-%CM!?Ca;+}YM?5s&iF?N!ax+dg5R#ZvBaa%Dwuq2fgi#D`^)lGcI-oT&1h10{q
z*>x9e>jGo#L*x3_aGMRvKGxEMriI<7o{i*rHbr+_3_Y7eFgO!UzIbK5$YQMx5-ah!
z(H}#^;`~`G7-&iiwZ^b(4#D`$F+;pKPMotmq=NtciX`i0-NEU`W%HOlk76o#yYlrs
zU-6BRjgRGr!8xP(aQE%)kmu=oe!X3L=lsqE=eRx38G{=}al||ct^midz)%Pq1%LS3
zDEZL9hLszEb$IBn?48=1S`u0>f1GNsbZFP!k*7*~(Lv{^%%#5#ewaJ(>0_#K_{=#8
ze!yL>$@RHkHgyaFei-Xz56{)!*l*{6?S?(m=V|xuU*g#D-W#vcl(}I$!QQmr3C^xJ
z(C;twbp<}3jbYcKO9Mr)aIXH1k>s28XXP2NzF*?n!ZBfROj!6;T7{pS)8Q1koVo!{
z;ZJjE4)19=lSlZUJQ>5J;?Stal!N`?<Kw@|Zy%ADse#ZpjyH$Mqg<DJ at UVa<jtnPQ
zQw#?{a481_$t9s|k+w;@g_cD8PTP)HFCTPm2(E$6Z)Z67C7AcJZlrb`H6#6Y^q0Se
zo&FIH{+YE__YZj`eAHqdJA#P)4%zq=+i{%Bb+}#!_u+nMO!O=04!+WQc<96WdV>wJ
zwwVv6MvVhX=lqS3gnl2$8YqUX1 at k!?bfauJG^W)=M$bEj|G~(Jx$@b-;?u;)8=V8f
zDW8muL&l+&+0X0H=jL9=vW{BcvS#*CanX6W>qqbqlsz*i!9)2#e!_R*Px;pT+jC9m
zgSbN+QwyUJ?u-1*H0p^Q4rGnJJWQ1y<e(sHAOlT#sQ8$)=+ at ro)8s$!^J?(bB)mrr
z{(FB}O}@mcgZKE1K>)`y9N-#n)3x5Bg}?EKzqoq6Hg~r+`YLVu6*9m}WekFfLh03d
z?Pe?rr3wfaN)VdB$LJPuoH7V13}Tj3I|+kqMW9TSJ2EltiR(J#IcL|}NL%+GL^SCF
zte17O{#67A`Aj_RJ)e+G!ddjN*$_I}5}RUM2=?YkKrUjEK+!yo#!*Qpl21MHD)640
z#9sKm_h%waBqlZ7y4L*^!POYPUARy8c^eJk21p%iXvF3`&gVKNa!g)zAMW=--Ipfc
zYji;$MY{?vunYw*tl8^j?=;YJy}7pDxMHt20de&W3Qi9*7_KDJwl_naqw~2A*Xscv
z(0#do27TJZO+JVx`{gTa!T!Qm?76{y`=|;~h5_C`=X0I#RqdNSdw`SstbHji-Ha2H
zqZtR0yw--?aq6VCCM%&56V3T^1Pf<~Xz{woGuRVQ#5PcDFUe<#BgcD-`xg5P9G3;h
zYTzW6k8tdt<4h~A!`U_Fefs_MI{pE#ZOua8Pfvh7;elzdv|-xxlJ3+5ynKcav*?=5
zR%j2&Zu=(7NOa=VKFsP3Rq{N!PK=uC8T-lk5B;JvK;UNwpK%O20etQlWC`zW;P<!(
zh<k8;>WkwFEkRd29Q~B^h4(pz<K5VWj%XiIm}_tBll>Aq*npUEE+alNHfF;=xxaEg
zbD0~yMEI}#Y2T7pb{-^OI+8nQygS3>n&E4#*Y*86?~Zxy0{7ULn~>UX=bt&4JZ$<P
zV6$ggLxda-q{a-*k)6%YIS9z2yAJ`}6u?z9uMYrXU|kyB`RY71^CttR%t;;^p~Y|s
zuE4nmbUd01_qnDy!u=0JfQ=iS7xT}B(vIdtaH0IM`l<YS)}RY#O?}7hp74XS>jvuH
z%X(^!J9ie&fX<cDsnDt_&M$MN_|lrj&@TXAWZTY{g)<Gwo!L|l4i!Ai2js(-!KVWH
zM;!~V{B6E7Ze{N8gZ-+@#1- at f?x1(@$h8?f<9Boq?nPar<KblFbX|*UqP5f<+%vW4
zC!+~<?sm=|`I;OpxW>LNH+N3%uz$Lr`s*{S{uBCrh45j;JK$^N;X~)6dKw#h5xW2S
zK+x#E1pPCEa{$-idcfBoD7$5Slicd-H2>yauD2mJ8iSdR$N at bjI_BqHYmX>Bj`*4}
zcZwF9MvvPw#5a*ZkM}<?&hFdM*Bdnus67pB2~4{zcC@|24 at b@>N9D&0L#bsLP&xvK
zf at g}ko_|~?jRADi2<t=)2YR1S!vXTq+E2}1%Ka3z3A%u$<iH?%iH>OgmB-%m(|^7C
zxb)-}Pv+kzk$HcC*R!er&DA at 9{_CrENOTwy+$+%7zd?(5ofh_5EtJOo<=Vtcw4oPk
zV=vHVpC_?=mJIPs8RYL2uuqlIo-6}CLB at Q%jQzKA2LFX1|E(ZK?SXNc at QS>i_Tcy=
z$V at tW(sQ!v$?WXwZQ$(h+&cQP{d%WKabJ@#im6(A5LSB`B&~gpz?KbmG6oT2dN)Z3
z0SEaS at nTX<abAhZWHZSI!9*-b6+{wwC|cePIr!R=d>%!$l2R1RQFu>$Sj{HI at k0ek
zt-l^1={2~)4OG($D82&qw64R)0M6;xh+#oTt-;6!qhaj7nvI7D&W-ETlXtE?_FwB-
z_S at Fp*U9<#1^*Dp1bPf(C<f%qC<f$Ph7R~U3Ih3_#{L!J0z#Dk_C*R5oEeEuJc3V7
zYI`Ev6WB;z!dc=nuLH$*qsOwbCKJbv3(E7 at 8t5_D&||d2@!RA1I&=-_xOD9PUcdLU
z#<RT?78{g}oa}b}*pph<4i{L~jcDpCSyA|qq at 19li5F+$TSX_$&^s%!L=q7PX?EZu
zg=y#oMJlNGIfi4MfZio=jXppGeJBTFPzA*2Yf;C=c{-nKM51(()IGRgXdCOUbrOTb
z6ETNQ(C`EFgZEr;v-T*qwRi5}rr(A3KERFwdyAv9_(9+In8{d4pE^dC*Z?g)&Ny?5
zopYDakMHMin7o|p8r-aPJI+TD+WA==1!uzm?9}sJ=dSY}jZ5Uc%6)6$b!_~j at DjK2
z8T`(otA?}UIes;dMouj5nD3Dj`PPZJfhNP7&-~{1SD*Rq at 8dN?Sa?NDcmTll&|^45
z4vryF at rBr9?Sm_|SK<{rgub?+Q0nM+7j7gc(jSYTnqRFuU5|DhyD9oLjN9qj;EG^A
z at A{SeIP#)%qBn{jCez^eA*K019Ae*Ihy$AU;DjM=xPf;QPxCw=&Vb~OLG1V6`}+;@
z_iM#9_;xJx>l>2r?h^N;kqh^vN3O-P{^~W at TCZ?y>Tl}aUMJ90a9_C3dU~zEUa*4)
z2*gq7o9u`^dz0+CfrcC&<BQ;OY2Sc+MGOb@`*^*-U&jV~Zh@!T0bQF13kLVxk;i0%
z=GS1qrr|Z2UkjoEoVsLA8rCm3yXd+xw9gt}s2DJ;oq>vzj$;mJi1!_99X{slvxy$B
ze+Zo2V_EOv_X2y>&wcM5qXq(HuWrZCl-BTfOkd!a=A#-+ at 45p<KB^%AFkj(Lev_yT
z7b`C2Fk0FZIVod_m>R=?(v27fZ2B<rlIk35L$7O=hp5zJ0=dVvSoRy$YXIp)@3B6w
zoOSChy2zV#u{Y|Xuh$Lk(am11o4-=Y@#R|7OSHJPvH!tr?6vVHoiz53kpmws2R}-Q
z;E}>#edh149`Wh#Ts`7b-?{pWPksC9&ja7O`m;}d>*`NG at vW=>{)ul60xU$*xjlI~
z2`vq}uATT!A>aRNz5Z+6^N4Sc*N at q-***@j9g-R{xR*0U!{uYV-SzCU3EhwRn~9z<S<
zyAsxu at lMj7AO|@mdYzaql$;!wq!`Ii2{8U<GD+EsrPq_RL`ss at UNG&%97Q+8R1yke
zij*|NnZVZO*Udc*{ipa^W#ISm^Amc{%{<3{M1>aTehB>Hx4Nc^b&{SFpTPa1`3U4X
z23XgfqMzSD(9Qd-PaLBWV$X)xs3LN{PH-IO#JcO+*bh50oWZvD2{buxk<Cfo_+m-k
z@)<=-G$r!ocycd4<8uqs^Wur*d@^s&xbQSW5G{}(I5;`^WFVgQgf){?@_Og{0>{LL
z9y2=}R~?SIGxXRT*yDDK;qhL_{(e998uYbzz23{R at 69$NL6%)Z7o6Oz2k3xc9S98|
z_66dem?z#T+~5MSO>sw}A;A#8aEf?^Z&74!yo9T8(tLCgnLMmvlX!?ez(We&;Nd7D
zlZ$|-W+cGiB||79igUP{pT%*dM?;f at kt}tOOqQuhIjG>zlcYs4sK}UM*uc8G?w}hU
zwDFUsjbfV5*=ICvIzRTOYkH7IVayuPNf*P8sbjOh4YdV^x<kVS$Ivp|F4*5Ao+3Az
z6UB=?S3Vq^@NdU{Z(jFxI%kan?6!^nn!hH0lf%K|(kC~0&*Q0IX_$vs(cnc6%OMtg
ziAJs$R+Ym>VO2#He8JDez{p+F+u)60J>T;dyosTaa?_{P{FAeIkI&F~ILCGPW*jks
zPQz8!!`g^}@eKg&gJH(tPP4~oCW<fq$33UkrcV}Mm7eTcd95B^!VPuqPV_A})czFU
zYyi-UaBCXCM(`k>{&o&TgD>BQ|FeOAwQNnyM)Mt7(Hiej!yE^RiOR8o{G4MGc`o2O
zTn`P3JnUR7+zoW^&_hG(xel(k;H%ecaD5PKul08hqkHhp9FE#6IGnm}4o at ***@m-+c2
z4-bSqriKUNG1pi%KZl^!Mb^pMi8pKgs5|5r{6izO4h!lDdg!LOf2lD?11`XvxH;fa
z0ZtXSx=vpLTr?QS89X%(l%{2 at u6p;B1+#VvZ7i*{ZaTJIPYvkzCj!0BxIe)mM`WB$
zz3!j)_xk$}6_>81-&w<@_3Eehw4>)kY_LDw2e#k9$T^_f+DM-)=)M#Bw<E1VhWRqN
zl-wG5N{BoK$49 at FbwUi!sB;t>r+G>-?>HyMM}HOhDQlV$*NRK>5^?%L^*(2Pl>4Rl
zS)bATN4%E~eBu|szPfdn77z`-7WI6I=ySB#XKLY3m&iU<n|X>h_{3`RA15O|R)+p-
zIf5pCY4CxX<+BF=Pt at T5$;T6a{PAxD{@cgCarH;SfBk6U{}TR7VI&t4(5Jy{#z({c
zsg7?CJo*HWDqQ;P?0qn=>wD;DUxUyG1&85)_ffbuQ7T|M93VYN2!=uaM(mx;(YOhn
zz(L+2hJwht6j+FIBQ6*dtVUiJ=q}7ViAi!KzI|9=BEO9UrDS3vQ((P6$e76p5(jD9
z5C8&0-j4`0{2x at 3BAIb6fk3gw_1q+r2%V_7FG)L+HAzeB8HpOiT4%z3t$%7CAd)!f
zuM3<rlXSbLkOe{BkNdh{coPLg6c|V3I*mL&*Q-PuYyIh1XA}&wH+FZkkEqPV%hRPF
zhX3qK{2GNO2^ZftE<8i=ZJvxoCk$aMeofAagM!7`{2am_$Rx1ydV#rr2XM at s!Ex2$
zn7a;poZczUuIYPw9bV(IpJt1ZFohoLo at 6_|XXBK<BZeuWdb3Y_zEVXnJb^oKizert
z6?46r0gfp*E*uLdiQi~k#Q#y?>DuT(ax9Cx&aoISRbe-ZyFhZ!Phv=vp*a-uO?OC`
zsX0Aamc~#Z6K~oR at j;Bc;qQ9Fe%MzG3QIfqoqdxy+2=dPKJy7J*Cfu}q{TiJOROb|
zSI1B3X2gw(fMd*5+=S1jMiVdA?q1wEc1HXdBaZF>w>z({J?^RZZuhhWj6$r|pS+yh
zOnw&PZ?#J|K-ncZJ9E)eKnd72cp)2`3!vv9{DH;|PP9gE424R6vxq`lGatOQHAv(N
zV!_4KX!Ii&C4a~@=Fd`G at hy?cO*H<z$8mcMz5U00{eM3Fhqnx{(CUmIc$Km9ocebF
zQi~_2h6WGqmF>$X)7Ptxbe-Ha at Jzb`u2s%zm;Lt*zV at zlr~2l`-y9m8Nv^Qp$&cg(
zoQMY)#RWgKK;vRCSh~=CpV}~e9|IowBWeU7|KKBr>(mb&ychKZ at bTgd*Wg<Cl<UH+
zs3{`XXDt!A84Wq)=b58fcjW0Bd{S4Tbx~t=nD_P5ua{%^N85CM)Ma(;xR2nvtjEXN
zVASv+^z#?7XAixiv9N{~{|%ZAKI0+FyMKng_@>Jom`2Wk?_Eo^9 at ZCo)gEYw%>Bq2
z@~?A79|oYa52e|s&J8F>PE-xN!J2eaSnE5iZ~gZLeP}SyG_s>=E$933bNQUO at z1Hj
zD~K<n-eZ8MpFJ0yq3ituVz+@<?zr^+LxS$thaRBc`?jbxpY4x9YUZwH8`+be)3#;r
zLLUl%&Ix$b^I7n>a+!zLa}cl&0mxy*NycXm`K(_fXDK#a-?(-oF3COlz_cEex>u?g
z9eq;hn&MPi#`WAEy<2gAE1&TH<m&la(DT0aqpN3YkqiL-PJ#K<uY7+z;eVWr at HaBr
zX#OSW^XYyz|9`Fqndbk`)cpUcntz_`XVagJKTUsc{Cm^?Up_MNpFi^Tz<>JC*Q at z9
z)&|{;{iAfhM0>6KKWvQacFg<swSYM=@X(+Q2>k7V&(@GYw%ZeFPoU>Xw35Dj;D881
zHxduh%4Zg!PFR!F%|D{si>`fQg>XYuC)-FUBC8AW*GurT$<2g&ugDdRK82Qu3-Kt5
z-c6AuLPFpVh at 2mc$#Xu%|8P8on+-k#0g5q>=iEVFU6X5b4=3R$up;SH;?cTj<om?^
zRa$c-W8oFzdQPe at VJ6WP`7{%d)M&7{W`g2QsQbme1rHSN*#-o;){gaajt9$LYCqhI
zd(S;&;zv|?3gUudNwNaNo##r7BFQSQ-NYo0$<RV)4y}pnB=L}30?A1y42!qnCd3@>
zzh8^S{qgz~Ys{Qtk1hYc#hc$dH122U=bd1zul8emM3UNUIg(HL0DokXaZ#M{8U?X@
z?P3^yz#n4qt(7>4JL1j5wU5!T=ru9MXZI_%+z7uxvBdds4PL`97j6`wz1d&*MA5bv
zZUra9L>75_lV`m-6!uyNMJt0aCq#5$Cd1SaH~YM1ue~@$Gtdh+`6OCmh`qgpy~%#w
z7kgrTjtvjS at WFV}Q-wmJaa~yWd=oyJH)kBW5wG|bK)=_9T8p`M310tc at x&e*H;qvw
zjhvG<a=tNdgS)Lb0?CQwK at 6RX2Ya*chGy_V{5~}L@@sGO$q)D(p1^IIx_AE+K4kv!
zz!{!6_lzcAvC*6SPex%i!S8&=G0_YO!8u(s3ax1V>l-8$Q>>4*Msuk3yCI6^Py00Y
zumv&VhR1qr4c at uebrv69%Q<sNaBX3@=C~d9^S~KLJNL{j*17Pe_|iGjx$&H)4@=QJ
zxRAEI!~=8Ttv}>}Kz?&BII)5E0mtC4-r#!>pS48}-y;|6zT|pp2{gpHH}kHW+v2qL
zKm&kpGw)7a^nQ1oHLJFfF+SVk%9y%KjHRv}Vod9GZ5P90?TMzHy<$sj5X05d+xJ!;
zf%A@&o=f0A$8kJ5jb8hkVZ<ypi<%|ubyA~fjge1mt7fmWJ@$s{tl8gf#=tz$>{rL0
zp`VMLSL|!~-;K7mll2?cWn<KK{ZBYgk at eo?VS`aQqhZM_r3q(nu39kkti89te~KD7
zc0F3&@9!m+|AoZsu02Hli-7?^gJqMUV_ at 2{Ya0Brj~tKvTWrK)A84W{&U4l_25M3J
zNSn|w@(X#!y%hP!xeGWijR!kRZc5#Y9!l~39=*PGuReH-F8U_@@_K!6w?25aZu)Ws
z?n|_g7u9g!ISN<?15eWi{MG-*Ym<K~Lp=8L-yK7NzfwZ@%Nh#&g&N=-2z<K+0^eE(
z0s_N;Kl<p|K;Y{&3=ls2^{f9R%qRcZWV`V`ZPZ&M|Hw~%^8~!#adwQce_rS4KKvZR
z0{?920|Iau5_mu$oK4$37+8|7>^zcfBQ3?6N!p2NLPEqy4kF@`U`0TR;X%MCytBD~
z6O;5RtY|2rpc0|pBLcqnU#g%I(RM at w5BZ`PS8{M84+)hd?i1f!B=J<7gzE<6o~`+%
zv1VOv;92K{8eoBB2G~b{hImJP#&Miua1CFNB*lHWUk(m3>9dYwL!Si#>jrO(q9LF1
zzghc=VnntBG$8>c$3VRw$28a$fJ8jM1u$*%n#C@&7zta{9`9;NHjB(-^X4Qw6A8#f
zV$OgySro=FpfHlaWyJK^g95+q??<z74J^pT^(O(n-Z7 at fpyI<=5{XesV8NyL2ew2~
z*V^v~ye{vx+hjg5O`G;4LLv{JM9luv)pN(cew;;d7H~ff9>7bu2=5%LZvIIKA6Mh@
z2{knzRgxfSyic*o=ltWZ_x<RX!9_U7HAp`2D;woG2q1<$V4{dLw*ZCQ4u2LJQv*e=
zkujHX=7A#j%%^v$Hx%aH18Zd;tUHpMz-u&y&tr%oJt2PFa7DAF>vJ#e%Nnp<@V+?j
zLJ51j2pU{%{K2o;Y?t<y4x`7tN%E7>q2HnBHTWIy`yH3wFT}OBW9lBhr}IRIbH>OU
zz<am>7JdtZ&&6rSVcHB0C at m;H9||JriggA)Q|#l9)TQJK-&`_JtjlO|3|HaFKV at Nr
zE(TZ7P4R_X0td(~aN2`sil6uX{MX`2<tFh4?(jbp!KIH-G*$8B82JQW>*pVWte at Z$
zH2?Z6ntxE|f9RKLfOI{Ypcq)|e(#E6E1MyB?1A-YDA923C7zI$c1L_wY?-UpYV3r)
z&;i at eHl5mBcDEmj$AizMpF<<dm!0D`fsY;Mwrj3 at C=5OTuk}RZgse at H7qe;Y8Uin}
zR!Qwkeozx+&Q8q=O at S}PnekePL46&^IR at A1wM5rB>zjS at T>E6pofP~>zihd({Il4o
zVdO(2@}+G%-#<HdkH0>U^Sa!;hOL{O*<;Ts*azDYYs48GhR<-Dn(l+*yz>e%!E54c
z>hU at N<66YAxsH8_b=M`6=hgTRyQXgJHHpFAcG&LT`*k?G<{7+(96U_UhAjd1EdH_w
zh8U at DW#f+Gk-@;o`4XOYz&{T~@sIIh{qE0vta+MToqS!O`;Tv26vF1L8 at mgAZ^qeB
z!8Ww5vo`D;6fWq|L~4dPZY>$G)@&G>L~iP at 2hJLO-ZS?1+wcAQg}Cpwwph3Ju*PEz
z2pofDht9{~lhEzULpeC(cr+jIGqEz`G6w|Id!t9IJQ#JKVwCu!-y#-?)k{6vCl$lD
z-l!880K8QP-^V}rr$jdJ^WR+E_p at Ke=N$Js-QYF4*(+42y+i^1A}xmDz_Y*kqpN3X
zu}}TlKVLmr1bTvmkZ%k;RtDi41CN$b<J$rPe=6`7YIgayz!(e&{xgC8ZGr2)De%{y
z{(B)CXg_UVhXUJRpc?hjyz73WndkNRy<T^W#=pI{;jjF<AG;$yZ)*^8UGrN7{$|10
zQ|<9=K;R;88446pm%>bBGx36KA{rzM(dTa`OYozKkYGmvE`Pr>#9rhPQ7F18miUSI
zyMb_1AI-eZizcE(pX;UYGyP5RC&6ZeT1h|zw{Y#EMKAyw9}8AaiEC0Ezvp`-<v5;m
zD~OCPt`Sg(sP0WMu@@3iK)7(w`tQ*`*ozx|_7}}PMcog1a`4Nmx2f>NUT<f(5x^!1
zf)QY+C<+(k at o(3;T;r`CiZDUf^|=rCW3Yftqj=O>SkpQjxikA>qfx|2_(SxY at aI?P
zZX@(V-1=*YA1Dz_baA{MmkOJkz(RZ(Q>?FlZ^hZYE+MDnX@>z4VzZs&&{&=($Oln8
z!0E=}h*S6~zh?8CJavH<NkCk=SKNV1 at Qm1epG2PjhLyPem<lz(YvOs2U--xQa4z^(
zT#FcX92eIpm|qdaoZ(>{$oH}+&*NjQ6;qM8YH;RQ;=a+mX)Po!l9n|mnzLHBb?1Sf
z<(i2V&gWWOm%^Sk&^%HY1=nTAXr5%>r;F3rKlwYkNiug)F&h2SRy6k5*k?2E!L2p=
zF`v%Cu5-}LL!k1|8Acu`#QW#x_G@=6gJssStZT0I`0v>m?5oiB+y at JLuCc9LG-1Oi
zjw-Igz8-MN=1T#zaGtMAn(wJsQSc6ZW>{3ZEI;QEVCr!U0mKEgIC+#@qFHef#4sA}
zyr1GnJc3I!?=c7vw~T1+1;<M?IBNb+QO5wz;rtj*0S^X#0cU at 6^`441z`8~bu=a17
zpTqDi2CengNR4LoRO`#0;y*dkMgE!A6BpK_Q>_mTYv}rR2A}8LP``H#G<@IWgqy6n
zKERrz!J<hCq(-JrX3-3yx#6exzQM;Cy_VRUps-V0gV)yWwA!fl+U&6BKj)O*M0kiY
zP&#xI^z(c@=d^j><`=Ec_P4!lUu=+es)jS_!XJrm^+2eGvuL#k0mKw>1ow#r_z&md
zI(da$1gFo205MEf9cHfL4+aw5?qTn;dAE1i+}sL&^*v5REwa6LJ-F6HzhCF7x!`pI
z8o0CEjXit)Icv|X(=wmW`g0j%Rn8oc22l4!?Pv7QfzIJP!`H&@GjGp){jz{`L|{GP
z7x|tw_CbRO3}-d^s3lt*oyE{~!<^H28hWGGi=R5bk8qrg`mV)?(c`V-EY2>X4-5M1
zLR_=mXBnK=!>_*XeSml5UD^@5qEq|8!2H68$*VcY%RVN*DMh}dcKU!~^w#rr&|M<R
z%f9#1t5>R!dW}AOof7Gr^x?fqR&Q7Gx?e&4E+w=Fl-T&maNsTajAJ;Kb2#^<y2f3)
zA=iAa7Qs*;{**uqeUcU)-x$#59;?mgHwJPrFupOM0_AKluzX`c_^<n5;3MA{#mip{
zkI}WF at Hrg{R6$k6*4~gm@)Jfj>@@bqUk1LhA>Vt1em<h!<L4RHb0+#djD1)zi@;X&
zvBy!=&BBdh&4pSJ5yAz at l3b7}M5{!fV23ai_y{%41kLFE6yx$W1<gk#@E?}IzyFsx
z<#hqhu~~rsGz15M;absz>bhMt5DJULT7(?MU>E!|__%&92_r?Ou3tiw!h}HQI$}@|
zXoCTSS?fj&Lm)#mrw}8&*ynZHFMH;{xO^i|>}7)-2vCS-F-oGuK7iMN_m}2AFdKZX
zJBz+!lb=s2rhr?tZ#PV_NIzS9#|F;=*uVK;@r6<L-Tl#%WWb5|fG%kN-q`NFt+De4
zoN@<*4UTpRTfwE`5w;v$5^QTQ5<bbZ5<Wg!xFrxPJ<;QD3w3ZzoPb|&1>V3V22E}r
zh|hP?RH(tB=z6bW)eVlp?-XkMH?71i=k$gjF2ciTID&u4Jr@^~d)0Uh4o)6Uw9hJb
z`u?~k*Jgk04eq~L_h%j6*E{*Tw)WG97jCZjo%d6JeieIQ{clkGa80hyJt?RtVp4n3
zPxuaQ<MZTf7U$?9$r+uz)cj}DU-_jp_uAZ2`K9Z3&nZ2}oN50K50B&Z0lrqD?l*=B
zVB`+a*E-i9`6N(#Bd-*^_b~t|yDWo&HWU~Ikn&CxJXPR~W<>TU28lO(LVQs)QbcAf
zW&A|3thjN^xHt|TRh%S`ti3gm4KB?%c^Cf(>=q~R=>7ZyvJodVF3GQG-VJdMkoVl!
z$Lsd{{`u{|J&e5XjMYG`iMVBrtd%tz at BWwE#{=3Au|K|T5Xd1ku|)okd^6(PgZZC@
z#yGyQ=Nu^1pT$%@LBIA~62(5bq;&8skD#CXU}1;#_d1*%w_oQXbZ at Vt!|Uto{X at a`
zINP_^@BEW_iCA#{T9Lzp)TrB|9nZPjwemhQ?|DsrlKm_OAA9UoEtGMWTp>4*C*Ty?
z3+IR{23&9(jRw4izl%;g$Dq@?R_b&OYX{G&PBE{-p3{EAZcDD$-unIrj&_P>aC<MY
zox9kt?pd(^h8 at d>VaG89$bDqYR4q_8jXFSjMy!!1og<wedkv5^CWB4}g7wW%+3_O&
z+3+_=6WE>W1h^)7K5~6(0U$4rnzOWlydC-fv<AqWzYGtWb^!d!zNdyv9kH(ive#0Z
z3g?<KxqBK<3oiuu^2m+J1DfzB8RV;i^H+d;=DJ|~yaC9GXE-}{LEW>h!9#=?UTg!t
z9^=?y;iPPcP0dC8Kt1XK!CU0_TQuq~kRxLVpf_G6lDwAxzh6Q7W(6<b40yYO`JFWY
zc(=f71_KNTVhEsPIp<X(+sj3&@$CRz_c`BU5b(pRr)vTE4T0~+Hv||4{EZyqe^cO*
z+I;-^fH1!$P=7uktltu-e at Ji}2*fZzaKZN11vknr*w%t5k%f~ADnF?gW)U`<_tDVn
zzW*!nmta{_tyAlrMP3zh{7(mdvLjo}A}z at ***@vn2(sh^SR$n$euV;^0_%+u6$%Lo
zjradDzcxw1!|MlBgdpw|?}!hAf^Z-f2m{x7u|!}IcHP5)O``=_mjDJscoUJ(wg67-
z at B1_TT&_`K(C)$grhuooSZG+Eo4i%XL7V2DG<O3CqJ^=Gqfrx9?Bk{#oQWiG10RK#
z*5o0|5Xv337Z)U1lvH8z5P|si>w#f2<7_Pr6dELUi~No?0T`KB_u~TCL5L(GFx2UT
zorAx^S3>#drIo};#Be^E)k?&#At5RTNRn>GNy5Yge9wj>n~r<cbPy*r9`{8N?t=UT
zG~mYB=LHw?Tob&tiuyTB$~8FoGbo4xUuz|yzgA!$?1z|Se@@(Ea1>k=#A8qR*JN!J
z58KZUe?F1tb=&tiaYGja5Uq`MhOM>sD0Hx|_Lz;_ucFzZ`9XI+APtJ<N#J(|lzh%{
z*eAXbAUkk9iWly~Jzu0fvZm*JJvjxZtvhH2Nflir;X2VDh5%s6DcLk<PMLYde;PLO
z$!Sgj--w_4KzPqJ{{0+z&U)R1 at 42ia)|Ggaeoyc^^T!+v<hKn*?o=*e-}^AYgMh;j
z095hvB-u8LmeS+0duXuyfOf=?R@#<)O74Wd!kNLB<Z|Z=z9uGPNTwPjh5+IL at j@()
zm{Pov$KVRNizfQrKhMD!9175I2Yy>W)r5;<pud;L*H8^qL;lV{4(5Dcv>;+xh&X0#
z(u<5?qqGD~*}#A-Ui+9jhx55k*PXFffi>L!(;O18HV;6&=ehQE{eA7|Ppnh-Cnl{g
z*gmvHzHlQK!vpy#^h6qaHax($GmlyCw>+`ul)|2SoPYdtpkGUf=C<VuKcQW9E7!T?
ziKbW9tZdpcU!bMvS2S?4Lx&ru4u5vuM5XOQlf!<3?!Ve_+OgX*?5Vf`-lJ{1gT1?^
zp{AHNnETHhnK9R!R2ssr(fi;Q{tz4JG6S&~1PJ`zH5#tMV;a*K28c)41v_A4?#;fv
zU)IXn%?<qR2JozIoVB3q!Co(>4n4U(&)5AJA6Mt at HDuGSUPF3_2|P?;-L@@0bPnwK
z4-WL2gPa}Bf6IelYQT(rYL5IlF+Z>2Ux%+DaJ~5eYSs_j6YyZmu^y;F0sePg5zx9_
zU*sUsHAZq9{!n8%hRkbp9eW(>jiwRivwS}^qHG)-kj<lhFJG)&C=6e&{w5!}sqT$-
zHu^LFcaYx<558R+>~LQ6>;C&C^lSP)^Zso;ZM~6O5BYWGSok>y?B-<J9Y4HDKD_lB
zk%0#O^$Jd!`L`$m at O1y)pZz+(>$fP8yiuRMUcq~}$n|Ow<`p8w%S4R3M1U8`@z0mj
zpDQOn>zhBidWLTBG&wRFe%<(qT0s0mg2LZuf$<FhZ6N<N;2(~SKls#lvhfEhPX6Q*
z$8Q7l0l at NS0!I8B0`+ePfGBKck>i4m;%5|WRXlZ2Xg!q1|1YkC)_nTDaCWUzv?6dX
z_&gAZr#jlZhXIhy<T8nZIPwimB1C~C1S`S(8U;M!K%sFzBCld7o|MEO;CE3(Anf<*
zbA;q|5)PWD6!o7(;J-*@bAXflqrs~{UW8o4MRa?>LhcOM7PLkShCc-I`ZW;*6<Ee0
zNw8Ln4T0y0zV{O#Adkp%>pF*PZ};)<eDx{5{^a)y?Ycw!KwC#oSb?(tS}aL$6|?xL
z7YB&+3tbo?;s|;x5TXzw36Kz+94cAdQw?;0q%soBiby`u#CGI4{ETBrQjx4?;)-NO
zVr#|mTPU(Y6~?!1$lLE6dtc#gI+ts}?Yy?`se5sMCrb9k9!Fv%Aqr6#SCJPDH^ogP
z!5sWx&o%k|KsNtDCcgl_n8jPfO!L*63=8F3{Jg}K(YXruz|N%uihDbJeqC#z-LG>l
zxCVk}StPMfb1e8J+n^WlDw;jn5xZhzGzcHWP(VJTiKAijK)_E_DK=?j at E^yACh2^9
z^KxA?ip<g@?$3JWFd+BLlsz<|CElL!BdIG_F=RdFmdYtY4gyk-hc*i{w=e)$8~M at L
zca7K2@%}(Nw%~z+uif*(_~|?+jK&|-n%P4%{*^b3`KJSGLF0mD6ezM;*v?uiuDIZ~
zCSmIwDkdM`_tcz>i{6O1SSF^HV!1ShI1Eh~T97(m4Iqy5&$HH8AA>m6H}4Q<$Zywy
zW4d0XPUJnT58NNly}q<;*N5Xkj&ICW12{Ayfejd3O=O%<!0~guujA5QO`jKyF8iU;
zg6$W>P1z4!WzDvkn>zMNEcshT``~~W<TH-3UC>Wr^j`i39KA#<ud_vI<!Fk-CarlW
zyCkNT0$y`m-=pDS5!cVBt1TZ5&g8z|T)D%;l!YtW7rxKo&Jpb2HZT_6h+E6=4gDHt
z=O;I(UCp(#d=&Q8zVK-dXl6bdO&XA0u=go^jNmvkS5~{tICFflM%D~BtjpAhAE`eL
z at Pi{hXOA48!+`o0sjkgExF7c?E<&p-4xB5|h-eO-52Ya^2TE6td5 at gr{G{Jo{<{{-
zH4;6a4gG2ww&yhGwb}T?)8r?6G%x2cbLyDunXX~3Wv;Df1aqZ>Ys9q#_>=Kj_~9>x
zZe_eSK2^-_&3}(w@~U;rF?(0(*m<p!1E?78*q5!zPk+u at X7OkFu-7M}Pl%i&w3>eA
z at yktp&+Q|>pJC*{mJ0(p9AE#ut{?B?3fpykU+2 at vsmofmcJD>|%Wu`ypLiEnBc}=@
zr^>F*r}zM$ppn5l`47K7!2bde&Agl)&AiCioB3yc>)6acK{t53{{cV+R{Wj668&iC
zfi|!-^)iCL-oHH6SHTg at J#d3>?2Wz}=F#jI4h?@b{n_|`<LW<w59dE1_#cJ;^F!ck
zSN}m61Ar=k`je5hNLvfDI~f8*Lr<e`?7#Q-ceKwR0rcKQ)Y`mW7kVz}T*R4t5G{+g
zB-Ilmh>}P#1dy*G4gpMH2Vo=zhy~*EfJFTLCGZ~*-Xmd0)T8K at xFBK>3~_sf2=_8w
z13{oz;kwTipSTA^<$eUYgPWjcEe`75=w}emU?xZc+RGlq9ecq2p>cN4hXU`x82b~Z
z7?dCsY?~0ivRMu+T5~4b?nQSr`>p7Hp?rhCQz%qGQ3N3NPEHg{N=hV;w~=V7Fv^1P
zH&^dg(hu-j at 4*oY#CHl=%w*Ef<V17*tE;y<F$wnqCnx{j-xJ_gz==y>O`{0f6PJ)l
z>!-075*GU+VeQE(6O{*5RcOFd+2~nH?9Z%%V=p#>x1emD{7oP9q_hvLx(`?1PMF(!
zqPh-eyfSXb-Tn77_&#G at +nN*FQ`>7cgZb4pkj)^xZ2$FF at seTyeZU7Vpm;JTDVpRz
z{E2^~ND>#|5{((Wdmmq^W)L7SsN_9#3C_LcN5721hGGUTa6PW;;baU0bZ^#?e$Dt{
zz4jk_vR`cLZc7&dskhlgyP-ZCIv?`R0oL-4v*YIV#`OpCzFvnB4Ss#q-<bbKz`8H6
z`2Lcw!_QNLy8eJDo~1!^5VSV_fEawSd`?W_pIJ0lgCY)$=A?>J4+6$;QGRwIZMex>
z&^6^IsPo<|oN3O~n<|cn*1)y=RvdhWb8y>xrXY4Pj7^rO;<DAy9ExHAJBBR-Q;X*N
zK0eQl*aCIU9Q3B`GuA5J1afr5oYoq)SDdhq9PGLg%t36#plp#1N;M#gH}pQfW#QZ)
z&=kJs7r(8a6aGApZFxi2=*_TS`}+R;T?`=v&Us+ at c7yNBJqyx=1>^pC4%dl$RMU;N
zus8dD_#A(eU!pNmol`z{j-klLW(*-ZmL?k>hfVXz`q?mxdy)gmlhO25&Sjn6W7=`s
zQ`;BzWWZqC^?^dq!Q5x^+<@=-9{Ja~I-AjIM7dsFKi8G(u@;XZz;Awc^<n+|AT^`j
zXRREI4{htn at z`1Wk9aEEhFxVdH=2>RiKWQfKU(s(;|WcH+i;v59#DKGlK<=L_In*4
z at d4_3y|E`&xG%9xys(y4uX13CpRHAJ#XgSs5yHmUx9qyx)ErN4+pjy4zZ~-}A#4h$
zxwg71d|h_7j?IQYdEGS(yTe`fbF7zEo2Q1ghZUtk)~9UbGw+idT<eoBqJFJByVgi8
z*N}T!9&$~x<|^ecekzZV%LZDW%YP%sIWV#3$J=4#&n<@zw0rOQ)a#C1D)d~s*Go|=
zmF=)2HtjW1)a~*IIVPHW`3{buA@~@7M~&2YWnO$xyt?&RIpQ%&+K<+aY2M=>>H}J|
zpTy6Gy`IJ!YBtw~{hOm<AB{Uu0~=q{KS4C}YTN^Qy)^ST!q)@;8PtCt82^RfhXwx>
z7y$f7HU1s~co5Lx!t79B#ot$|_$uU3V14>>+L-@)fP1z39-4kbz6zqshe^T=3=^*t
zjsT2e4U&mqG(15r1v!NaN$a%|FNz(+3i3Q4;d!5gJOn+40KZeS_v@>-i)4t|8zn3V
z3WR*6gaiS(s}<Z3_*oKMgo2{RMdB(7a{!QHkb)2exNt52g($`ohv4jR5DSkE9D_a4
zJ`3 at f=d6OVUNg||)$iTW1S9-qAv=M6hz$UeKyANfF`o7r0wVimA&%IlZF2}f5tzx&
zg?A(|`34ce*A#k at sN`>w#9Ko=@cFMJapP|TzmtSWRwNmG&p9L&{C~F+3fCi<L;@d)
zL<Mmr6A~yzKS_nPyr_y~00&<nkpr1%R*Xb1ILY^heJ`M~K_;TcIR;OALJIz+EyJd8
z&=_0<=>s>z_ at pPNYdLC=An^Id0Wf%R;LL4!eF>k^c{@LYmt1cL?@z32t9764NASKQ
z$pt at e$J1?^U5%ofM0`C50yHKnPE at 3zOOfy>n59k8h=_~k>U+gchLva)zf&NQ2q}Ew
zDIBNx-iMVgD&ZHLB4*4Z^T(V?zD%x6j^v(u(PD0#+3Xb8*!WIipLFzft$s3UFZio`
zW)L6tor{&Hd{MS3y|FK&DV0B?5v?Ya_{6TW37s*GpNah#1b`^6Q#0 at n8iN0$sglp4
zP!-&y1}I|14fufu;bQ~7M6tUen)x07oOoTp$L4iH+oD*W14h=fH2r8?>DdduwQ3jp
zMzbOhmR at zOnnm*kgl=6z4PNy6aGt<*yKgcttiEAwyKm6rIiRsW<cspd#b&1(T4FSt
z$ZSZKW=91n at k#714UQU05Djiey+1L}iAG4cU)Su-Z!|$Py#i~AhVw_&1PS;z^g!$H
ze$6Im9p+$%o};>*4D^F<cJ0`YgY#U6>+KDtZ49@}ad at 3vPTpc)^z2eI32fhY(JbyZ
zHf+a0*>$)30*0*#G#0ImA#BwL)Q1cKTqg$VIL_f3+?Vy>uk=&a5*|>zMf+h85e+NQ
zUTJXbv(dZ`$S$&t<DEE#k6j1$_fiu&=JmJ-_W~Zy1hkg0xrZcLXL2jozT1EJ;LQHA
z^O;S<uG{a1k2mkR?)^V28+QAd=UOv+V1FK5!Kc)$+2F(Lp8sNqQZ<$J3Ei-k%-ZQT
zc~EfvGY)x5`ObCET7S%1d=AqK{3Ggty?<*1^X1>jalbVCrX$w(_kXAzxGxxMyigah
z&!y3?JnFya9}hxGgI$|Py(1mqVO7-S@)y3tkN7ldosD1CxU~*XU&jzlT0&03$FGym
zZ}H^a4g6@>h5sr<b6z-azE9Aa at c1wM2KxJ#LDTM^HwMkUeg at p^pW<s*|1kytmv9^m
ztWM9ydOTeTV(esT#G)~8aI=1n{`Jkoety4CHu+$Z(T!*n=&gZtp_c_-24 at m*ZTy3L
zRcu2L5*>-1WQY(Vc+m`sXowDi|AAkpsJ~l+biV|M0RV#iMjcDh#JLpeB(S at 5J(|1c
z*W{3UAu8P4g%0a+6ZV7>leOt8Apy0w9&E;F{!hgu at o1y$cRNg5pPiG#fd1KRuI!uj
z{sFHKpEcZW01%>5wn$+~JME1X!t5gO?<m4u;JL7qFYIf4G at 2?u at u!ebLdLfg0+H0^
z^Y at 3(e;e<Uu;ImMsKk}-_m`IF;CmNJ6hY4^4vYdgP(`S~TH%Jl`dzr1FC9<uWVry3
z%q1fl`$8nDj<R3y4YcI7!?rif$34LrXMVgM$pPXx_)v*)V*YM^kJt74o#S%zKcH*R
zH3+9`Pq6Q>Nwd?4<KpQPzL35!S7~1GWhTV$1rHeLFyJ}zbq=g3<j|WpC^^DI3LmtH
z1^}(1s0zJu5h}#+N}s($$C$%t7dkhZfk>Xo<s4+L&0Q2rD%!1S at Y;=Ca(i-mHg_Q7
z at r=jIQ<5FnD0uzd1)bwNI_KlR&J@=7=Fc7T9y6Z2hPf_c?`$6l_ShRu!&(%OozQ`>
z8%3w^+_Go*9bjYW#|vnbWOr;&ffSH0 at CjP;GV$VN@)N!ah$C)L at gtz{eKmsuAphPR
zt>FhWhZI&o_u{^+A^0(xM0Bt1L+C at xsej3ng(GFZbDks?epK^+6TftXkD717KSF46
z`Nu<n^i4Ll(>K`&;}`aAe}FzDAcoTZ)9x9&)pRND+;B0}i*I--9($v85j2YYtY#5J
z!zgeqt{DxZ;O35d58rA{tZnt at jP)MxM}LyflDosF)ii})jj(6^tbgNXyml;<y+=$q
zF3R?&_6J%M`E?A>h96pNgfG$`j*ID&)KY9Q24}-Bvk^Y{rTJiQf at wxN(AjKM3cY!`
zA!4Y*fJe0lO)nS&3mW1L(IkU7W`c)U{&|LX3ETt3{py}OxW9jL4&Zz at _H!MXa{>%N
zgfTQ}d5QX}|8B(4MDR7dr#?8r?)U&-;G^Vv@|&1*4zoVN6?g-e;8*ZYd?fy at IiVxc
zd-4H!f}FiK_)!B@&Og=yvtF3BMApQ;hIW0u!hO{RY(3K6L){K}p0B6Zb=}@ufvD$Q
z!`EK=9 at +P7^0T%XPw}P2*wOV&Hu&{GLp~rb at k=)N*=M0;5ij^P_ at 3Z*;tC(9e}8`U
zTE!{xi(iTN at TsnkMnwHldOrP`dHk-gfB)(hjs9r%&l-B52EL;=_Io2fp0=Oh|Gb2)
z5&sVZ*@T}xt^Z#I4+Ro^onKps>(|$zAJ at rc<Y(1HjzC$Ffh5v_MnIF0Ak0ErpvVSM
z^nLg0$rJ at qT)N at U1VciBFeD9xfyD4Ci3P+$K;A4diN;?9e1J)12^V672+;)ICt~v7
zMM7SZ_}wKsuMn{*ilX@!*@xH!IVCt+Lnmh^Xcnl|C at g}LqBDdC)ZVdyvD at e08~xsf
z*A;6lxEUILTG00BJ%ebLKn_N*%Pi7e at TG4J7j#izNC*&k3Y9Dts#ud?yp)0<d_IRg
zucwhBp_d4e;P5q#KSQ4!0OZhz&tm|f<2f$|KOss#jqBR~@QdO-#i?<Cf~S%WVBJr<
z&>T_F4n(mFW^)3bw7`vy`E(l~-1_;1fs7yjo}bwle!q?xJ_35*-(Wez;rJ7D|AWqr
zz~oHl6c~If{+)62p}^Pd_gZ*cYYp9reWcCsMb{sIfAO~)L2FSIwlow~#6}abaWo23
zicuG!;vXDjSY^IGK%qzBMbT7x^*-?yxRB!Wcj>s`aTQW;7w*$_@(GHPt-$q3%5eNm
zYB0Dj!v+vVmZ8{T0Cu;4ezMktnntGZ)nov)@#R4KB6$;sfodS5NE=Y|LBS at QfE+qx
zEE(9%jR<fv0wT^FYt?`p2W&I$&SLL6EOA*lJMIj=9|MuTp3xLVGo(G#UiyGw?4O2A
zHi0uS9FVPSyO+qGIT%PgV{dG4KTsIs8!-K~;?;%pU;2=uEqsXonh&|3eHMNTf7S4l
zb!xrcSK%jt{S6;!?`Qsrp^<QA$3G<Olj)b~8wLXrvlX|CkA&Sv5zmJ9j~$j_LHQ~<
zp938GY4;V#Ce^;W?6ZmKUwj?D+x at 5eWwY;we~r1wTje|Z&%Wz9tjE>xSK0Io5i6Cu
zJ2IDjH{d*fhLN`ley<-hhj<{beYj^09sAl=|CjG$kLh!o3;X)gKqv+g5eGF4YQFX0
z!9MH*hZr`*py3yxxo9t1e4n3qN~>wK(QmXon&fJnsZG#(>Ju7p*C^zMq31)(Q^$vf
z5B<*d9J$nS<Q|%z`^W(k*W}vNMdS=}M+~ZJNHX>#u+AJ9<od}|V_&s5>h7Mm-cfst
zrciiu<fhz<YjA9g%|n;O=g1ww;fz&$X}%6#1_zT%OD$4$$EY!?E;y@)6Yg0Ow|hY0
z{)lhc2FCB%7sc20{aM3&$W~4I;rBw_-+ff{Qrntc=RB^}G_GfeCv0OojhLudz^>>U
zc82fRJvpAd&Ic6K)%gV9^-9O^CH1uYm=7VgZ&E9+PJLMG;!p3g7Pb$Metf=;Uk3nw
z+JCzz{@V~B2LZ-~hQBq=v%&7o{%rWc|6zRat2e_3692yqem_6^%ESi?+cBrt{vhk<
z>%NRJC}?~4ljenp9XBAQF$!@Zi|<C#Xb#iiz1V)59Q|}iifD^0Q8+1?MS(4nz7#<g
zxhQZbTp`_?L_SDJG5pRDS_zK?=)EPb at A_pvIeRNl{6*$?;vb at uPk%|Ui2O@*ZSE1x
ze+duwCuuy>#BB-Ffi(+B5g9TI$EL2x4X$gr+ at J;4b2CZKYe#~_cGo;T!Je#@HOJb8
z5CQGQg%Ep-f|USm;HfwJ-|@E({?kP~u3<^CfTAQofg;GpQ3T80FRlVKlW!Hk6g%=Y
z{-KbKq~$~vNy-W8S66RCoS1q?BQ=u}$OQY_NI(pKLa=n+8;S?7m1x1I;DPS at lD|(L
zur?P`6i~hB4SNdMx7&Mg!Oeb$eOCTE__Cv&2d^ep{~FN at X)RgEO at ***@rzvXxK
zXW(Oew`1|;349#q`&#Bw*v|H24O$Cpa{+32{p`g>-E~E&5y!Rj`!!e2Pp*5fv3~I}
zp4N(s=Anm8uUPn31(SI52A(WY at JUnP6h#sm1IN&!ktmsl8}%8-aBM*5Mbob91St3#
zxW^^%xzEXKBv?<biTfx~3zyeb0|kRZ4J_~1v2_ja0dQ^aV-&5Ruit|Ro&+d%v7d(z
z4B)V>o7RX!#XTDEl4^ADhnt*;OZ2&76VAmqbl{qNJK}WkEIDxG*g2POhveG!6nf(r
zT%WPE#gEqh0{->+#x?dxZadRG?1Fu;6Z}I1vD-aANMK6_nfC}W%n9VNXSRjUZYH_k
zP3;UE+aspK&cdmk&+Ruf5}<DlUH5j4Jfb&`>u0-$g8g2BTF2Qs at pJca_;>i2`Xp-<
z{A|4&dSW==;q!sCZ3jg%=<oUX%$Ieox^CCm!TZMfeQ35f_mNA=2Das_QK}XZ80JS2
zUWIs~HC2M^yt5iGK#f?n;?h`wvl^2|NX^sQ7#Z!jb{*HETz~vyX4^VOEefI at t(r9I
z(FFU4JJ`jx%5MbC__n|8YkcG(UgQkLmK!NFE*dFmAlewZOY>aA-Wcviee%1gUHCln
z0h;-X(n at J$)hN**6T6C8^kNKvbbk+kUMOuja;I}p#|Rvo>s~b|h8|-N%6rlf4+yB4
z&~x-1&5wMd{XC%k at V~D0K|rs)sLRPC<cr7;$_slP9(!wbI5EK5Q{Ri<su}Qwwc8p3
zhm*Urw!Xw$!$X09f9JEa_X at twxTfz>{ONT&F~wlwlFo#_s7`i_2FDuDB9=>Eh;jH9
zd1R|q;J~O=!f!R~@o=YVl^E*aJJ$^Ou;Gxm2mktj=BJgL$rqU`c0aM+)FErn)+@;#
zp~+2mmY&EqHDu=)0Q}L%zd640|6lcb`P=+L3<SX0FhKavpbr5){Eg!f;H1enve7rP
z>CWbS#s4?(<-q at E;41~ae*c%R{@-VKpYfo67kJH2BYxko-6QWkk!z|U!!j&r at ZJjl
z;X_|-`%Zg|Zx at uk_%nw5Mn&2*zICzL8=r)q<TL#D--JKrPdPsMt*bwg$p80Gedp at W
zB<6oE!RFs{fGp48sgHsk(g)#1_7 at I;%>o87q`-lkZ?qtl7`>~+2t0tW_U2Eb^=6Tu
z=J9nR_dPlvaebAp_lhES3TqZaG^X79`4ZJAhAIe`<Xfa)o16-Q at w1~HQ|CRaUrShu
z#v$M;3J`dNo+2#*unBh+j at ajw+RLjX-s~%iK<&|mBQ^uC=fBV-$OQ}gn+W`dSLm34
zK7YA>9-!;I%uoUP(!kFLUecj;ASkb=38?$}-U<1IHPkxrQwS2irHPUMBH_ at 8$e;Hs
zVd86i924~NIj?!2&q+F*hq!S)?t$ND(wRQDzp*oR_t*aM(=#N<nRr$)L&%QFXGbN6
z>)xxxF^4{R-6&iwoONH|W;YTC#a<+g<kG?)xC3vi=*&S2yvc&UHymzs;Y>6g at Fuw9
zrb7IYpNScB=nOO^ZbaZ6*NEaJKoj!QxEJ>vsAdE|MEsFp3hVFl7!VB%>p$VX_i*5S
zaSfiGam<bK+r_g${T|J(FcPKC<r-WMPI2wnv+kMuoO|;g()Qw+VwgA{#Xd>2inEAu
zfdoH?V- at RV5AQekI`<jA(OM#&6+_+|>(03OP3WQHg#wLXX^$PpPZXpSZi+SH$TqMY
zuva3BhwBhU219}cI+yEgIJ>s at k%dd at 0~&4(vHjuR$~oDm^R4kL{V{!#NP8Rh!H({e
ziOJW_$(NsS(t11^cytkHFYIgAKM;0ob_+Wh7wp9~;3#}RcO3(vf2?D~<g||qa1gl<
zJtY4~Psn at DQO<SN#whe!)9-=!lMWi0+P5^9Rp=Q!(K31=J_>fhjprHm=FbhFf9 at F9
z)jejDkoO<!>T4bPjc%uQyXX&4;G*53-{%^BC+O$*;d0v6IpZ4p)*eRVQ(*7AojUll
zDL2=>VfUXSo_#xX{MVxOx6FSP$geT?|3Tyt`uT|Xxk0t!wOEel8i{%BMBH=ynXA7p
zJ=f`{wcZnZ-1i^c2rg{H0({)^Gd_yiRk at fPO#UTaXtIeTnrbwFm?Qp(N#Ybu^+OBm
z?>m2y^(t{q3`ec1b0W78ueuJg8iTviFEl9{F>-y>i+O+7ss_K0y3(i`AqE4wj<w8r
z#&rSrb{<8i*aPcBci0DOW)MJ5 at xvD$!m%&jk6fZ0ghp{*=1%k|H5+XV9SRMa`^rH^
zt{dHnI-A-V-KilLw!bvcU1H}1`|*2imCg99t*~R-EgxWw0gBcf^^|;ry=MKPM!a-4
zbY8YYkKK?15BuGiPwc;U<T;!VM^fVj=R(!u9s;Lrl?O}XBmae;%f at i0G#)!g?R%}Q
zFFg1H(x=d-s$s27L!UZYEqura4bRuTZ~Zp~^dH3#K+S)^!+?_kfUz~C3;^ag0Mz^g
zH~xj=6Mh=xtzj1Cllj?fj|N|$F%K*aJB_ at 5($Hs9|Nqj at hl;#L!Pi~xDYW&>VL=WI
za%jM?V(tUXfd+d`>^8_@!HSDRg3TBBCk6!aA3nvub1?AjWiarU65mIP2#*nI9xIYX
z5K0svu7i)jgXFIk;qRufQXoX3AAyxY<KoE$)Luj}Ac+57QpdhIp!0#Q at kZed3bvPq
z07{e<Y*Bc2RFM0%8>Xdc8prE=u2D!~$R?P3aZm2eI%d!x!J5Y&1b!byp!ZXI>d5{5
zO3l3*ec|N;)!geRjlVw!uPnUE&{|)mb-r47%};)H^%`9dyjHl|KXq?#PvBp#UZ*v_
z?q|O~;2ks^3zRhYT3kcESD#mN@^-;ZgZGBr at KxAWHh--^lA&3GBNXKn>F|a@${6y9
zQx?Bb+<xWzS=>IDqKC*?;AqrWL2F`mCTJ48 at tNRa!ayWlSUkDz)rA(}MTB!mro<$H
z&f!re_#6}|nJX?B5=AnvriA!l$n{FuAd(ZwK?xm>nwQal$Zpwyq%AwYu=9P at 7{`-g
zn!|>-(<l}=uE*EC5npSJ-6?|GbsfjD<JfD<^|6Lr=V(|3&g=2bK9eVD19ZbYanp$H
zup>=hZ-}t>XoR)|X|9+r=1fnF2h``g->1*B5aFItU}_Ec8UA+tBjKYrQKW^<%3q3^
z2i)jWlnEI}v)IHQoQEyoh6 at L-O}u2`kj0rB<S0Br6lw+5S6GTpicKE_IEN=zIv?A5
zsF}@l-Y*(y`63EYHLKCMYHhFOskgaXL&ea};_pqg69gaodk>MD4;QJ&tU2>l&pmxV
zxu;`c7%@Q%2+92(o113pvxte>D>lQ1*faT`8kyYxNoWbaT8i+m{&Vp1Y1Ty*e()F_
z8#*V=a}$5oY(|4A>`#Ml+h7{i*e!_WZ#JD1y&2Wd!@09j9H{%`z1Id3WD~hIk^%Np
zhz7dt73_BSL%`R53~2Wc)Vjj1VB5#U-1BY=+i^D8y$RP(n)3_T|L3SbKZ9z)YjJjt
zuwNS-)-cw}KS*7C*!Fk)cdDlScAt4Lki&t>?E=FfVt`l}+D#KF-L__<nemltX)19>
zV^8iS#)(DZ_bg_4-!;zAX`M&@UK;4iTUp;^jRTIu&eYk|TBC-SIzKfx2bVPeXm03j
zs}s8JM2^u~{Qz!!3)e#cp+AgU_agnFCf4=m5PjBa<bW7>phvNnTz?<bl0U!;3jQ7B
z1G7E9tozNqX2YCyk^G|duvgdR)@CDWBVip<mv(DkoM%7vz2U1Iyl%tk<}>?i$+I5D
z)<DFy>UaQ2v#z?3TEX7{nhpD`NetH}*|evA8~LZGb8wqY{8sPY7;Bvyzq|hRL$Eds
z0KHCrf$H5`fAXpCM05DZpDakkd7}JBV<@18vf;k~3CBJNh;IQ1%OIe>2{48L#@5`9
zr{vqW0DzyeyK(N#v>WZ&bY}y891uJN?ANI4=JmgFc;BBL(bstyeP0uO{{r at Cwh5H&
zx;<_0{D%?K7pH>)`Em{l>Kg>&K>r58Ur3Z06#Ny#0+H#_BI{p^+>aIUAEy9#yc)SD
zC_tX1fO)C{=cx*$zf(XxU4iw?@BH}cnF_dPEAXDH0DPVT@%akM=PO8GpkRHW at FL;G
z3f{XUws$FzJMt;_zg)dULEeF|t;lA7fy4n}1&BG#>T9DBsmW-GVF;oS-&82kc<B%f
z3uB4~g7+i|!V?Ad`~($ij|Z~B<0TA#D|-ZFo4+Ywr!)BT_?o}Yu`M4jk>R>wQ{Csu
zvg=c@>o<NFwtbpxJM619foFw{|L at ht|M=6Z=W9>T*WS9F!`5N%_ALS->?kolK(-wA
zMR3cm*ff$P=r$ED+0#kpMFI)L4G#OJ at k`<TK{Vgd01okO0(^>ooS^f#hMRb<%k`sS
z8Vyn=u}ofCS0%2Ok~DzU|4Q+c{lxynolMj<RFZ9$W~dT&Gz&D!QD77(I7revct23D
z`#Azb7;s;~zjyevffy2~5mDjb^%(aGeQ?FvqZtwyj at jQaMAKf!fG2#4KLyz)d?}mF
zAy4|TC(ra<Ht^BBgG!7~elQzzC&Av>>`&DG2DBpaPQkfc<8R}-bq|uFbc{84DByw;
zzQ7Uo1t-`q8Ufd_4|c=0`0IZ85a289%V)$9#}W(hA6sFkd>T-;(S6`;4mD=c&}|aQ
zx(eX5iJLw at z1^PTp1|k$DO>J6!9C_+Y!)qEkBe*ub*#0=RTM|%>x`)uR~1`;JqIYX
zfb<ifqlVw(^C&Xw+!gKGy3g~fP$Q-dYe%jvVGRJ!^y|_Ue)_XKZ|Vfd{p6Y`7U8=G
ze#C+YLg=EK3^)K6;KaLl>L?J~3<ZcaVrz2ar@;+uz`nRQ>%!)P4-|&PhWv)V;jwug
zO=&$rrulS}^+-_7S2mX4s%G-oQ1<5Tv^f<1jGw9({_G)u^8$5^<@b(lEugP+!Payp
zzE!9uRIhszy5LhCWv{Z`L&3O)>Za5C2{gq#H8=hejJ40F?R{^jdlz;)fxUS@*tg^C
z_znB@&(;xW>+SnF41r|pX)|%v1CucfNG at MD#7Rw?T82KNUkrDxTj(iTMQjsKL&u3-
z)gaU)G>O!K)G^NC#O at gMk-H;*7b2hj>&T}ghw7ZnpP56+pMIFN)=!yJ`+FP{52Jeh
z0JH|KAM4P)qYmI94SJ$RKZeZJ{J-bdH3TT+ARzU|wF7%OUvoCnUUOf2#~Av8!&=w%
z0&L{^BkXu$zrGIcne~Qi^K9VBn>6j at -%(>klfKp$_<B4 at YPr<<NnVSG1BUc;Z@>ql
zCfI%_PsUH)tJi184$SLk!%t54LyBCF^Q_U=d_e7sT-?Eajs3HZw8_yf#$B at Gtw(<T
zyV2l1LZI2B>HD)!|NYgUDo|+z=WyU#(Iozn0(>6~jDY}<z;}2sFa`vm4+)}4oz3du
zn*)Wj_YN3;W&qZv_=uYvvtkS?7SMz at RAcUDJ)ma3H}W+0=MDc&kmvV-0GLC8xwduv
z+OKS68`|do>7!s95a7r1E#C@>VUYYjh6LgSgCqFyr{c<=i8FsL?!ce;FC at jK7#c{Z
z`Gx_5gGULERv<hEh<qL*jD}cbHKHL_A at sOttQ!>Y*MZ{`)rk9=?LL5evxdhgAdN>U
zU>~I*X05~oYiH=;*chmNvfl%UogLW6*goU<K%IYPzrWI2SkI%r at Q*QkVXd}Z3=p(e
z_8tQXiQ<zakjub81 at zM;pgAn~$<?zYstgOBBY}P1J|s|KI)*PQRA2IgUtGOZ&EU%<
z(({`Pzr1>d62mLOPktrj&sTLw+yn8spkp})_!=)0xHj-$$M=4*z*+$7>hR#fxQBs6
z4JMWWkggvIm&7K#kt9vx)4D(;Gm;TWNg$DRytNWm{3Ma;=WBF4c(u+oyw})c?T!0z
zPZt1Q6YI=DR3DuD{OZ-C$zJga;pJ|;0}LisybP!*VQ>+H7K0`|1}>RIW9Xu0gN7!W
zs at 6=od5T6!9HQBKx;V8r?@k~w)m9vn at JM{e27WfDy=m#lCu{i>$T)q<w!lqK6^ur^
z#(tmibyL<h8s91!wJ-Kba~Mq@#Uf3=Y>GeN6h%r5cPL_1&;a-Whwv%>b2Ep1pC_AA
zpirEUgt<@JDjPY58>fvN1u at 0(D3oa|vUu*r^nBt9-0*DRIGPO~*UtAf`+fYhH4E})
z-&$X{=Z+k%tnlEWf91O)iumpK{&^zL%|XYG<2_l&8IH&1HMn;0)fh!x7I482b3|as
zNPGlORE*NN<8yNbEh5&@6*%$^72_1;6z&WI(HiuC*yni8gKKck&40w&#uwK5Sgjjd
z2Uip`+3+V<%#Ua+<@;zPmA4HyaeE`^CjCzv{=1<%?B5mrUWL96h7Mzhu&q1L_GR=v
z2S#%`8`Ee`_jnknM!v<x5oLGmub7FS?Y;0z$LTdzi~)jU-8fle#<j4;e&63saXfb&
zpq$!iU*o{p-q?TIq@(LghqdN*nzP1ri{lZ$`KKbpuQi^y at _?5(BiF^?QaLaOe13YZ
zcvc=o&l&oXml^yM+gV>^ULW-X=uI#=LbU?%e_u4=9^}_hKL-5*L*oU%ySiUG0p3|a
zH;e~bqrZdC`mw;*0QYlkgWrvldoJe{#%mqVI`hHBZ(~mkDcEl`_CWT)HqqEi>&TDT
zE^D29*ycKh8s#o(6xp4;88wM=C;HlJk+UY>zI7eqrrY&MXs2tE1^qo8*Eo}?Yw4O?
zw>Rw01)Wb(J1m3oIY>6YJj9M6xb|tT1*HFQj=GH+E+E at rpG2?yE+LN{b>M03*Xq7z
z<5%hZTTfLoqiLXdc$_x$SZ(gF)mYFVJyJ%Y0a*qF0?o^x3jbYA&7UZ!V at S{;v50{I
zkdRDd6ZuCC at qRn5pBt|wFp0c&HlGIfRwJr4OlWNZn$v7h|5U}}p9PLh7+^1fb{$_E
zcu%oTfoAx+0mwe=h{1-M?b9K~Hi-B?^!vr(!gzmTH23{=U3+czYdvj!quDQvhQIt|
ze{_3eBWyOBUg0l3D{d4=qIs1dN8_phGib1BU~>qN4LCdly*Y<}(X=b*|29CAtEOJu
zjHm7XslXfPzx#C at YvlPLuQ~BIx<2<?*3gi#knzy*XzhW$u%{dzbmV at GM*=nQ#1mi`
zLPO7IaSd$pU=BvWZj-<Ha;`P at uDubf;E58QC#%taN;LaFx+0eUPC@>31wGCFGbIE|
zvo8UTZ(gVXeUTcMyZCkmO?Wk~uaI!l%+lDtMuL9#&whP%&(D7oc%20Q^%DMo62Zi8
zuU at D3UiU8`kGn^>Tj#u1=f76h;abM4l`vmT6CFS6b=|W!)OpPD{WCCRc)1eJfcC<G
zA%+YBdt{iweqS8;dF=lMvIF+OE(}7RCp=doioKpCyFF7P8g`UDpCK?v`8xqSGhD&$
z;K|a@&`|j!d^7mB@^0subv8j<6d%l+7C(TP%AwFdTs=*^bwbL-2wHM1FoDkGI1}9=
zIqG^e$ZoD&WStdYpciV<w0B4w61{O3q#NU>u^%%~=j(d?UWc{RI?oD0_WY!>MI>zs
zK>3EmM`C`V{7DhQkcB3mV&x4Ch{QP$h2E^!yf+*D*|c$;XUNZP at +ls$Wi)JBTi8bX
zh^9c=>0&t>wbr1}tOztQ at dQpf+|ipMqc=;Ju%8px^G{Is1WV%tr2n&d+Mcdz{j(|P
zjmvCij?KW1Y!2KwWwX>?M{||f8;FimE~!CI+yQqs-i$vNk#9X9iYJQFRt9PChQS=1
zxTkm%jX(^ED2#t|^;Q+faEJlq-D)0a`YF=PABr%pn@{}zDejrEIXMIt9s${J<<j=_
zxO`~e4u2PRJ}tZ%4f at v;<M)Dpzb!bo&hO{e>%8CBmwWd$#kUSR*hkyb!c|aQ?ah7+
zz~Jh}&){D*@4=z2Ic4wL^2LBRhPCvIKz=-+9dil&dIj!rin{+rv^Ac- at 6Y=0!oI(Y
z=*R8YkGXI>_u2<@6PMmkjPvVWi`^o>rQNeB6qHxp*f~eKsYAob4>X#@JG#C%b<b6v
z?+x8(=4iB3E1(IZd6PDfSBUvnOCuN}F!+lH71E1<>J+r$jjCV#P-1@|5f2_{vID6r
z#vCNLF>k1*Jq7{{2x?I9?q6^406}o0&$)38n*3k<Chp4`SPN@%Ui6w-Kl at -m>?<B}
z2+{OM<Nx!kSE>1bB}32gFe4vW#DfaKgMb$c`Jm#*S1({F;HFje7Pe=&&I60*)<X+F
zxafFRVSjCK4%*ALhCg*5?)f6!Kbmr_iS?yFH(!Q7|0Oj29 at UkLKRXzL6yjk}`#G>3
zH{LsYUm(wPzT`u!8opdY`HF{9T$i=NMTT2%(H?HST*dQCR3zV}H(&7mpI<#sn|-zn
zK=J!`GRjkBpr^=KPn6LpZfQXNRzX7JG=~Kfk5*7+Q}ey6M at 5swPZhKc95V~wyvAsH
zbWJyZk8?9eQ7y0rifz{8hKKb%?K?k?wbJ-JLrw%yyo*>A^3T$K*weGs1U;wW*>ZBc
zAN!r)e6GcHxyMs<uO~?WDDYVi1wH$B0neVYK(9fG5Q7q+#PZ*jV3t9N3a38w$YBUW
zg at gwS|JU-`4SF`|`;+-OFqzG|2O_g!pG~?ObQ%rz5cV(Iv%hFGwcoV4>^*F)CaBrD
z+j_Bg*mv6cxzS+#ED#M>2aT8l3%s!5MQYY))bghqH*wT}uL(7Fr|&n2=yxetIksP8
zLEU4=3kT+!`Wkn59|MZ11M0K=+<srylzS6cJ54O0p>3eSeVGD#G{1`HS191YD}`v1
zX|&ahzoziopQ$-lgMPQf{T>>38h9Y#KS1wu44|oh4bU}c-nlOK;9lI9`;Vquu+78n
zVYj30 at O|gO at _R!x=h2{7?0)yB!Lw}C_qY{L#Z~y~W*rXGq=$})*VeLK&t_v at dR96X
zF|JsNp{U}9A(vxm#(c)T;rP$tVhv0cmmPl`C|yvY8ZlhjFbAa>>!}S>6XMUYfQsY}
z7p*R4qlp-(Vz&z4M|V_FJR7kK(3(%*KY_35d-P)4I27C}{IcNA0xyc=`g^x1;-pt@
z&=`ccNh8 at mhr}+wzd$^QWG;=T at OYKDMqxrCB_Z}C$?vaMg1lSFk>g1GFV?wShih_u
z?!~=X2Zbl=jP+|j>@yk+`Hd%Mqal-TdK2b`YcxebjnbbCe67&m6F&U)t3M8W?F94v
zKLO(!C)X)Na~4frZ^+h0Y#$c%2JCVZ2HcRgW=uBm6GcB&jGxh%&E{-r(u|Eq=56PZ
zIo|o>W-S|n<PJ^1fjf$SxI=OHJPJYz`-L|=1yr#oZe$U*6~6+-AKalp<Qxh}ib?px
zb)(TQ4smaW3^XS+E^yrIjyTo6Mhuoc0`(Ph>}b1An-|I#-B0%20{ivf11I<MI{LZ}
z-080adqaQZ%+8ZtUoLXO4fmoc{i*S)Ep7;{G1*A`P>l#pL^UZiD>N+v%?k~M0T%$g
z;^zwoj>oL;=kNY(2MyDUmG`)A{`Bi3+^B+Vw9e7jgoZvpF!vU4V+OQ;;^w)+bJUo*
z(K50LOWOrxN9_4@{ya>!{X5m0G~eSZ%Z74qA83PRs2#}0KHx^5IIo}U044`~6YU(G
z&$WUFhWOw?V4~Jk>w_Dtojsr-&nSL8v+X_j(YS$4v3>YK8iB^Vv<3z*SB*pN$$>#O
z&v&bSLU%kYKx?c&Z|;pB%{fiF>bbY6Ub~OxUA3Es0UijvvzmRH{s(?NhXcGnnt$MP
zh5LS)*ULdb4FiOGb<el_yshCHuvYM<fYxu+UUs0XXJGH3zwW?3#`$Nnncfit3;}zi
z<sM?-51Rk^ZOrsr#!|*hA5`FT`@eG at j!e!ce+J-_QSWg~45i?g`rxiXTssCC=9jp|
z;Dj|r-cp^+z=dH2g9`SA4a^w^)%fqdzxd77EsFBHDB5*U6!ALn|Do=^|1~R*D_{P*
z>lxdU709unX>vEA2~BKrlXH$j(U!+?JdP7QlAI)utz;!6l)xYX0?B~%)4A)rs_NOb
z_q)&O2Fbp2e^{UMhP|Iq&#JI$zYPO=|6Dc*T+nAx|C9{#gzkG>6Fe?KGm3QKQQ;AZ
zynu>zqkk6QI<EJ<F8no)#$#N at e|iX?6gpbpb3cwX)%p-0AJ?W3BA?L4K7lYvSg8Dx
zU>wF~F6L()tjl}%K0|~cKJJ%e->XAFaNMPXxx)<u#Ky~RU>wo`-U at V}H!E<gHBUN9
zkQ*Wb_uQg;Z_TENpEPQ0=DDjiLrR=mj7uc3#>vhlJj=!bUJvo9*L=@)alUcybhaVD
zz(XS2gY3VcIhS}qPEw5mYy|EzqQO$Q$4Jpu(4J_%6tJsdF*gAl1VZ42$eYkV56rKf
z?ho{_4bK~Eu$>FFPS!m`?5Fm|UY96alx+;zYS>QpoHbHp_ebS7oWsm->@!mXVe%Ux
z{nq{?;6M1YeJK6tW3M6Ng at qp(ujk)H`Bq2&&aZ2n2F9<ZgqsBmuqGqd2g=_%D*muX
z_G&-O_*4AER^^lCpX`dgeJ05#&XaR4-vsy-&9Av%hWJ0If&lR!!vFiLqW^$!g$hra
zeOIU$-4OR~`h91J`b$*QhL{grWULE%P`}zK)USEKUgMiv7f9H3j9(dn&n}?PW=~=h
z2aTz)4gs=xT?w<<Yhf<-QzQ#(BJF0`4*}#SI4;PeIJ={YFP#O&)_qxIRdMy0&e2Ja
zqE=@eMN||}pHjm6w75gUr{HkH8^y~zdjGZy2$JF_73;W<F&K{mmL$uZ^+cAnb#cZX
z!zLlbLZ~#crL*D*=1l18ES4htG70pVkpJu^E?vdf8|L3l_kO*-7REfxyIc$FOSCnQ
zW<c&|DeyLgToY|WxTR<d;Z|Jgq7BHV#TRUxwjNxuaLcEDGoGkm*BLE&5`}mc;0Suf
zV}#8bPku-7<aa3m#fM%v@|Vv)t?#*x>$#8O3NbafqGAkQGB+ZD^}rd{=q3>y&pqJ_
z?9uy`&lHEE8B&6N;*-(sE0oQ*L!HeMYu7Hv9$1`X$M`i!JJ&V%*CFg}AouFO3l4zs
zi;s5`JK7WZ!HdQX#qDbLfFas4mOPMRtpvTfqFm0|B7C1x?$}PKeVm^&ixZzv{2+!{
zuqiM7w#7s6rUZq7z!(T_&ECVehR(;15;GP=5>WgNQPrS$w;ld)<+J7ezYlVr<@{bB
zYu29FBYS1f>>WR`U=lu|y!>(5=VPi*uvg%9+wfW883dH<>SlyR)T`NSkp1PaoC7i5
zVhZFrabEZwK3;-~^W<Fb0T~C%9}8|8EKtpZ5dQdX#1s3lUi-Uz-|w3>1=@T@@k_OY
zIp$b2#iNILdM%zk2G7{1_Uxtrc?_;Cc=l1*&rN|D$C6(<hdP(wM4TUIOpc4DK;}K3
z<kJ|Cn5Qw|=0F$x?*^?oP^d8hbNmUQX(0U9H$mp!H)CC+F_8T0f_`wV at hmu&Hh^E|
z7{4rd!@juW*>kFui)$9^Gp<d7owMLv2CsBxoL`*h#2ey?n at EZ=#2R7_v1i01!Sz8Q
zV|_KP9rFiT+?yftLa(QymWuHz9xmhHM*Sq-7Dw at ms+-7H>>FRh9 at xph0HBb)PB$Ku
z6HxS009#~=ycEa?E{h%AjKH;Mkugi8JeUIIVT8R7fFisw#0o-%LVciprb8T!gnB(b
ztLqkMV;B0ohr?qYr{<C1MNo9Xq at ZkZByxUSBn^?%8Uq5KeO%xgix}Y}y6;($mT{gI
z81pHO&G=7<v<Q}HoD`<L)^|_px at kSJrUGL#M+cu3Jg at FUz%wRx;Y>=LTL_8xh+59}
zkj|K<0_T3c2!qf;<Xj^{T_s-d1QSuS{AV8V&mcm?Out$v#4i_Sf~G at 7<aSt!oI)2n
z9f!Mi?fcn(=b*5*P9yf at J+jvnZ~OBX9Q~iBAol!J7hCb9H-Y^ShrmyS1wSE{^ZK7n
z$kv5x`4x$R4d=jl#4lweNad3>f!qL+Lzi#5SwUl>ni1VUb><JzIDqd$@IAQo^ef3H
z0S>|4k5&^voQB`#x`Ov_|MVAIzoWqZX`y}<z-vAm&^285+Y0#H6PWvpAs at nz!k at yY
zrq?@zduM3lF0aLB at ynfj(>{rx$S(F1#V_oI-LM}`D(p$zyBnWT9CX7#i6VYA at UL#l
zaW<UM4Z^|ULq8ae0yhZ~oISq=xIBF-8U)cKaC1PMf at 9Sj*r_RSq0qTrh-N at E1lF1Y
zZVd4EbNRQR_eTG$kYfd6eCFytRS9Vn=i;*yQx at g7iPt125-Q253Z{GMin~yXBI%J)
zh*KCv68{JVkzzK9|5J*I2>dFPf1e`4#l+hKyr+<LAt6vSaW7*q9>qPyCdDO*pQKMQ
zN3q9R`PBh?a8lP<k&LS`g1{M~Nauo>ve43b)X%Gj_?M`jgmylaM~IjB?;_ozeIeX8
zKCAbO&r9I<*I?yW0Bb+b9#8*s4{Kt7JAsHGwD4OByb||<iy>^87)1;`kze>{yjj4^
zc at l;7y*z1iA(K4Oxw(iIN1mj3rf at Ef$fqfkM-xa~aM7uFL_y5oKh*o;$EQ_jQd}Zf
zKBB^r;s`Oq_=paQcz6nDSy$%=dtg74u&@1N6B;0sos6_$iSV*- at uzcW{7uvujk8*!
z?iI%Qb>y6d={y%}6ym9So$GX_<7`2m?Ks~B{3Jf@)6cyyidf*7flZ?!NP#^#F?bQh
zEhtgen?H^v;>msD3GpNZe(=R2Uz~ZA#-W8*aOVldcnf`<IUI7V5eJ at AK7dOAUJRix
zUJ-wYCl>m|A%sfC8Tj;j%A;^=2y7!_QoW8C6 at ZHc^Asdc|5$nSj}cJ?<y!D3!hb7B
zl>O-f2({(w5^(kTb{OOJIRxeeUW3-cx at w)Qc^-GC*o%FBM|Q$y*v}0D0lR)w;>~uJ
zz471P93b{1R^k^3A=)05Pm&)H(zAwuz?r)lfPfPh-~`+#^d^8sesU?q-4emKb;LD;
zi~c3T)F at z{5 at 2`dFG-4 at tnWVZozVGN%>ni{H3x#D*Z^B}jy_u)Ey#u+lReE<#lMNK
zkuOJMO6M>*Yu*;}tP-4Eo!>Y|pc<+gSj0__m**SJpw<v#{#?iG%=5efdtfiibH^vA
zrqI+FqAA2L{Hh_;Iba@$1MpyK3{6}xAM$MK{Oe4KGsGKWPsMfM{0}mw&13w8YJAcd
zU2Wvn`yO{2X7RXV+z<M=8KeEroRoJ#uBBqLV{oqD at iud9Zxr}H0yzD9@^~tAz6yg2
zfRf6r&{Gl_1*jGm#c7H at Eyjhb7D5s0pSNovlQ^10Qb&lTCYq`^*5dgaPt at ijs*5Q<
zebc6Z#T3v%8VK1Ys1AO$L{&av7a`)QdOV${urE<{*JyaWx^<t(h<JWTM75YoA at u|z
zU4);+xda9xL->fCrBLE(jua(A-D7bAG*&ea5Gl+>!-Bb4LkSfB+CahLjua+C%xhol
zlYL(!5mLefdt&oTRh)2EB`!)xaMqlAJu#ek5&x0FbBwQTovpw8Ukm(yLfF9k|BA4I
z{(n^v_AFipzS>?dvGTuS1Z#5{v99_5Z6WsJ|9B#MGit9B$`0WZh at cWylh_(QQNCb5
zcs_ifI1jhQ=i;z=o1874&P9Llb8u7VI=HE`4sPn~#m)Q01B-p0dgrfddQ%G?!Kvb;
zxu*n8<I3V20gYH!G7tQs3HYD;yHC6U-tj$dcqz#<#&a60^Y<C?pSjH4!YdNm$zwOb
zglK#fv{w8{{D$MpMjo68{WIWe4fY!Q1&lxTop5uE{R`oXg4Pe%%g1tGvA2M~*Z#VX
zj=gC=v5z;rhKIEt?C%Dfz`1ZfoKyKG=Xa~l at n-qwTEpO41!TBT%>p+H(r4W$0Ldpe
z-voRZzD<pSLdECg=8>S^V<evwZhqywQ(TX at UA(5LH5yvtH2a!8Ws^M~b77OBO>vCm
z{}I{mqp~Fh!lz{4Ps`R68^1 at fOkr6?W`g&8&i7nr0jK-8pK+?FVEiX_9?ZwQA@*N(
zfp8B+qRxSWtqOsqr~^~dPw@|A1H{oaMkM1BRb9*tL8drSqOAn?3<&WZG5u6OFn`}g
zAt*6eqOUL$ev5))Jgxsipo$3>6bO0jknj_UW+N~JT^Dk)CpPT at t_tTWmZM0fIF7=7
z5^lvA6~xII#F`6XL|Te{3d&Ea$fW=^XXLkV<Bt@}{v^c=e|gX6|3%-!FN)%iD_+1A
z#tWW=xELJKn$|>r6@}OVZj_y{8#bJH5q5shyx0*-PHbYv2axlw at nT+VCMV#zIWcj;
zd;s{w;DeAhS#o0V0(5Q&7WiPsj}-Z``%>haCygs5^zTo;6dpn#2#<_-6a0DHg5p)5
z^<4BLKq3we;V)iUP${NZOr?+tgwTO=#GWCJ5*EMWS%El3lk)eKS3n7Wi~o#gBgToR
z2<tyip<NtCkpJ0Rn<&A~b)Xsq;E#VMfv&L(<?$XvD~>Kd3)J;_Z(GlDO at F$w4z6LG
z5vQ?3+U9p;FE;{YM{J61u`@OwaT_t1LhuRY37?(L5%EtvKq$vqr|6g1b3AXNe~3Jg
z{tFH%FAcE=l8=GnX!12tJnrb<5A^$uiR%>$2j5pYzfEJSK!dCEK4WEXBorQ&hAAJw
zZh*!D{$QUlQdkfFC}8vOl_mOj^?E`d1LW8_C#bcsF4o67=R!Wfo@$RYe%bR*%^e!W
zcL~@I8_v%DE0djpIgsZuoqwF`GKM*}5$lY39CVWxWSpD}|0(_(8D~3s4E|N1#@%cj
zfN5RTG+^xy${t7U{-0mnI&%f%^Z%7--;K}S3nb#slxSNMcylo~7neiC4KW(xZ7$sA
zqRq_=B|nQcB|Zx_8K??e7qv1(6t&TWxIzbiAR7w^Xo}fun?OTg-y{<HXZ#{2h5ey#
zQse^)e(<BM+n+}O{AlY=ksUE`mx#Xv-*FA#KJJfkLePh3_}8r)H5c=SXb`^g!>wz-
z)CK<cyzWWlf5&^f=<k8{t9=iVFJKqjM|P_J=pZ8a+|PU?Y%7s`w$aZ(XH*zxhFBN=
z*S}2XyT+NFzDvNj&c)^XZBgSTSWD+rt$CA6vCn7*<o>te(X1KPIE0PO9R&z%Zy}`f
zxLU!5r}+px3woU$;*ay>Y;RZayF+Jxw}K*q5#jiNlHP+#fDb7VK7zPaVzj75Kr3mw
z*`%Taq5Z6qY2hOXRVCT&!1orh1r at ++f}J_Q<C^br8c#~jC9GKscvOP>QLW9wJpUqq
z3#|RY9|8$tfG}2(<zJu(?2)DgV9$Uin?*BFQsQZQ_YZ6pJ~biyB+x(W*OXtC|1oaZ
zJDMlM?t<4x6D9Y-KD~F@;mKDf+uL at wc{UML#Le*f+iCN%aoiiWe8cv#eZK#CYZk;_
zV-Nqjb&FyOK7SKFFYXX?XkNOZCr;t>@C%+*vjE>mh`V6`^4BNCf>nsG9d5w3`y&Q^
zck9ZWqhNvWc=-LT>l6>+_x12wV7;u{zfghW+7GsmX4Q{<=5PTU!=X>fHoqe~{VoM_
zihYXBDl-48K;g+}f1qNLYodrm!2N9NlZZIkm13RZ{TcD?X`SN}nx_hqM`c at z#s{-#
zL at ZEDR0DwGp^AmuvQRw4zwuXrM$tBkIoV=aARv0K2eOyNkZibFBrK6d1IQ%orb0tq
zxBSU;VLVyy0!-*@8%1g>Mu+Hf0lFwYl~0zUi-M{OtSUeQ6k%C(XHn*&6i~2Hyd at rx
z&3j=7EbJ-%DCWg`7pJ3WRB_4AG<AlYC1PMSiNqPsnltC@;Q)fdq6_{YUK)S?n}i7*
z;<MjJ{EKH?Z}AUrG#+C!5A(tm#3O4oN3>V$PyzzmVaMWu&tK<oFwdN`oHqa#jUnZY
z!wP at pW&TOVCg#85I6UIM8ne$aYYb>TZU}%}=Tt;i(Ww1sUv37NvyG4Dd~q>svTO#-
zx!8DUE;b%!bExx>!ruHV-YLG^tFyT;dA7kXo(#h)#T|1?XZqNRz#&FdBY^XNnx~II
zd;o3=h;!8xcn<EFf5E|M5WHy~6%ezZK-4OKR-<4*v99pj;$XzRg5sKT1{`*S;EfdL
z;_V-a%NE|rX9PDuZ1b7LcE(5qdx-9LJkIY4jA>|m&oi5MC&WG6O9O+k#=5dG;HH4q
zfUkK?LdESr`dO_d*1&k5*0{ETY=fOXh7Zb~*x15f_K#m?MeOF>9?=;-q&&jea at NF`
z5`pky2>tX?;P@?Wg}4jet;Oz$-%}io_?=LWER=sAF)BWH)Eo(#helgdfwkIaM(i#`
z{Bh$V!9K}V#Pq=APZO{WLU at Yv1#DNoR*2X?<$#_CcEV^>EZ#4#I~-!p`I-u~-o6L#
zDG at n*;sQ7XWS4=oTiLMeY8zwsb_UC{xq<%!OPymo-}rUl)C>ld<ExPxxnUCGfgWcS
zdkYzdNA6fdi`lc!-UaUY;&-=>I{klqb!);`wod==fnERos|j9zdFwR&Eu8vSUrzA4
zP at gsY<>GaJe*`#fG4He{trg_D&nQR`4&hj$Food86Jdnz?CEb8eT!c}$XNa9n4k3O
zKzs9`3Tqe9B1<o#mxc6IA|6G2fP!8SIqUURMqF3-)HpOJ7`FsJxGal()&ll_J{kZQ
zD|ug}wMN4upZ0^?8+&v^0BFyK_J1C5W1uw$@@Y9XGqMTO;a>+V(1rJrA<k;nY~ZsJ
z^o6``j?MAT&R;FW8aIVLdmU#k)S36Q#-7->#1ZG=C-(|E7C<UaZn3xzVSg8*N68Ek
z{ICj##}M)=1fEs`d<J2tWH<zQg3tJlYf6wK#<}-V#G}Tszy=!k0VT})RJ`1)d4_;C
zB%*l&t>k%Uf;AOxU%aMKH9_LpSbm;Z++RTG6_(%Cy>4<9EOrBjl-O at oG3RENin}3x
zl?-T}U|&Be7qIuW3i99 at 1@=i0gYc)}H~GGNteSZS_X><tV>1t^hD`}t&h?Pi=LUn;
zjy>;|jqj0AaRY%Sht8zVnKR?;+%V9Yenf at Tb2JAQ;B(HL^M)HV2_AXrjd8yB>ufns
z&XPHqyX?i9Y$p{%H>w!ALF=vcyFpmCqG at 2TUm6J6MA#0xhI<N(QTAcnngjd5`LYq`
z7Iw-esMgBa+Yhjn_JOU~Q`sw;T+w7<|8BBmgQeRGVfP0rI{EwiK!xb<RbiQhEd}*&
z3!g&Z$)2CkSQO$eGF at oCvGttr5zR?q|ICX~=(}kkKYCK at dO~=-6`)as1`raD&`i)d
z07ORNK}2H;$6pCF7D99g8Ibd`2Jong<1U&F)-G7wXfID`Ur+NiE%#|*qrF?$$PUkm
zYb9oEBLRCY at o^RFGw at mazU~b>ceL>vIETXYdES#_*1VkICv}z<4m>^786zZyU=k1D
z#UK7OgwP+S00|ND3yF}Qn=4!oN6Zb4$vn?Ve87XJ^4zf}w&n~Fm-mR%6r>cM6q*#4
z6x$SwRUBGGs2D^DN7474)h0j{X!R8S08ozU!n}U*F&F*?iF)Oz=|2Y9!9VxN at 7i_7
ztSJx}4T1VAY%~Shnq7$IUIJCn_J&myz(ed%D5rg at c%DSfBxFLsEW`>zMfUE(<Sw0q
z1%l$u)O?C&KyL^HLM(1J2f|Owx5B at sW&nmjdA~vTFZ);mAzE=@^0|fYE&Z>2u>4T)
zlkN1!nIC3T0nT^6!*#^C1-wvka5M%Q*WtYz0dQX5b8W=Pd7Q*|0KTvt>|bsc<b9t1
zZH>qLn`=Py|B1xE*OBuRr at 3e5cZX@%VrR!z&PnIRIdZO?wS}Qj;;%%W{ZSl(S6#4$
zxStxc;h*87<)`*lU at oUX8@@aD;dh7S7=b<ys5KO7ZQY-|ZhUGDB}8Xn&xy3d5 at n;E
zPy)DP*-)Ni<ulGjD51TCeIMuy-z%!|(cky)w+GFDwa+I+!(e^PTR^VA_EY-}J}!~=
zOIt4O?X&T@=?wFHE2k9d!NIj)@U-(Tp7w9sI3TWP{;3>vkJja1000E^tQnBve-iz3
zp?}I>eo5f(m$y#-3-Bf3i}|-+3x9qj_~)&Y606_WST(lh2B+vX>p1nVKsF9q(;%7`
zUzzVqV6Wrpa%&Ql=p5par{E<XQ~1usqy8$<mVi883A98tBGSJ)knux+3p%KabZ{3V
z&~>Q$g-hk=m+G+nG)^R_213D4_bmDakqJ~Y;BfHu{&m2FKK6j-WNtSS44MhiP+*OK
z^%^3dn+qM<6Z at K)4Y}8RP2-`O4+!kSy!n6)18zWoY(Ttc)cLfrE%bA4i+!I_t(m>W
ze%;KGZLr}G{7OCupqmheN>H~UbiR`UM at b%G^Qa2h#}PA1d>{GAJ6j)DaSA at B#EG!s
z^Cy)M5sHr}8FJ745=Ar&?$$VWNHig`5mL;7xC){7(hzzf@?MmH{oxRJZXhWzEgMHi
zgt{kT(X8=86n2E5WZn|uh(zpC!n1?V<GT=~g=yU(NG;rRE!f-5Eg?7=&9&m<;NFsN
z_Ol82UHD$d@>;#NPtxd#al2nG8+!N at Ys5CyJg^{^2<MDS1ap2NeqVKi<^dHu52 at HQ
zH+1ftfA9m5`_9%!Ra|}aji3839C=oSQ|AfyJ)F$}1hktzK;y%iJH^3j&cMk-;?AvF
zhxtRZz#Izr*F*{PDLGXrZXGG=KE^7H27zoslYqZ&?f|U^JF!023D2Wxkc}tp;SLpo
zchbZX+-%VvX}GXw_D<vL{_nqTzrnWtRfTM`2AXF6Wrytdu>7s?h-?~o!^P<wS+M4N
z{>JNUF68H%@B3#R^Y1^Ya~)W|Pn76ghl*+n>lGjz+zeS at yU)j1{9TO8^<5m4AlQV2
z27+S+2#4Q8kRS^5dcyMB_}tgl--H`KZUTk40B#Cd?4;me3`B?4<EM=RcEsi(_}_@;
zkNAQpvtSdiXr{Q4BR(QJ?rox at 3l56LD(<RiE0NKE1rQ=)D$JI}SQTGG_!ki5!c6oh
z5caeGwu3Qm0F2kZb}stoSj;Q90iZQm{DWL;i2s#e19-1loGM0^AXyU`H<dV$?OZI&
zjy#p?g1<z63I973PwtfcC*l9%_yxcOz31oOiYXJ~J!j~1Owc5lUzez{#%DPuW7iz-
z7HupyC^Y}FK at m-fXh>A!!3_m|@-ALJ>4ri63PHSuzix;rR*dF=d=YVvf8Ymym<@nG
zq8ZQ{0)GH3%75-_?PvCrLi+H`x5JkV`IYBLf2(=iY)j!^^KlK=4<A%KVa=?aJ<#xY
zMtgc%dn at 5jlcgGOG;QvajeG_=@1^L6H;AtiRwbtFi^|jCi<5XNaa}@xF7PKGttYWG
zx&qq^soCec4vZ(aiTT(&A=iRWb$ns+v0n{BJeE!Dx8u9%{f<bR_QpiVXiOB`kXWM5
zDbC8^>=G3}mgw<hC-jB|ai_m7&U9GBi%<TQz$_*O=eCbW!Oxk`6KB%b4e at vtd7a}E
z_jwHc)p*3YYIfbJIg9(|KXEeGX&=a3M026`kF9K5*`IT&v!A#hyfeqe-+MI1QT-_`
z;ukTDDBdmbM7;~=`bB^n0-!YoMl%3$-WvdmCcsIn2=Ra7pXqgB^}0Fc4T7mT;O0a%
z1O{Twv*tkC8yLSL$o)riAQ}X264*w|C(PL-kl+N-AecmKH3q6VuvZDT3(npUu;|bM
z_9nm;I%EqE9oAKdC7$9ToJ5FgMGSDA$TBO+MWE~dMFl=j2SqFw{36<oBH9chAh;>9
z at qOWIfbk~8925HdtcP`7lR}R*vv&4SjfuI)`>vZH`?Y`UfDpR~V4t)VVs0Oh{oF_Z
z*mE0nk>64GkH(Cgp`QV3sAkL%eLOwZKHLD%Ua<*61_5)s68K#R6p4}t5F1L^k0J7u
z{GR0};SzQqQ*s2nenyG*i68%)ui;wmxi=dCCH@)rW(5n*23wa+Cwoq|gdfF~sgV<V
zU at sQUiHp;=>@|>fE?fVySRE&AT%0#1fnH}?XI8#4nn56a$qk+Ku|oOX98<$??fZT|
zh-Oia&)=N8nnlH%?zh+v`?`6T{%Wr1Z1BzUL;P-VMQ3ZSAY$`L_`}&0 at KbOVP4I)p
z(Q_));0u3w|E!9!XI^`2>uFu{r1(RV$<2Y6f9f&dQi)!K at x2nrZYl}PiJ*q7)g(Z4
z-)f#kli()c7%=(w+^4f~)0#Ktp}AOyICW)mvwS`LeZt`DVPGy}+qCa{N1LCuv~?}v
zGt9rB1jrnf{40TXWMT&-`Gk}HC<H=mc5FPg<VjcofvR(R2=J6F at i4`62T#!?B)}sJ
zJi78(VR=2*g2%+05+wsXwUa=3@`tZ&J*7gPVxFQNJj*XE5Zb~=#L4G);#WWfh_4?L
zqM;&Tunpid*L)1|uItAb0^@p)6cZ&V5KXL&HL`B+OE$u8CGN4i&qHU!8B){@fgxTW
z5~mTURa{XxE{m&!Dq1JOkGQDfsux%(4iwu8_2k730L7D~2(Jdfc1?hFY+kc5u24_-
zhsba1q7bZgU&DX2kpFmL?yZV__FaWI1+|}O$wpN?yEsidVo&Tk3T1pk_I7c+;QrwI
z2G_SizYgRWpvH`I4qqGohcBjovL<}kMYhj>QD_5k!4Mzd#I4#RfEzBps{lVj_=%xF
z6X{lsS0ba^%;G}p@;bHVVIS?&O#<<`erfO&za&V1t6$DkW0A(!@9^|qBHT?eiT7xv
z(E#}Q*6-5{I1Jn{@ZV at 4Ao?x*OYArBIoB{Y%>|kVpH>e0ZLOgi0Qfv>#Ba-A>latV
z8DdxW(-KGJqvKqB9+LpNNj^IBPk?{gM-#(Ow`&AUe%rAw>iIkWJboS1zvu7Tm^oL?
zzd#88h$j=Kb%&Unqkj*^c*LZNOWUHalfNB(-G{^S-h#ec&dKM?&$hv6h7_7zs-dy8
zOEf4t8V?-Drl!NJvCta?;uXGLaV`8a#lQVi+{{?kee|Ks$M|XF&CHhqTqi%_w{X8e
zlg}WJ{V at E3oXT}vPoAxuMjjq{P4h4x^D;kcah!8}i at 0W=(fWtKw0stR^4+Zmzxso%
zqbPDIdMSj at R>6Fh8v<Xq&@JJ+Yz82lX$Gt}0z!mGBOt|j6YU}NL+l&*{)Bgl7-I>I
z-<k&-&4Jz^nEi8vTz at tPPIIFp_SqW*06SEZApV&_HckBNfocqd9XA>Sva`j7k}*KU
z4q+kZxTqQdJcZXGQM^{MYVofCc#RIW1poC4kcd$VcR%S98E#Qge~1EK0o4V+3jaGq
zoV&goV!%%h5eJ9_k?lSa?>-UmegQEG9^`3bK|%W=C7A~|z;_6b{=PxUsm5dM`!pAG
zB9td#^4iv&TH75WHS4 at h>t)^X1d}J=Ay6z%1UD?S-x~z>e(+y}v;{UPTsuQFN#>sg
z>UxhMr*Shw<K7 at ga$_WI%35y2rfE;sY+GtS*bX~kheuzLC{x0FLW%EbCBbJU+&-ej
z_?(g{f1goud{POTYaUTj#7?sYfb75=oZrow(|guhSQqQ$>=9mY0g+|#55yCM61?f6
zA3k054<N)iJSz<0EmX5)CcxLASkZCb22!Zk-)(^}r0`DP=;&g-aQ49T&r7xi*A)2g
zT8#J8c*{AbCV+sCYCnedUA8G-?fyzrC7MR%vneEXKG6(Ff7KbnTX;1%C9ZSk_yOmS
zKbHT&r$;329}`y|m*9s}GzgwnVfD=GZ<|Z2(06c;YvCIAaX*}6tVhK=1XlQH@=r0q
zF#(?x;J5t|UlbR+A68SU8U*2QGzNa)_~eFwfDNKKmHb?Av>H+~j$+r&Pr;2o(9WT-
z!B0@<Hc;mom|m}4dxWTY+Pw7?ql$}Jfzd${7W{-l_UVO(L9#ZKxRty^d?=A4vPzhw
zcqjo;O^(7^lfw-Sjei&7N9RXz9j`;E4NycFQG^fZ>=9M>iU)HMmtu?p9w>f2)S3|#
zERVQwdDWc1ReXX|#<wQiIuNnHP~0=L2Im5;$9X{O?Tsp8I{r3z_|M71<lq!1;ol3%
zzle?e_j1fTagB2tf<ic`dwL;BaXBx-Tk)!~syOaX6qgNw!j(XC8q4=<$ZOWd^3zF+
zlBKAx;yDXt_TXZ8;^}xwChoyI^DX&hK|d>g<Lv9)<GibRq(W6OWE8*@uvyH~G<tFr
zx$EG2 at C2v=coe|_=73Lbb|D_cIdf0zDPHzwPcMw`5Qd->O5o#f_CIVOtcuHo1!iH!
z3!b{glef;15F?v{1YY at xUCuF`MXp2ZapOSi>rIwA5B#*B#{+pD*aaJv{i|754YOwy
z`=3<~aDz_y;A6 at QALrLH!Y7q4`mcaKrF>&C&tHW70-pl at e!AzA!Y2^_8jptFN3)T~
zeAU2vCL4IHi?gmXhC3EH{4yucm3{Sdb#q7O>NrIllRf&`_VbM=r&A*bZdXHQ#M*Z5
z{rn?F&ttY<=Q$k->RgxTd>SY|7$H_?e4+6u6t6&uf3Pb29gjMuxHOMZAY#afC5awi
z>h-T286*3=M#i(g&WdgEdS#D&{|g%ppR_IU!H9#{pL5~NhX276VxhQGz6ZygGt>9r
zqJ2;3v2gfb`rs4kgHM+awq`lLh+h<VKL`Gj&9m+^#K)Y&@vvfH`b+r<>m6}V{=lB#
z{3H78C>K&HX3kaN8-;dj08|rz27u6o at UH*SehKj3LrC+~eKY_pxaZ=(#6DOP^*iDC
zKNb4>_WDRMYZmxd2iYj7M#Zd25c_e1VC=K~g1|OtHffCkHwU(B3dqJ5Ao;Yh3dswU
z-1lVxOi at B{G8zFQ;{hGmRXqJyfkUB#__d%A2@#8jM7|+VMF<OR754XvF!#TRD3 at 4Q
z5Pk$9fFMwSenNrzDT|4Bww`(8ovmjjQfGJr=sUibxOlqZDFyx~fr3BdJl=umDB+<b
z01zLAM;BmC9S<W?B&Ht`c>R!s&=L<SnHbvFyTa`LcpdY_oDb(3`uZO89%?_iH=w<;
zcWh7?w#aL0zl_iP59lm76PgD!5iGV8FlNGE&da%SzMON2tY`pSmBsD60q{NZ<WdE)
z{X<~Auyv6*)SvKQsDK&b>iMm`3a%xt;NDK6>b$>|aN at 7HYH<%|+v`~aV21u(+%pL$
zalg&6gx8a68zN9^X6=O%<G at 9Hq4um~Xd4Lr^@D(2Y$E}C0Y7P${R$RRY1<M~eyaUN
z>>dKw=ODN#C!ch4CeNuil at 20O0D=YK0(7>VaR?hkj)V__D1G=ge$p>L25#PoC%{c7
z`*k$$5bn{q3o#GBiqCKu?hU>sPw`tC1jfRj?bF5K8FzoCv7=$dd~O(szpRP%RkMIS
zlwdP|wO96!9g4qKD**+6L!8a{o7}w^&=@G*<{5ABcEOo}<k<!%6>mF;!7~t-6V)hM
zqBoKHXWL<U?RFTAsKpwMT>tPN(DqxtJM$G`-`}nK3aDQ`&HZNXE5ly|M6>fz`ilki
z!aw{g5ap=wiODZEe8Nb-DBno<7iS&iGlH+ldxBTNt*H?O$66Br;H&s;H3Q%qa8n?7
zXYOfF6+0__nui8lEMTXwmxV*Zg3(wP099bl3jQNRjZx_1hcKDe(VItAxE5}gtq at 9X
z08zloruV2w90Ky&5|D~N4_Sb{y7j31+XW^9Uh(EB`MwKS3R1<IXO%<2M}+4Tcb-$+
z0shs7;s!um4k(Y-=X2ye+ at Iss*c8ANzb<?Qngfql at vB&fU}UWn-49X#H^E4=iv3wE
zYR{8Md@;r058YgIL5$tn8TPa4LjO7mhe>ep)U`c%1>(gVlVAzNXI;n)<S#HL at e=6b
zWr)Fra4|2;h4^(wi5EZ3%;tePpuJ-QHxY^h7BV5Oqlu6_XkunGb+Eg{O!2`&-h2oQ
zK9~aqow3fI^9M8=KK^PVU(+!7IM92p-Q-9|=gUt$-x9?gizn8V=xg=b3(4&c_7|Kh
zWMisxFnNe=un|5pnp4F|+44c<#`~2U2QOvwyWyqI0DoNa65lPMRt<^mc-fl)!O7&#
zjE|Fm?kM3sp#1tDj<KHY#eSger+mbSeV3nfe;FvjpT4tfzEv#6|1JLQLoJT#Ov-;M
zj=BM*oV1Li_h%!n`w)N^Yt2zmyc*m}OrK5H&iMA-iEqpJH)5aG$$E=l#jVHm`B4;9
z6cH3l)dZOR3Lu*R<5vJ6#qVj0Ccr6w^%aTd#XkcW4S*2cM=Jgi_y)p%CoHe&_cpA}
zQK+Us{d#~kk7fY>eS>TUxFJBZBlpZN1x`y_tTqC&2{3B}VB613#UX{Ki at Pl5DBN72
ziP#h#6eSiVA|=Jkl_KTUIz$Q`iXV!nY69GffIv8i5N-nSWLW|1KE#0n;zJ6ak1Du^
zAW*@t!v7gW{!f3g^^u<ic>RpT|I-rvPwIQF<N8M>BoN0BAqEt5EoO!LHMRvUqCiBw
z8(|=VGC%8JJqQ}a4ePsQh}>7UZWKvND6o%%BILoZshHEgW(D0q2`z*~;Hn0H#&-?V
zJuzN^Ib1+yF<Ao5B28<W2{btr>t_AnkQ^JZud+9|Lwhc;|3ZCM*IDq}E+P7sc5wq>
zX&cs=b}4(XzpD^ba_B2ncpp%q>*6+1#qF%XRRFvMWN}*pd0E_o3kxY4W at 17Cxf%-Q
zt6mQwVbqv0K68cm7PJ-%Z+M+z`w9hIxLxA9&dkDr^I1KYI*)!1bK6 at yi;s7IKe%b1
z5Kr+7L%fB*1%A=726%qI3We#jH`?of{h%X-vc<C2P<|0ySmT5IB)Mf?u)oH;jrT(5
zVS({#?BXJGkG<!f at 6&!BP$5)}vEKZ0lhDnqx3-?3G4T4^jt9hy0-rlRWW#{_xZg2?
z*r2hoi*2E~z4zQV+>eGq at E*Qb!vNn5-w&S-j!VRe8}MY}_lkg9 at OyCl^K*W~-QqJj
zu$oO3hn*8aH4&5>D?b*NVxPDk at jXG)*LgH@>2`3A%{&pWm!EBi_3=8+8ffe4py9vr
z3mL$E=S_&oHZ&aEWLWyYeSK=QO at 7`Q20BOky8OK2c#qNe{B;)h8Jl~2CMG6`2df}f
zEa14Fe=DZWF*O!8KG)y6ZwZgDIqSWP{p~=3*0KDYA})alFCku_&_iGVioeI?)1!!V
zk*H!(zV at W>G at _=9ofJhMK{Q#MrI=DZ at UawMpO7DS_{pw({8K+EyuJ0?g*V>b`kjVP
zzxmDvephuwfY%c?u6^SjkHNUiG3H}#t%0?C9B7RnlUS^^KPMr`o at hp}$EUPs_U~d@
zcELuE2-vRdO>s`4?&4VIh6uY;H3vm~iR44#<1OOm%_+b}b4MIr6<|P|p9ENnu!4M}
z1WXq<bIgU$kzyv04%<M8wT1wSpF$Tx0G05W{|dyyNA|f>zHzr~hV4efNOm<hW#<wy
z!M)%c=LEmZC!Hy096XqF10KZr=h^4E1MaV;0B2qT-{-EmEYgLUP|EYiSIU1%hyi?S
z_+7(8{PG~bpY98k-%UQZePawiEB|t110;{xPc_4yeI at n*cky4wx0n-G%~RR?F2x at j
z1i{UTm%Sly at SoyLt3hQRa{hyZ1$Z;@FoZvU>vdu#&<}?>CkqoV+d2w^m-tTjQHXQ)
zGVu~rbE^b8{&*8SO|IG=0-Oaj^#)`w{JH;XZjKPf at Ec%fLoorq-=+9(p|3b$!2k4t
zdmKliq0_}bz&Gq4s?la~KDibA+T_^7s*mdRBZzzPfxq=xA;w_599QErA8UyC26tX=
zO{Ny(WD9Kb_%~nLI_eT7=_ruCtwQMet at D-CDSXaV!aqleKMI at H3{c^*`>*pC0j(L}
zhQMeB2q~CHLm-<1_0;`He+{rE=I8jQmCxo_8 at Etva04LMHhv9I>mK5N+TXU~KYsx*
ziT|*h3$jsk^#(u`R at mHymF&+sP at uY4)!9(cS~STKE))4fFl7Oy19jn~!#zl$B63np
zTOc725CtL(Lf|e7fGEiCm7sZmr+NxP6#kDYD7lzdq5p&e at sn-<OyIM}v*3SBLF^G-
zPeb9sYzW-1AjX)CjnKMX^W7$rvWA;g<h#Jv+9<H1xPQ at wJ%!-qa%75m_QyV_qCE<A
z>~R6yOdA0g=fDMeM-{8W=ky-*@7ui|D+_-=S+w0lARri6$FTcSs5aYQN6{!pTiX6s
zIi*FJ?2kRF5m2J+P9+k+xfl|u^_jm<a6R`M8jJB5m$PLK=CYk7sG_lw&6Tt{Ym4Se
zzyeEP?S-q2Xqrq-6$vk(y<REscc8u-=uMXxlR2(a;9>4H`>_5Jsq7u@(5#}d<R+82
z1;^m$!%CQLKo#edU}<W>JMQV?yP8nLZY4U!N9IH{W48g$Ds4E#wLUK~KF-jX&X6^`
zsgU#DrviZW_}3*`U#<NStsVcuZyw{X!23sNstMi`updb at ryt>~@B%(~FPhtDuYDNa
z%l7DdIHV-ueRwbP{S-Hglg#OTRjgodS`&L)o(+45*irFgiXlCY)O)@&bggY5U?cBe
zV-k~=HefBRYlHvVqj?XMbZ5=88TXfsg#f(mO@(SGY{sB(Tj*AUAmYx{5O9tJtpPCQ
zOMzTK6WxvUY^DS9XQAg2p>pcTt%dxjcgFw7zm<>1>uuiG{W)gGZ2q<`uXE(I>A#0V
zZgYcS<h0g6kX_ErxI1EOkFS~6E?&)R(IAKzGsO}&Y>8ip@)k=tbK(iHZ!~Eaeml4h
ze>&F%HwQc4lk?`iit^w+O)}z5g4iRjmT$vhxLm-`!yiKQd@?b_O?@U``Gin^KVi`m
zD6!D-G2x>C5sZK+XdNMrCVV8tv4v8H{5SB%*3-gM+TYUx0t69dAtgL6J3L;0EvynR
zg1Dxd4S at ***@Z;YSwc?}Xd&&p<ib+Nt at M+59B_XujwB?4`iwADb`ab{B?Y#H|ryXjoY
zR<;eo%l7Dv1MN-1?on~#VR7Rjafagh0db0=K7LW4qFUU$OB_TbL{VMhEDCE25^>ng
z17Yn~1;Anl$PW<alW<!$5V~M{?}#zlxT<l+e1e+<DZ(b<l|l<)rFh9c*)zhZo_Zoa
zuoZU0hVX#1=1e)aPthbo?Emx^68b;i`t3K~@%eEkoCW7l0@(Jq?L!1lc1H-mG>I6&
zwoW^jjc2x%wh6l~Y%B3OvoF9d#)@#|`n-3tk&tt3*h%Y}+bN$4i%V{lXrJtteZxuf
zT=sy&{N+8L^F6+WO%Qz#$R6e&+)F#aIrA-TFd72ItBt)U`o3rTU%{|JA;z#>nFD*+
zCYm$n2eYT@*oL!`ZHh-_qp}nGDq(FwjgZ!!OE_En%6 at Ldz%@5vDlRSJQN5O(v9-bH
z`MRzvR6Hwe#Jz!N{ESA^0<5b8pD4_}%YD>d>e~K#Ag^;XAb}l>)*P_UfYA_`8lL4t
zj$N|#9m=IoJ^%97Q8(y|gEIWJ`T!9?QG~c8A at A1#lB7x2`$PnixC<a9_H#b_%`AGp
zJ_;QQ95)7liiavLC^))!j$aFW*}~clf_&P3l7zS620`KQO at bqZg?<}51b at sOf<M+X
zJ?(FTKld_<rB)!hu*;&TY~iOqqd1BJkpk)L&qZUU3;&rIRgpxY1okNiT`1>sA!_I>
zbRHKguw5c&<9w=kssieAo!u33v;$c{T_q>uTrJ2bf+>b|-q(u=oV|-E6;2e<x2T|w
zVkruxJ1L6f42Ft?`;^%4rvOqCrTBjc0iz&J0rZH1)}sx4UPV3kF$Uu??yV}!n2)(T
z_pa1>Svz}SU+mL+mJQ&a8v(rt2Py2&1!>ztf6r^0THWTu?&39eXO0V%6r(r|``WGw
zUI+LO8OoL}M&&@*524LI4$0|USRx21AZ4q2l?2(hi$(0Pf`=633me}fa+jaIS0Jnq
zmw+=ASlhjZgqGGj&ROec4|gfpS$qn2C<s}AZUesK8aFO<J@?uU=8Xzz&0%4jdqVWW
z5sSqXg^#IFFmLo7*W9myn{_b`b6{hN{NfBvmk at D3v|uO!$C*V_vjp6ChJf>vUSb#=
zN*=AEz8B!z%qN8qF~yS*G1VY~D{ht)SF}#n%eq-V+{eeTS=lIfGTFw0qWKcOWudI^
zW?T`sI9H!-o+(X;jWbR7Tz|mX#_PNDj5jd87Zzg-B*)zp$Tf7%vd+F2&ey`<&472d
zo_yoyTTiJNd`d;()BNh_X8~UGIp1?_=LdEmt`K)(|H12N|C{?}kHuklgzaep-J%3Z
z(_qP`Xn;*QkT_I);@sgtamRU3ab;=%#MAzs4 at XYSd{N at wVqEAs22}2GZUl=4`jjgh
zMlL%-WR8t|J0Ew<#k{!|=feDN<P>@%VVMulpvgf#bWYr+`7OIuEXJ1jCB9Y70ql+4
z=gomBuT`V*+J8|_OCO7vOiqhtkedQJ=kU4AZQ_7qR>ms(AXwpa#csF^kKMo<JbruY
z2?-gv3TF-YoZJQQJor0rnumx-{O|-Y1dv6L=6+IZ2;m(C=VK}=AJJN)*pnc2k*DHL
z`?_Db=e{A33R&dI9(QJ;S4B3s4aja)fFEkORdxlpi2s3nEt^lDQNYJ_bzhC;aceG#
zW99~|!_b;o*Iim4YrLDay5OIlrY*tV0Q;nvH7IN;a4if%96Tu7AVRA!rbwoEj$&Q5
zluaq at u`!r6DRc(U>MS^q=XBO?M(BJD&Z^+g;u^p`b$(B4JjS(n$n)!G$NE?&>t-*t
zKlVRwCdjtJ_yxk3R>W=MI^~@bxYrm9kvGF6+zKV&Ld2zL%sFmAxTR?0%ze&UALq%M
zITJWIgunKT9k3y`a%1MrcLHy`ZDCuY_6gMl*yiEyN!02L at 0G7ICLAdnc>lTg+B55{
zy+ku4{(Be)gew%24aJhn6aGJ96h8NjtxFsBgU^2bh|%x8>~He_wjuaG#F_K?Kf0+k
zu%2qVgn0grZEI1i{cx`Aku!$_Z~{BR8F)m4jHcBmT0;w)!ZkR?b?_TL6_ at ZQd=4Kh
zUq)<mep3_bdp_6V(UD+!`X0?JKY7om?v4fU!U+Dt5BMB at jqirPmWXHF7R!pc at W4$&
zd=TG*JLz*DSDbYtZw>m6??-d*Fz8Li<yfCod<OB$BSBo90C$7G<9ng*84brgBi2-N
z&DNE1!yvw_pkm5<f%C`!u}m?k8k{XQ&2o#*;8U{yQB|-#AlxT{-K!h!dFf3Tezz+@
z-lhY)RR at RAK`<g9U3lxzORQZYl3etK?`~ZvqE~@LVn>vnEr;Rh00lr4Mk)@3GyYly
z!%CwdilSZ^g%CfbHw^|_u`<x#PlZhVje>^p0 at FO2d+~In7d27PL}BNmW+v=YXllRg
zc_uI^7J-5SLSl#s1qXoW+@~Oc&>xT;3sDRu5FIHz=0NOh0|m{11hs+?sOCZ8Qa|~M
zCPEck(Mb5g)&V&=!kqKIO6Pu!octO&c{LKEiJ*c@{J2F<en^3g0_#qZ%;G`hyN at D0
zdG??P`(PFD at J>ZMLbM9^I~5piS3(Kiy}EU?f+GzI=D1#S9aNyZ77l6+ti?^M<fH#;
ztyk(b;IsG}*Hk0q8WoL<;i9qDPZLCQF(-4oNJI>=2k%4c6Id(z!B4zyKG)jWD|@!c
zVC^qx?Xt;@8rMxWt=qn%b at w%6+bd;b3R`dmklinrZ}Hd2?*P|=+V9v?I}_%reci}U
zthJ7tc_OSrnDeRq-Tr+EqY`{tzt4+v at V=@+5Ma;Xenc1NR_D0}&UX#@J!ftkGS7=|
zjK&aai^k9^-UsKzKG`?Cgsbz0Wc(_`v1SJ$hTnz|D}+y%e;*O at p2GN*Pl_DJg!-Aa
z;$0Ux)l|Um-8|6xXALHuH9YWH>Kun(B`3$3$uEXq$!?vG_bYZU?f;Mx4?r|OtVGoD
zh?3QI*!-UN at mYK~egEj<FL*44{tO6uiK8dp{KeLjh<wEU0({1IPv|;dulpWTqJ323
z#rV^n97o`i04E2Z3h9&hFE)ec*brOZG8&MIDc_WD%5O#kTzs?t>0F45)r9Qgf8;jv
zt#VuPO?;S%{>&wj+j_ofVt?c+0YMM`JcRvdSm%E<_k<bN8{NMQ+;BItNs!oR5R6<Z
zv^_bG=ANBHLGvGMW54Oma(pK9sr^Rz)W0A|->&?L{oSO+hnxo^uT9PHmcvx2;#U<j
zBVJC;aB at d)h(|7H`3&E4+>8c-eNY&AA!8;yqwz*e3;zp$gRkKSOJ8VQ&X@>ypHb2F
zv~tRm@@a~+$HZC0<3pN{!Wp52P`I}Wegu=&e7p7#qCSM<&Dtx)`Avu?+297*;`%K5
zC*e2=zb*(%T#cuL!qq_bt|!p(x}mP+K4UrFgqm{=tZ9xEq at b<6uoNoZqriSk?6Civ
z!~qLw at c;}lYxIUiG$;^K*w^AEn+?%uc-3d|u+HSs6fkZo==`73`Ez#9&<t<^uA-dc
zTs#0>jCAlF*Kz$bKs*>6P;t)qkBSG(SxtloMiYUj!NrA%58w`jG|-+bsB at 3KIm35u
z&{Sha`(~Wk-cz)(Z at 362Srh9k(Z>3xJ%vyOe8*nA2ic3Yvu?&_F4n<0a3+Y#5~iGY
zJ+X#ci0Gxrx8PR%4H3R6=q~}E`P$aSK=I`w#hUH$)x`3%{(gI03^dOrpZ!{E7_g?P
z`QYXNYu6t9AMn(kMq?nki@)N(*oCu1*kdznhfp3Ox$%kD&&vLAj_)gWAn>>k&P4oZ
zyb+%{TZDP>XM5;6t`)eC`{4v*4Sz^(*e94<Yh at kf4}HxaLv$mW5!BTja)am{fA$H*
z#*gcoX at BJ#u|NEbv9X8eD!|L_(61Ao(EW at td^XpK{|!Dbe3o^yE(?7_;$Q3aKB`I3
z_p<})zE1#+GhrH^xxmM4i^(1Z>{(!~*ok#7;RXQ>%f)^Qf26sNx<!Y1h at Y0~AaCdC
zkc{NwpQ2I*aZ=L&59$X06&_IHx=){T-Q5a+Gzt#s{+pF3DOwMTJl86yTrDymP+?0V
zzVx57QQ(5=I}*R&R#Ja{BzeR$Psb?&_Q;85MU at augQ<Xb^Pq~XcY}7X$IF6bch19{
zCGK5}$br4aDnhjGcuJh2T6@~B!h`*}_ at MBRc)lFrret$KPCW_I5`KY62yTzMmvOKq
zVvw=1Df3)bPpT5E<q~5O{I+=(vJ<Mw5DkcZ+LQlkf9$a%zK?6z`_!1g213rmoMi_K
zSc<RQw*{&=aZm;K4GJtFZX`+-NJ8AGNLNz5Q~ZNdA-E~#f4X%K#l3JJg}!jF95((6
z`5oZ80q#rmYsPisd*+Z>(42QEurNP-Mr^@p)_0QvpGB$GPUC=cV_%#Ddo5mL7wlzT
zi!V!FTbP>H6Q?Z}HZbR at xjKWc0lL;dDMsLGtX@<D=Gw#0l9 at aCJbr<qb(Qb+29+CA
zb=GyxoH1P28AsD7#F6=4Fz at 5sXTTR4PeJfB_%Z~R=7D1t^((fU?3Ol5yWrE4z*>8v
z`jx2xI8Z`sdI}l{v9lCE#>TZNhzb@)G5+C%QIA7D!#uZ$I}v;O8DWn&n`jPVuR4qF
zZ^Q?DjktTw*Z$T1R*fJUbj0UdN30Kji+CTthEI*gj^g}7N<I%O2|a=UZzBG2L^_aQ
zU*d6~?~Vjq|763){n-e3ObM3xS;xa#(?gYuve7}Fay%G*9eK&(Utpiam-1)lDcOTK
zR6dO$v`;H$UG~r4H^+%<*t&R$PoE1fH#nIMCZRalh5xBd_*dh3;$(1V at Jd`8qF-1O
z>HnT6 at jvr{8OM|7gX2q{^J}^I#oUbVo%4cou2A-iTpyVHAoH+_`?HmY$;J2tXHc=r
zc{$_PtjS(^>kH*GnXjC)bgnIDfmsg6pNL!XDK}r!uPTpiG>_A_ZV|WO7+j-~9eFJL
z%04CD!r{ldFA2Pd*Kisxo4+rr(A8gxR*OJHl*X<?{vH+O2sVo;t>reJ{)xlU1PEbu
zqeMkD07^I`tgn^8zUCiGn1_fDu~nFUHhv|LU6(+Rfwk`pp3deI+ADP)9%rDwpMO5)
zYwwR7T6gZD_A{V8Rudw?{<Hbe8xCosYAE<Axa>D?BnYbOurmVokT~H6j9|g7v$)e@
zx(n)c0X0OFYK=#9zMS(AD~KG$WdIMJL;!6Agv`^gY<|u?PjYYGU+>3vLcflA0x|D^
zcw7yM$HePLei&<pkL-ax6(8AqHKlHWi{|0?gNJF~Yh~-sJ<bn~SmXow^AP$8gftjp
z--16xKjOOt|C&gjBLx42OQ`1Bz}n~fY`tmFk<ACiF`5x>3TVCY>w&2$uv25;y5ymM
zg(1%QNxN)%hxmn^?}bnBNM`_dsyV}Xah at f>-B?P{EO-`CjbK!)0nY+H_jmE$-zips
z=Y+X%EJ3Qj2vmeBqScUqZ|DLyKFfPN##<hnwTv}ty{x<Qaml~pAi!T9nPKvyx~A?i
z7)RqR{R!Xcwi-4_JIrk`t$!2!y0{N8M%j7nHJ{SkciFEn?Kk)N;_I<T?TPr0&$*$K
zei!(0<OCo;bdx9Hc#|=w;!ck}pU at mfUBlB4kqXg%P=V?O5$i_Xbh9qFRTJGtp{NV*
z*5VLO2!9ucN at R~HaXqR8_NbEC!+QOojBvjSvU`;9xc+wCcSwt7teYhEZkRO(UQ)sJ
zVia6Twj^JK>nOV91PBqt6p6hAl?yP0L5TzK*%Vj}dj?cc81wIakM3ohb8_5KP-Fq&
z!a+&GB46ucotG>4v+k?pjJBNu9(%eT+i8E;?j{uj?D-bikAeUjg4;z%fIY#TJpB|Y
z2Y4^=9kw&_9*<E)tZ<78dFB|!tmeM{TVdbpRMcK08?!#_OyNQU;R>2DX>W=g_GIyj
z&6^P0D_o%cTZ}DG=ddHV#&!%_78ujwQsb9xU5IH7oIUGt5mrJ{Yh}#`w0_&XAlqN9
zBttQV&|#m&<9a=VuH$;{t1%dJ*h6!5d$1nX#u^dA7bq~BgW4NB2~qk at bLz|#0o9;7
zU4pzsz$5^sU$s~O%tUDlfF=S?l+ZM?5I>>to}T>0y*1VbJl8Zg>lj7;5~JYXEcyev
z*WC9S>btrw>{3YkfMKIri~f#vPU{c5Z0@`NH$aa2vwzw;?oU_n-vY-TDgI>hvl_!#
zj_<kWYgw+d_QAepjRf1e**5Lg8wk-nNC9Qh6mgCC2v<uG!QqNy_?LxEiW>alI>j*J
z7mcoE+`mh4iMW5S;{F4Q`^0!+KZ5+RYzA1gH$3*{FPswqIRZSa0>D7T1HX^&oJTD5
z1>HLu0DWA&XTBKgovnvnd)sTNhV=bE`Zuq!ntOLCkrGRZq3ne`M9d^M6EDei?3>u&
zct9+WU9gY+pB$9=hgdfG{UrRcJ!e2OZr$hO>^R4hmyM{wW&B-89u)pPpYk*Aaz0S&
znYcKucfF}K at v^vC=z{-rY?N@*vp9?3$Cd&%o#kj1%h)@F|CFP9o*sFo(DIEN0gBs&
zsgWJI=R!9E3Xub82vjZ_%>Xw7@>f{Oq4pVazj))i$@xEW|IB}stI6ALXfJ9fcngn*
z|1 at s%9eg&I;j#P=KfEpZd-Dsgy2h~ZQZaXrxIDy{MCa|wceiP6%Vxk$5)rEn0l|Vy
zcIYA*(OiOh*%Yu~J5uNzW(@$p&!)f(A%f<w`}=;a(C3(qz4)wQ+RGB{JNBHI8VHkJ
zX250xVMl;XJIdB;n0~#$xlHgc8B_-i at QV(EUv~&P&%$U-48*S;;@soxml)&a_`!?d
zMhW%8j3bRF7VjW!XglkyhL8vH%l@<c!eu~yU4po9X+gfff1t#E7yb35|LZBXCH{}7
z0kDn>XRkx(cd<XcpWnBRSWB&oHP(8^9^4R!y?XC|J2eGBH3r;d`-l7w?a9_*dm2}9
zF2Nt2pU#kT^|{OMt6|{Alw!giic at zfMvSJ^w_k}Sf?^4A#KQ1<5{8Oh;335u|MCRk
znF9M!#j{5hiylkN#5HIl-LDn9Cak>Ibsnd^J`%8o!>)rl5YvXlH3B<@_EU<*Pt$Br
zjI|hV&5vhOus^3b3 at q%k(P7ZUQ0+3IK1=j#g%~HseMaLmS2Y2i{?Sjjp3*uj{sq>_
zdTWo^{NW$QS=6}@_aDgEf1gA>LjPW&@<9E1gL7U(eNR*JBO33hLn%&gLu3L?Own|w
z7IHUFQ?$T)v{(|-{S;f;kP9yraSzG>50SKh-t#@z-7N#(nGFEOMhM at eMc??HA8%cs
zO#lSyRT6IqyDLQ25 at Luj7hodzMGC4U>b(|WS&YdcsvrXt28j5xz~?{+`%y?3A=n1$
z8r?H%0BBssFR_YHb%CJuT%vWk7|=Rh2v7uQ57%ig2PM2|oZQ6EzLlhJRr1G{VaGRZ
zkFcQ%RohTSfXGqydzc2w3ivMU8`srq+n)P%4x9&L-bc|Oaxo8Qc9-V8Lr&l`&{_^@
zO*eB66u=@(oWm>L10o>KVQR?4Iec$A1KA>;ZqJM2I)iA+U{{K_wD0T;3Vfd5cW}SX
zuZljOOP)<H{(MdyoLK>GBtORc{(WM$ZZOs^czw}4s^XMFb+ at 5{Ujcp+`ce4rQn9-!
zYQHkXY!~}3`2YM%tHN~>tSMSkxE>2qa2gV#$1HI4e=Yo<Bg8*#efW?6&(??an!oGU
z%yA6(lfr!dHF4arqfjm^zT4RM0 at M7{x{d~mb%PK8*ME%t4)Fd6 at kiUd9_ZsXFt`3L
z*Rq}6`rbMFjiv!Y&A&qUqPb*Vbx|hnS%_7GKwP!ZQsDuw at hSL!{)lagYw~g8E;0Bj
z#R1|0aRHHBV#Y#7vBct<JfK+P9H4mgh=j{yDb^nYdi_YouF4BLq2e0%7#i=<H)9+?
zgL#a{J;Xbj%*45uf2KJ1(~USsz99}zV*f{u(>>N*E at 4#pW;C6ZXL at XNOvpG;zCVP1
z`uy<wJcH4=8b1GJo!6H`<lFb<_xAmFC+>?29c$NZ;LpKQ>`y}fq+H`zbMoo1LLZJL
z&m0FW at Uc-***@gai8(j at jv5xkLe?hXYQ^1TMc7!Pc)5b$_B=he8Bl7s2w`u*KmT)
zxf;v{O>mw6W&D~>InNL$MzdM at 9j>^6Jo5Z2&YN!Xs{mVyedl{|G3utMnaIn|_x6{}
z_l at s<a6(QemuDW22Pm1t;kD3ted8>LzwCz)tP}rb?d&1={R1}x4!IfdqJ at E>?+}JJ
zA_OHIt_QNo!DVAWxJEX;#=jU?h(9Br;4Yzan}qdTgl~rf5;<W0+4Q-8aZs=8JMm<8
z&A6w5Yq)n at Tc539+***@ED?Z4dV9_mlwqUB`lCT6uT`H6GJEi`P2}~1^HSR%oDyb
ziRXrk3y9XwCYp%-)qwE}de4*lwuT9;ak+<%zMq}3KK?I<`5epj=zTwj1^T)5^E7nM
zYg_>4Oyg5=u6(6@&pw$xYRG4MQwrbi4X0=>DGs<X^n>^(L>VXe1xNhSW%`win~VM@
zCh^Oo+ZB6gF5Ia&M1!H43;_vJL at DA_K&aj;(F!bH6+`{x+Jbfh0`~#Mx*>WC2;ssH
zB#fmkAF at d9_{rA8ikFWxxLL4h2s}O-0utc}am8vk1Q6&c*rOScjQ|9_;<WL`J6j)n
z^PR1at2P0jP at OWM8fXSS%j>wOz!*l2X=pCZ!<^3=**E~o4PKkTI$1AxQd;i`?ScIm
z?9GV1vhT-UV*d-sCZBrc&8?&E(#>~KNErxsfzSAxxI?&IgWm2!>y1cAGW0Dv07NCY
zQHOSe1pYxKrR#L?*NOmFiy$N=KW%MEX}^-M#ihtd0w<x9;Je5_SA?fXu((%n0~Tc<
z3kwR3D9m^g^EDSCb5w!S3YB_V1L`_NU5?}8#p7quqIs)H;Nn^9yFiY%j{-!FMPYHN
z9H@#17twMEY;e6uk6o}2_QHPH)5WV2{rx&*7qt`uDtaFlSq!~?NT0cY7BL>sH4nV@
zwyy{G87da?HJ@>f$I|t2-zK<*`<VM~t%0?0o`-($lW~TunS%KmogWPv7ZZZdO?&m3
zY2WPsf-0EXc|{{8gme{t2oT#ef8tqUdUk#dYv1+H)-XL$;(gAQJn3^!$m<vAYwK$Q
zrx(YX at V5|1F|ghM$ilie03_gg1At<Fi2f9SUF04Ont+@{ro<<L)cC^Ihu$SVxPs;P
z{rxYGe>7^nfxd?YX8Y^V-urut at EUIu>udRs0(*|vvo#M)=h at FVnl0HRpgB+t0yl=5
z07THy6j(L{l8ey{2yq6#E2iPA_%7m#7<{pOI~oCqpNL_8vT3pN>eekvx^50<47*z*
z#Z65mCdaXgJH)MyMGTrF<CWu^VwuJwHZd;alZTiOVNX-l4NT`5#VF+&at!OdO2x>P
zT64rI<roz*2)xlu7A{mFRKILu-y!fLRyjtc-<QZQfgk>yjXYo*Bb=AMT$qdW;oE<@
z>Ek=1pLxCS-xth>!Zc^amf%S8B)Kwv at v{{F%U|~7{w at 09QF5vBCY*BYRm>&ER=l6(
zOrZRL&8OU%V!p(?&WCzn66q4=7U)0lS at Nqp@+;gdaMo9<Acd>sTyoXb;sG at Wf*oE2
zB#^}u at -cunfILUjo|=UR6F0u_s<~D5Of~V>IDZenHZkwxfyg}fPMkKcliOU&J#l~V
zn|kYxtgD#EJkJLvUWe90PG)Vavzqp9X63K^;68iD4x@=LAE;WZ`~cgInhTqcx(mOE
zTwcC0esL-EMmc9X8UaEy0lu?!)fZCugAye9w=l%@5bK5Kx319NnYhXC`e$?Kp4HD6
z*l~>QVNqUxJ7j}3%td+#^)B=_grMr75|dqQ at AL$lC)CE`C+YhXs|tI8d~}HmfPDB@
zjlEzo*FKQzS+2GAu(?0>Jv9ktV*7KT#B-qw=&=3lO!B;zq8SwDCT_ynL~&RMAw3D|
zBZYloi8k)CIacVtvJ=KVeN3QvmTQ at s0MQ5-prNN2aE)RCO}^e77;uxIH4FHaNNX0{
z=mui_!i2^_{@MsA{`4loEs9CtR>f<Ykp(vsvY~LB;@EA9XTXgGp!j_|ziJZhP|O1~
z8Vc2Ln3 at i+Y~9VTp&F|BaF1$+d)$2ZaW)=a-MU{f){Ta2DEOBSio=ifCV>PtLfZmd
zF&tt398db+kYGpHm+1eu`1^6;WBUA~De|9FE_ha=-Xb1ooTm}-!VvL>M7-u2LVi2s
zx(*M<O3)-IjQM`H^}AZnQHZ<3NU%B_qkUJn43J#D{KKtFb at 2N|h)WRkBFRNS<cWgo
zyOCH#K%O|Ar=Sgnuoupf1Mm6VH$&75yXE{ATE<jp>{8LODzpj`Tp_k5xLA9asCzBo
z+W1uf?NU&4;iL7jR at Q8>tG%$VC~#EV$jPw5emM-bIv`t;s1el%MZ_EVDW8Z(Q{Xlw
z|2tmJqCy99KLrEDF~zfp#9!XuFWmRq+q&kht$V6aUV_ho#^JjAG}iqTBOdD)TMvq?
zhF&u!-*Y|90Gd3k<rb}pwNZE+l;d10r at C5>c%>ZG=dWUn2F^t)CN5ME;f&AMo_)3o
zu$*l*0Ydyw4FJUT8AhG)0&7j2R&cJP?n^Aj4Dnv`PV at T=_4 at FrF#==kn%~U;IGX%i
zax^(rKLMubMm$i2mvER1g(&Rn>9-pI`E<XY){iI8DI&Yb+zuc7!*zV1 at CS*t&z7j~
z^19iW%(cMUdUi(bDKHnz>))-9^B<3Qzwfq>I#;7L1+ocrjQBA7r9kp#Ch|(yS<p>F
z4qjH%6CPLWvPdI#DMsVV7GsLz#C2j9IRM`$23&*qK!hkRT+dTT#fX~_Dgc4bQ%VF3
z$oGM`hHHs^ZZy&?);J;LBgT}Fk2s_JA_0SNA=Zqhqw`5N9kup|H^iFCBl6kIBNp at a
z(}>;OFQ*)lwrYOqr}PUkAL1SVT=&t!@)s!f*+QP_z~Me?_x3Rd9}3Bf88^UoO#$`?
zsu at 5tqc;O&myrvb&EQZpl!8Yf8UT?CH^hJD#NZZB at l*6C$1M2and*qk5Uo0Q^9 at n2
zqVOsefx$aO{KP%;PyD$dIXL5?x%iqnc&l=mb1dQ-D8C`Ld6+ at IyOW0=JZ)G0voOyb
z>ZbZi9yauu^Rd3?I&!w}Q~qWg#;XS=%*VW};Z~aL_(Jo88zk(zAH;)`SG-?0wzPly
zg!~Vi^m;66FbRCwk9-U!kstnot at nK){Km~M8umJisUDje_aJJr$lZ~@C!eZD`aB;7
z2fDzra0VK8TWFrcVW+2|zbXvjzKRr=DKv+eFUUS~Q6EpOCt)Ar-lE>ZepB2pMg2Y?
z-?EsOpA|}QpFhJ_Cdg00dB&IjoiNQ~^!am5v*v)-JsJTZ_qfpjK=iu_l7e40v^~?_
zJ_ntL&rIBzgghcx_(BL at 1Z{~~1nUhJsuHK;iFOK51gHG!Hu=}>@-sxG1tfw|erTa6
zfmpa#vE at ***@6}jq%-U{tnz@<Tw(ZjLZ0U%g^u9TnN|_wX6e?%bL74#IV-M
zS`W$ZS@$ghdkD-$_8M+de3&By`zA`z3$ob_`fKo-e=@|cgMeQ9?;2$9Y7)%e3kQEi
zSQ~H5)7R3$`n`|ZW9%7wgq^~!=7elsjRrRkk_VjW12hN}!yi#Rx47mP1OBDJTU*ac
zU(pEoD8gU(sPq- at pZ!UQ{-=~19#>xAzDJc4_;tdAKYZN{2O1EJUmSrS#f?=?&?s5(
z;&5=Yh5Z#6OQ5;()OUZhb=3KvS3;os>*6Z9!Fx#@6kG+~H}L&lC6*BQ5`ci at f)I3a
zi3DRoD5rH|0Sc%H{z>##vG(;Ltad4(Snw-ol%VQGh at k*f1<F*&A+XkQ62fbUuNCC?
zC;w&M)5hGk5YqZw1ZmCH4A`T9<z|5PO_IenRqW6#A#q=+gS=XYdo9Hb1&l~=GsOx8
z3WW&;2?YfLo<f5Lz*4;HGdBc;dqu!|5c0yk^*6ucnvMH~y8oWnqnU802zvX=Qv={8
z6)F at c2UVP0^Q|9kUG>eEy>1sCa-97t%&XZ0AIyO)D#m%&S^J#xtlN3d#PmQF>_-aS
zv!n0_F(31;A=Y+;Slm0!k at M!db}7-Fmi#TwoC4rfaZ<cH5zq)|zX+I%jj6C70%M~Y
z0Oq22U1%PeFzo_%4QuxtDN3vljP(obry+z+iJocSC4y$xFURnE#!q;zrHu;fYuy%q
zm{|F4*r_!`)~=hQ*3j3|*IoNbJ2c at p1YhHfg`UM-h}rSWfJGeJHipS(@m&M~aSWd(
zM<Be3_xt`)A`WpO;QxUX9gYcwxTdgI_c>0a2yuQ;tgwK0ydWn;USKWdPvipUfn0Yr
zdq<2OaXrQR%%1`!fM>pyPvXnJHhnC)wB!?K;<M_gbNlziG+(Wu|9ZqIA7LN*>;1I-
zO^tzxE9MIrO at YQ6+11?1oM`^E=J<?50&#H3BXYsSqo^~;85hDE at r8#6mws7dRz;Z`
z04i**O!03aT*4or%#&~x*5oD&egw6IHM#SUf0-yKhu)3==jpm~DY at -#iSyAQS6&78
zz9s>Wh|fIvz)zGX0HHu$zsZ#gILDG#eV;_W#<@#lM$QyyoNG?zXB{^yf0EB>LJXm=
zHD9l_vxn<c<X!7u*u7#<3tW|A|9}cK_CG{EkX^{P^`K?=7=A at PmUY<qG{)qoqxMSQ
zTGn2b%bde94{zizovDG}wH(%Qii970D0F`u5P#w)(j|@)5_p$<4#C$yucyBK{q#Me
zFzyS?#P?ybBG|V<pL2<ejS}}?-?|9Mj+4OOLFDsq$WsJw2z~wSPwD4EAEf9`tcml@
z&wg1<4TZVrk2QI%tUWQrzV{e=p6npISm>w7$JQ42(QI*3NHKz6Y*^TTVJ_+|_W17=
zAl_7eTC^dE<U1Dd2zQHhi7JaV2`u^I!>VT=k#9a$Pec_DEXFz{<OY`Ct%0Ys1H4Zx
zuk)Dyw)KQ!4tNqV*zmORR{Q&wJ_pk^Pv*U2%$%3~u&;;z^$qXwAw(rm>|yT at ATDJG
zniJS$G$Rn161Ldu&L%W(E1 at ZyA{O0j0E$0uCI~kw4wZnWL2$id(Im#dyLFx5e==0i
z*~PDf;+H~K4a6 at Nt^}$B4jBCxLi{2qp*VKLzxLS<ZCvJJUavuGx!S*mn0^Uio_%rR
z88$eC=&r_qn*#C60c?%^;nfq>4B#jI(pNMCKJw<zx1RY)oF`|;nQ=Y$aW*~|>A$<a
z{mN(pA<S=;{loTiyI-&P&)O!Nf6vV>)?Fyu_s^E_FFo at 92fy~>)=^Fl0*M0gb`Hry
za3Y~lBdG{3++;M1eg9p8&llfSLjdHs;2a&ytTE8AheSm&s30+tm7!#%V0(rFiIY_a
zNy~{V3q}Q^85E#SJwmwH%=?@KNs0<$H5Y4OJrt`ha<t~NwHMnAJIMz7WMmTc#S}ML
z*c^~^U8O at tP+zA);Cd0 at MhX}??yYj>+eD<>MU=Z-q^RJa at K6DAzr;JZPlQ6)^SK4T
z2zU1kDozICGZ!sf%UCLK?(=vtCa+_>7>jwCpLHA(QCZiGDr9aD*=bZ<tDteU3YIGs
zD6SAmDNZgGE*Z^$@3~nN4WT&qI&17RD at 3Xo0eQy#oOgdF|N8Yd7}p1448|+yy~bxA
z=Ib0Qu&&_z#QOq#jbbYKJ9u1J at Of>YpZnHWi}~C6nmje{luV<j`s!TR0EA778;bKu
z*hJyJDQs5Yr<OoM;9Vj_LmO)c)LNDZfzd>Ug$Bqy3I1vFU&a$jqwRa_9rQ7_6?X}(
z`&dJJLEse-d4-wKlc<^ry)_~BABiUTysi>@*%<ME_aH at HKd;>XWc#o;cC3b{3v}_!
z1$^=kMEr|*T5-=JA^pxz1Iyot(dEY-^?mZb{CM!cd_Y+9fu*2uv+OUvoaZkrgnjI{
zxH{Ql^~@!V5z1l9X4Cv<C6nEkXAu}po+bWp`bEr6Si5dCj0$bswKYswGz5|xqY<#u
z1eiE7 at uavCd`aI*z7%JIFUc7RfjTee%*>U8FXqYA5GN)&rYe4t8{7m?uBaTjUj+{N
z#CekcE|3bL%9Z3Dgg^O`T;!aoBI*|9r$a9(ZzA?pfZw6qbtmH7`7`n!&GBf4XYNDL
zXWlC~|IrA~oXP!+!+7LF#wI5s@^96A%xjS^-1LJ0Yod|Q`dBA8s6x?D?j+w|`)%QQ
zgn#5w3xA+|%6<Vg!sUww0QJNEFM}T_*M5KNA{Bu>-|{f#f-ij6b;tAohMe^LA{XJ8
z;hW at 3*HYaVb$(U%bbkz=To?KMp^BT?BVNOy^wk!tcS0A<GvR3T*9#!NKcnycx1+>)
z2=y-9H!(ehp8n2Zv2U!5 at 3qt#Ywcb9PYnQz|7-yGC;LG5b^`#&-gEI^C;^_(IUF&3
z&vLAIT}_8B=2?>ky~Vtcdl-958)Fw5BPHlB71v78Bfbz_LuesB_&GUGWyR?su*7>m
ziI*U~iznssnS13&_e;b+P(mJ|i{M50 at +4LM2p$=T&$;FyM3(LW+<(7n*!v{7?m=*A
z?7Jm|@76paf`26O^-4Z%MF<yYE+i1fOU$kf)EJC+r^aTEyXE^KzGF`a^1d&?dRaI7
zvB+2ac|tWj&48zQimdqb%$x6QJ<C&NiA#gm2uyv>_gwd+u74b{srwn{QS4!xV2`kg
z?Sc5zI$~WCpc1v%e(YcSyH#=M7R8}z0^EoYRSdd5h3LT)q6o?o`&R><a|wNf_FT*d
zC&n*?fOrBf1Ie8=z^hCDcKQ|0rHW^P<?DPu?pYtN8cx-8VtvsVn7GQ`*yjzc8Q>@9
zvQadgUX5mx?8^CJbIy(P_=wKvxu5;Q=kv633unUlavco-cwjEd_GR}&vU~l?1A8;C
zZ7n-5n=7_+v$di1yQ#7R;-894_uTu{A8Z}f#nIU^NC=@6I~M&Z>`62v94%m<lFx;J
zL<HzeO9);JNK_)rC314GzeAfVARg=Q68mKUP-9%I at d7c&MNWhbxenIDx>z6UG_+>c
zZD<ed<9r#<sJ$&w-`AcO`>s8+7S_j_UBJj`t{|D~K(8j*)A83qU#|ndkzzq)xmiWT
zA(7!WiVGDQcZxK3rARkapcwi7Zhd#Bocj)ui0g0v(ZBiL+bB$gLoWk~c4PY7U=Abh
zWem?pv9s-*Z~J at C$6Olc77;fZ0zdIyC~U6P-mcLeuX0o1<*h3eG%nNreSSVOol~9-
zHp70{vh04I2nfI6*|~DS5Yj4IfE=_?+%!Mi=i~c&J-8eEt%5TeSei%k)%n7MZMpo<
z!KsPMamK;PiKBixvjc+1F9wI<F1&5_Fh}8}ZIT5Xc44io8M|m7?5Tr&*1o%Keq~sU
zJ#5X~e-~#H4ZQif3f=w&XPf7{hWY(%K7sj(PiKNGV5 at j7A&FRZ!77A!q=^!Zlqygu
zOiut7kSaL;e5GMfjRIjqH0Cc6LR=+AlORxHY+a}w3HrTDVF#Eqq50ha00_J;@`kvZ
z1YQWcY6N7Fo`rk=#S^w0&49FNh&#l3iiJcq1g3@@DA7L&|1%1 at rk@+*MFSw7 at ORNM
zYlPJ~3aokF2wFME-23)t*&6^2Y3u16`*{SqFgMo3dtxc_SA{<4<Fv7tbI(znXuL2N
z*7*>enA>Rx{@$3&rd%}N!shc|#4Y$CZk*N|MLJ(Me&nl&PW%_YCYD+FE6&jzuUJcb
z9l2Ba<A91FL~-R#@(lUr1_U;uTRG?!@+VK-m6ym*cPdZa?S^^eGaBXhsQ|n0&0lQY
ztJgi3(i9-KanBu at OWpJ)SCU6HF3tE`UZMdWP4JsEFL}?<I#|mM-;2gLYwI{@;lKDS
zv3xzg&wB#dG)Pc8Tt@?e20Zyzg(o at pYJQccyc>Ag`S*b84s!72*_;RazoPsz>ZYE1
zqNbVhaK!71xg+kb#M@}xZ8i$RXL|!11c#;uL2nWS!j}ul!-1W?OC)CteQeL?zww$U
z__L?_Jn>)RZvy*)-j}!y<mcmkBCi``c>HApp&AGCCIOf?3J!xN$Pb74JUKV(XzOCV
zV~;v_ize}45=hT)9S}dR6i*O&7DwXIL4Fc0ULjTxN4JQ37Qz<t2w#aD38edZA}v39
zkSEphEsN3yK6?=8d#>a9`y|@$k#F2B{xcSW`gU=B2qkg-W(2A at ZgDEmRIot(atc)8
zI<1qnf)Y>f6 at G%MaTpVL4s0O5Von4bYhW!mX<Zi2JWZEfSo3HS at Z?>>k4A(=xb}G;
zPwW+EY^Su*BRuWrR|JYxPbg+RMI+!134X*sPnZ+WDApk~pZdvLzRpbm-N*fmW82!U
z5}ule`8XTqNBpy%nF!T-Svz~^c0HKFe`ZVZA%y4)<_A0(f?p^O8RC?MegU2}l#maf
z;%~kFWf5alV_?k58j9l}d5$oic>Z0VaWt&Nah+#z+|3=?628J+pO?<+N&dZmo)Lea
z*12&ek15Z<b<Wu5pfiBmw=15P?YrHF&1G-a(QO`$mazGiUkGu}+NWPS#IGI3uPZ(u
zdka4fUuK{8eB}pQM-6d=2+`mdXcCJeO>DuUg<PUVIZ?~$F8i9249SL{g_D3tNF*kb
zls0u8Nlmz(L`m}0hQUoFRVDA6WrV;_0}`&c0KN8K1ShD^4c-^>z8U(sZ+fo6jY{OT
z27@&THy~yeXjtb#kn0BQ;X3v*Kr+tH+jZP~y~e41-bB%md%KmQg5rWggMx#?Lj}m)
zDn#!7NfsuFyXDw?ewWC?HC)R*+<Qo4FxJ at r+TLZ?n`X9+HH1yWX5f&<VLY!Zn*x1p
zcd at qFx_<7@`0jR*xYpw}*tTIu+f4Sk=7m?cu2xXFN(BnsfFl%km&tKT5ML~3f>T2b
z3)Qe0Vz>$7A&j>L{B76P{X!S{OHNzdYb_<}T{KZZiQC|SoYMT}i4FXw0Mq{9c$|N5
zhy9yVb^gWkjq^xeF8NqUUM>N*IySyb{`qeLPQvXQ3_h#B?*eTO&$qVb1bZ^l=W3tz
zS-&>MProy7UbS7X5pO8`-B1z^6nC<z#93XWfXEr{)md`Boc%d}|7|xc_9&>+DCh+%
z;slXWh3d&JQlmgUiGPN%A}WsuDUOz+X(lYYxD<{CO=J!rHW#R;_a8R&S^izSzr@@O
zxrV^zI%EA+Bxhkv5lk^&1-g-fE(JLD+NEOAg+78^w%pBAL)o>20k(Fd$IZ2QW3Bt$
z2J$;Y*ACy+7>va^(%h=%)0sZc6d(fYVO_Id4G0z<vvbv%3ZvoUr;%}{OFIo4Hrv|n
z<E%nhm%xrjLEu9`0({;u*lZeXqFu}VL&!JOya}(Vtr67PmwN&s?3*}B0p#;v;Xv`A
z!}dks)1c|R;GgRyH~d6d+`#uZGn$0O3(lA`C;pDOn+<bfE`E)FU!lT>hWUuIsw0RA
z#D)_7#1Z1>t;%7ev8`NmhjJ3laT at 64&wCL3Du|6YLFO^%+{~}!R^3P5V+`_O<U{2~
z@}qET%d5_<70WizVt&SWawF?xoEkR}`P22l3i>*L*P+}!A at cc@^DEEf{0mI$o5$+P
z9ggiS4jamC*E$|6*Ab6(9+Asm_JfVe<!&wr)#Q&H9)2FaT|WK%@aKxpG>3>ObHAP%
z4Digr&kJzSTntW*n4TP6qOKkH3yc?IXCq at E_&gQJ6xI2Zj6!>f|MNmT?d;Ir`FmBN
zu9YonJjNcv=pULe5)dLA;;6r0exCP?F&HnOWR{RQQ2SsVtWOA0BLQpiig1-^wSY#f
zO5o^>59zFLQ~teOXMdNtaJP7YkiU<o$Kua}JW)otBQU{_z|Z2fIQmeE&JgoI*}6AH
z=Uoz<jLF!{Q6iqXS%U?SgfwfrMr&lPta;e8+p*cQu(atBq1kK(?AL9mbG%Bij58iW
z3}~Iho`9dmOH|Dp0WWRcEWf!mn*e3oJNOj>zeY&=-YZ|kz7NQEqY3cStw&_n#}ua?
zSIl~XpOe!7`03BLo{_k;z!aWVjC&H1$&+S;CgNZBP3Q2&>>OyS+{sy3{HOS=^Z0r^
z^&cWs`zRsG9+!<2Y{J=GnLM9!eBJ<<aU32u^e6TPVm+}b=KK34s&OE!j63{CsCC6J
z07?{xZ?iY{dQh>A{bLL4QfG+mu%nwdvaQcc@!DslbMQHh^LZ!EM&EHw`NqBSr#g>2
zG#<QQ>{~ep#aQNB`UcI2YHF2_bW|Mj-}bt`ulmgo*c6-jCk012857hIKic3GTEqc5
z%p&R4B!U#a2T2$t5E7!25F-6nC9Ol1*hr{Ou5WGK2K3&75$Kv*Mao-%?z<U?;3PA~
zx=BW1+#5yyF4&oGiTF;}a4q-fUd9-Lm_+Hd#ri<4k9EZwC9+jC+=;j~e(t|_2)A48
z);{vSwujnt!S5Nr(C5)ucTjZX9Cv{?ezA48iW5Vx?^1y>=6 at Y%{#?V%jyacY*zIUr
z3b}W`F6cWqQ at rju7|-jiwT|`1T3KHeQ at jrQ<hrybuZ6iaFK2;Jq>%zw;0&VfDv4$q
zL<dA}cm==U*`?weyrZ#n(U%c+t&k89cr>EU2O{wd3OeT{`e#PF?gBRzV!R9gSz~`u
zb1;wQyO<{<n%ly^ai4Wwi3o-J2>#-J31W&p at r`}Eks>=_k2#luM?S}9+a;IWNC7^-
z at Bx}QaN1ngd<c0O4XlC2!!=o)u{PFtrTi3My+Z509KlSHCa at ***@cR#wl1*mixa#q
z^lQMSUyXaK={JuLh;-R0Z57SGSHo7~!1cpc@<q6oet{jjodBO<4;oe2mixG$f)x9E
zubPK>%^j_W_0q(FFXo8?_qh at s=O~b$MbW81N3l5*jsk_Ci^MJ*0m8A60&<ARAtX~w
zCfq1kg#=i=mIyay-%scQeTcO}&7G(<b&NF&7IV3unSgWQo5k*DQ at ANvTC_P4eA~7|
zkW;|##b4Yc`=RX|J`%iwXFm6DM>CA`=}liZQUSt3X9$PQ<3xWQO)8zUuB`^FdG2!$
zo?oTJ$l1G at 2*=@e^7&#VM*Mj+gtT_{aIT6Fk{f$-6G4KbcrZAS;$eCIwrkm(GiYbE
zCbSF3zDKN$1>C^NdAo at 3JQ!!5=ibl!RPFJ!5<8!n&K=R^U((1ounin2RB>>YiX#8o
zN5G#z at FN?oD)<~<9b*yr8DrrL(3#NWt(ao|WDIe9Qk=q<>*2wOwdPYaSVtTYH_V~T
z`!o|P&l4|bjBn(#j5B~3JfPe)d%xXh0`)<Sad_0VQ+!9vSL2?wy1vo+;XV6ef9810
zkChvX-<OErqghVlGxH<<S^3eiPv<c5-y#QgY at C<iU%cg+xhbCKHqLD1Mb0aHu{XnK
z=cPO~{C^F)#{RAAz4z|pBbQBe!j#9tCgh{aO<|uv<uc*{>*sHMw}kn~zRbs#*We}b
zP23!ff4G_aWQ{!7fT#B$q$u8JprHTB=I2~1afiqQ2<kf!UlM<}Y24eMr|8co+Y8*<
zP at i!whQz_BTbfT*UM^9|{H*IfaqoWl&I95h;{8F at 8xLB%OSl&hjsk!C=Lmh at qk9>H
zvAj3-rL**Y5HQ*cYrF`~jz)d*PrO`f3YEYg0#Yb(ZvnXwk)WC%LrnJ9^?n=laVjs4
z+-OYA&4`zZm7n|8j^h7XiKy$eUkfz(kVUgNh<Lk6=VURbbGk*GuCuHr06e%;oG5<W
zqj-m)bR!_o>LJAt&f!tT7a9SND`q{(Ps>%8gQsW!ATsqi-#@17IKw(O#$mj1W}1gN
z`?*<o3O9>OGyz!m5TDu)`<gXpK-!_suo?mV45wzm-1a_?erCd@{1qpbqJ0gB`!#{T
z#B7c>|7iSVlcx*+Yxudn_U8tf_I^X1qii$IPIjwv!>-X7(^+v&$^p@^c}HgxXVlM!
z?>Wynn>W_aMscy94fEdmEuD?ery2x#P6e&AgE-$~eZ>1IN8_jb6PKf|`@WKrNOwJ=
zTAR2D5vc{<LJ}jPY0<Zl<dhh11A5J8hk%kD*WE1Kq=bB<#o(JB>w0Yr;dGsX|Fyz3
zN)Xp*gBFLv)xuSXL_>*Sysr208Q0Z4E;u#DwHoVM)=dGKYX>*DArMUk3uCRT_R(?M
zt0Atv2fe>l`zUeEecWGrxk2L|WG|Y>`|+L%u{Zt(a!t7|L-%3}#<^iMEn<9Z7V8YK
z)&gsC^Q6}7bJ!W|XYKPivpBbU?ZSm($9TtQ%U=UwR>=Eor)Hy>eY8*8BF~qzyHWw}
z3MHe<<uI3jBgET&k(NY!5%_Wz at FFB6y+Al$ge}p3o&t&sdO7Gh3BN|@$#Gqr@>lOE
zPz_(hJ^6&O6+~_bXpVg}1LWK;tmFhCgsa$5 at uBq|An_~NUoB^Zvz$4_+l?>MY>IP&
zL$)2wn>T)8 at H%|tEuWvc)cgWlxd=3eCVMdt^U-_=o5@~s_OcmkbYjJ3U;KghuxYOp
zK+Q&H%SIMM8;C-GLKOU5A9jr~W_Dzrv|$KD+0V99VMRejA<}HezAOZ_XZDXR+z60;
z?y${%?na4iC417aBL3hj*ao|oO&FK)yDezwuol)8`+mXe_x=>{;|cP&wsuSKoQ?pL
z2to{51R4^8ZV0rdz!E8}wte5=F^n7+5oRG)MMe}Cv6d(>&fsYn|DA{?$Xp!#-E>wy
zlg{(x_>$k84V-YmH@}11J{ya#&TSR5#cc}rj8`L0C8{Ai;yK)1;V;Gf)x>R`7h~i5
zoExA)1?qKuZctnU?o-V0nli>O*A-3QX!bh3(=;or#3IKbjmv)V>q}(=#~yP>{)6w}
zH?kwP#nyY0H at n?DO5RlCKq#*G%*BJzK<LOP>fodqXfn*dU*22XS`+fS{x|%AJ8)($
z;)5p=?BYrH*ICRP4bX^t7kwq-u>C2)>q3bp`#0iCJgSBw4P0W=48*I1<LDCN9!(t3
zc~Al?xYLj|0K6K2XXZ%oWCQR~DE<@>pm3tUH{e%ttS}l>LOgVs{Gl*>0YA`qo>%j;
zZuV3SS;ueL&Ni0qo#z_w at aI{x3f@(`>J2MUF)Dd7<BqxY?ywyXYy3F}i+>TnERKj<
z at Q-+<J-AV%*u=izUh&S21vo?;l0Bk{oN<V=FTeM>#W{7q$KI})I+Q0y4fP%oV>FEM
zr?|H~>w>wIe1dCB%s7_&>3r&YU at fx;H`IeGs0TUq(15=*zQ$**Hk-lYwmoZaV_)n?
z>toIEcf|0F-}ouDNN>i#XJUdmT{TJ8ahy5)Hpgdm$;5ZpCH!g+-W!qgsu5{FNMAsF
z6YG{BHqQYk*Wa(*UtoOCQ)u(gnxf`-A=j+Gv)t^w9Q+UT+}vYv)=waXSjF4 at 5^~c6
zDVjPFD>;wpVQlcp`B3M{`ND(8R7d$qv%u>Djf00(yCY5?6dw?t_v^m<bpJi#08NJy
zp0{fb8dHZfuNwmLRRrfv@?AtGjg4vuT&o)6nrsNv`C&uiLY+a>T!Q0A<j~OoDCl0q
ze~I=I_cLhR)z5h9|F>ZAUBhSyXbxgp&FiK_HUX~Cx%t-~{L(~cH5xo$;#VEf)bTH6
zWCJ&IEXpO$Wvko2`(xQo;+=+ at e4GYZG;e+yO*PryXF~(vjd!*lry0Os-v1=dh-)5J
zZR|7BeGjxVx|cK3xV=eGfE#nbm*7mHKd9ru4Nc6dvuHjXb*lv4Aw-@<V1mLtU-R9q
zTI4MfJP2xweG%zK7wkXVy21GA*7XW%2esgi>$LCzO*VU<u(<a1x?f{34&wpFXCCG=
z2ynTEn-N%rT9>}Rk+tRhwI=4dR!&2bxr#)sKzBgKxLn4uxRA45s)OB6ktniPLF8gl
z1lULNc7V$ucZBfux{rJJ$zd4hLINg%GYhaNycAS5?<M~dYuK-~upSpw6cPkst<&qJ
zz#uq3kH{7%Ism~N=y2I1jgt-+NW7K}mfzVXpvL&ls~!^@F<05CY{j}*A8TgqP6j}G
zV~^~c{g*%`2_RY!@n=(Pr%>A?oGHhwpiAMsTTVTSAO(^DueXD~*Y(_Ec#LUG#;+oU
zd70k=io`^c%5%EV!8j5dXK+~wCLBjL!EV=(%*7{jlf){{;T!k~;{SGuT6_nex<$M+
zA9dZ5i;OepV%YdH>?_+cKXx4)H2;1uY|6T~vuP!$5;I2%t~YdVjG^(;Ugu;&JFk-2
zwl<3<z!hmT7j?Fo3Ln`3AI4utypgROUoy7XR^3jvQE)MMxMH8;oP2E9Ckv0T&kHN|
z3BbSFw|Th0rcDyqrP(F~dCVCJU+b`ql<>8#u#<dV>vghMlDB`$m%^{)&$1c&wEv}F
z!V}`wJWd8GPF5l8cwBL^!Jq5<8<bFjgBpi;`2Dai$za{Sa4+q<VcXa<g^!yqN~Dv0
znmxDSSY3<#hdph}ETC3-mJJOGq~uxorg=s&E4#R;*1q9WHB(1!NLz5-$Orge?)_4Y
z%h{CQ;d7i}_qoBREMnota<3zfb+p(t(Cz`jwX$PyY-+?Mzu=ZIxK)C_xTTm({=i0^
zUx4N!d&O>mGdJ at 42@&f7xyLbI#h}L&u#^90p5jcLzj6%)+Y!Jc)(FUd3C at -E`>(KV
zp4EOsR4frZG2l$X9Bo+ptRsAO4Vt5`qoJ>XbD82z`UKoaUU1f3*t?ko{#s&NBKu?&
zrX|3uS#%=!tFLUG at K;|B at K2SD_;t$h;Lkz+LZ$F$?QgyA at 7JL3kLOoS1Jf@~0y%g7
z`sBp_KK=TrHxJkc`(a<~&y9m at 8USp7EsE=%=c|p)v@!NBzE?bTOlVv(%(KR|1>a~!
z)V&7HbjD1+73b<)jpT>9lIMI_G(L^Bw>XAR at X&!c8+Bg!DGjog3yiGE6sMgNIuySS
zkEk_zz1QJ-k at 11%V_xb?#|UCY#)pUzQ(OQM7Z&k>n83aS_GeJnIzCjr*lNa(es1mT
zHe-a~Guw<6lV9c;*7<QR$uD?TzUmxSd2HF3$Xr%_T)u3W%Nf@@;Cb?WdvM)^(UeHv
z=oo&Y9LqZGBic)G3;x!_7&mEU?}+>2P~}IRv+FSBeLpD8JXshIsf>7l%e8K#i#t6>
z!qurhh#YCVr;YLB5&v=zj(^nY+B at -pxZoI=jZI?4DJ=$0h+nu>ta&e3YqSIAs|M$(
z|GPb?$#``jn*sg_J^u!ue*z&5=Y{}{5bd9az)j-&&B~E9Om35nZu<^RfmgTgl-;5!
zAmOf>>pt1_ehGUwVN{De^r}R^#s6DdkJ7aH$=d_*VEQf9#ql6`s$*2wP}^i}=X3Mf
z_46yl_l40AWQ-h-X3<eMxj33|<9ookAJKy#r=VYhHa5N2b$NXu#?xlBP;i45e!VtB
zW8gZG@)|^e3fHR@)UJY<BK851^Kua#!XuzARUo=VhjNjep#sZ31(Cf992Y29kkHRl
za3DyZE5cIHoh8Q#f$(h?V7;KDNTYD0h(l-^CUX$FW7jt5-_7r7W70VTo~s3#TtkP~
z#v0dv;}N+0S9=-nr_cI#XZ~Fw at 2~N5E+f}u%xsYR`ph at BPP1dT;wByZl>Y_fbU65m
zlb_T<@zY;tF*Lmv^84jDMiwB<8IB$6U~Oe at +m`)luh at XIx4<P)kVF*FE+qMgHy0z+
z#3#6Qg_5F$8KMjkg_Ge>;_WR6TAuz3ha_rm*8AY|g1-_SG!hu+N(BkVEZ*){@?^f^
zENd`l72t!j;;YtZ0n#`d=Qy3+I5UC0##!m_;OsW&+{^omXT_HiYRrF57CQJ+*iD5L
z3ES&evZt`2FrZkVkf4~se%e2Nj6JZ81DNbY{BSdmxR9~I at u9_p9uE+4G!?HUCfKf1
zOrRM?T)0AWGPjX-?zj|ajRQ(<M*D0($j>Z>d~b|bV{?wo<tCiwAN!>EQoLe~tkvt*
z`q{^P&u at uC;O!ldaWm~Q*+!6UHhCs{XdMS$2pf36+Q%hI-o>$fN at k9U84u5q$h5dE
zUUeRsC-{07FzMsX&z;B*gYwbgrwd;lqCwnc?#{!rc!DJU5xa|f_=yXDifVYLy|QN)
z(Xs(&VEZcx2j67BvVFH at v!i+CT$6bwxy0GqmgE@<p_XS1`7OSSFJRxjK<nEMaUJ)x
zF$Pp9Q#eyZQ&>}An}-zO#XUi5<D7{p=AYKgy3Ij~xPjPHG$3D(z2*MwGa85S7`Oa|
zeKHVEt0w>ezb{EdK~#4%#;ZA^_|$VM{84<00<bmR7WuTe<Q!6b5;k&2a-#TDSd00y
z+^~Vof)HWd|4wN4t<1B5<njzF*KOvq6!*dj64Eow#Qs8n|HYR>^mk+fV2J#VChliq
ze><$*mxy^1%Qa|yU^EHbDA4=b3(($b&r59BURe8O!haav&D?qJ#m^xqGM-sf%xaHs
zj#w6=?%Vd2b7}6$e=J&wXO&A^OxQ6Fv{---_dGO^z8-NQ{6F&3;gIoSM`T=~smlB1
z*nPekrZ_cXQDXM_Y%esdD^_LW+VP6KoH?6#wT#WgWMZ!CsVV2pG=Sq(i&c(O8KV at R
zB1dJe%d;;ol%E%`XZ{Szr<eXi!wny+*V%vr{-<9B`&D4_otz*3755tFSikEy_?BF&
zI(M(cY}C1`am6R>S2Y at E=3g!=50Wowo|7L7d`6zEhcxgla%0%O?7dgD^i*5O##L8j
zKCq at r`|=B;5&L^Bk at ***@qFp}&cCxKvj<8qQZ0W02do1hV^4qg%9$`<{A(QWt
z4{3_{L2vV2H~WU)PQJVJS@>?>&>5^f{NYTnJr95CK_qp{_$#<M(9X-X&I<VT!BGcr
zFrW#q#(^~%xRzp46Hu at o)ZjNzgzKgoDb7`p-u(JITekp-9{%#)p9?psP`yz_)eXA-
zdfmtUjK!GOXcNrCe9U`5o4!I$eL01yj4=u<;Sxj<gp%>9_}C}xg<KRL5Nrsf03yjk
zNe43trSEL*G5Nk7qE}A7TL)?<7fz?Z1rk9Vz6mL~FcHe}3odwtlSQJFMN|W_78>aW
zVYm5gh9vKHpP#6|0Rn*j^4Z4c9f$jTiRqdX8s_g6gp7ROgWUM8eb&*6gyRhbI%EEw
zv37r<tzoRWY$e#voCAR*gQA56&P`CK2*s(zgL39cP<-D-`-M0!3D*v*1cQ@`uW<KT
zoDl~Uzu`Lkzcu}U_k3>7!*@9_T)z^Y6DX78mnsOr at 8UM|?N!j|e1^woYh7n0kKu4M
zZ6 at wooK<tGao0%xM)E2iFQL!#IvP3C{W0EX3}~)OCfE&M!mn6YH3ZH at 1f&gZM+A<O
zjBH6VCMlDg5!6oDnY>Bl2oTu_8_(hqNd{3XV0Ucln3Qn|T#s;DAmUYk^C(1<F|hn>
z?V9?0yjNTsP%PxU2QvN*WLz9^Qh+Cie)5ZfTaEZ`8AEUSvEpc(n?13&*mv0AI*D4_
zCwW#e6}|?~B92x=l=HYi=fe4LR_DO6;#cFA<6-h?6hFj05_847^tJN4!^fjd^q5!U
zRUGX_4S=Ig&?M*L<4DNalrsOKk+-i3Xr4fcbLN};53b>lH1o)HGzPG#&zWXGp6Bc=
zbk;s|T{F%A`-_k8(s@&7aP<##20n*43-~+$zqf<FH}8!c!#>dcfY=l9$NAa5P)MJ!
zU;K3Idi)|$ep27VnaahnW^qUJIv0yKQOy0wvCsKe+;M#RlHybGrt+(7&lxx#nKO|$
zJ6~oT(V6$W;XI%M_c#^4Awc85gRuPXB^(3(6#SEMG~hql*zn<ZgFgw3`)f>(UvtI0
z%e8=5C+nSrviG39Q~~cIzUR1}!`4uC>3MXC<vrU0v5|9+H7wQ!!tVNOw7nE+k7Lj4
z_E<x=-7$X_=T>L9<N4*;%&_<mWA20x{qY2UwtT;awK;P=V~t+Fu-MzMPuk439d*nU
z=PI^YfDq3VSBb9`&xXk8 at l5e~7SmKCjJQTkJaVc8Mm7beyei0_ at oDGRjC%zO>RH at L
z9PWFN*DP^BwLJ5<0S{{a2G+D4d`;dT$j^9KV#MCqW9Wnw{n|ed9WJJxYPpV>H9bVh
zn(7OxsYX2|yN}p4&v&lzGtWirTEwsBSChYN`bfmC;LaNF!Qg%&`M11o_)r^v$-PlO
zYn|pEyc3Fd#W`ZO>p0nh`WG9y at g!bhPi*X_vhoo*hg`ygt*Up)jpRde3b_ehaAuqj
zxns&3)En6d&^#NphHF=9&Uq7ft=6cs*a`jGfvhReYBjEFi$XR6$}bJq#Phm18U$g#
zZ6BI}tdq%&(Kw)9PH6uC-C;jZScBN#C!a6CVeIIdT4zM_=EAQ|O$KaDqXGWo2b|v&
z4;Hny{E2ho*9k|J(76~V!l`gF91kZ~VQ at 7?f(nM~D6A=vcoN0ot8nG-jUvGfDv%E9
zyK6-duH_!?Js{#-uAp$4CcI3J%lMaQF&9&iYR(HqGz)s5pmx3m&=0oGgDe1trPz=`
zT&O}GoR`7_q#^fM;1_V}68dvk^cV8LETR&p0|Ei?0V^N?9r$Sp#8MIE6!6y>C_ps?
zifkg at 8bQIbP<BvRLr?05!SNjwR%@Si=riBju3e5f!>kxtS?emkI>WT**mt0PR<=p3
z*{(ZtiTo1!L(uB1EMhrFovWSGJovUbau!ZElB*H~&c%~0{DFju)8H`jg)8g}hy at ki
z6w&DiHzC-5BGIqEH<l0l>(3hhCB$@paUUNG-UsI|NWl-+;rZEG59>PX^DiWigR_I5
z=4Eh`y_u8n(VQ$~05v~lmqhWke{badr}<YL!Ewe8+r^wUzkP;Zi)dZ8A^xZJl28fk
zBv<Si{wtemZ-`Cy$$s&5fZt<>859#PmPo@!g-Z+xSfKORKY*}JPz(Us*l|X1F+oF7
z$?FQmAHZ3FD;1Nj{61n?K=>el5O2geL=oc1B1u3rA@%^`Tjy&i3EqGp)S1HrVjzGA
z!3pAH2eI-O68RJAvx=h|V4Mbzo%483&CMEa&{|j<0*`gG5B7AW#N(WQio1<}oWliO
z&?Wblyz7mCS?nX$t;D(EyWOXUpRb`^*T$JA?eg#Rarj#Po&03Itb1 at 0KAMa0FgVDb
zT{Pq0vIRD=kBcwGk;r-C!%OMwdG>A&aOVBIU*k;TT$ZS7>a30!{rcHB6FkT3Z9ctT
z@`bomuV-u0xNrs at v$x{R)yWy`fIaXn{0>{e7so2u5}RUQ^F*-#+mj<X6X!w2<l=$j
zzw!pT24Nfp@)s9{@jtsL9z}15gxQBc6L9_iqR{`hiSGro|0_eE16UZchD5EYit#Mw
zSH+-<al~~B1fz23lpBlx#raL%C;qy<HmcTG)El6U)%`HeBF-buB-Rz at QUYc!UTSZ(
zSN6SePAQ=0=QN!WHeTBO1BE~Q!q#v7;pYQ?@cFIx&+rdh at BjUO*m_^#_qM~|2mVX`
zt=EP6tbgwJ?fx;3=G9*#*TK4CjnleoAHkd8PS_!BVt!1#=$x=XOCHqO*ID=2W^vKu
z8u_;8+7t;RzEz%;FrYy&<=TvSh~f at D8{nF_wsHft5Dz3S;8$XdE%@Pt#dOpxRiFET
z8_>FlyKW2`QJ)+25RSOv`g{|JQP&lP&-1tL?Wl)&pz3?siMk%hZX<V5|5XjI`ew>u
zkyD2MG at qG#G<~J~rD9k|i)WM1G_jw4Q?UPZbYEI~-!R5mX-sbND>yb{O7aUEV2`MW
zgHv#cb9G}$^#OU296(drO=lX+$`#}dn&9L@=ML3Nu5;0Nt}&+if_fT`%<76(Q}lYG
zpTme<J#GQ^)ImHg-NN4j at B4LNoaZkOV)o9Th0f{U)n0b0cM3i$Q1KkQ2(Euz14aGi
zIFYep=$xvBINOXH_NR&)S)aS1p!4Cs at o>~0x)6M!56|c4iaI<F at nVtSQXMJ+{s4ut
z3ZiRNWL~Gkzd=RMjVe;XK@}`~#&=h#kl@<OMV!l2cyd4ET%^MOLXBzB1345}&TGQw
z9Kqs8!Gp!_0SX#t0y%sIh~3)Ik%Q|4b^i<yvatBBk8?&AIc^RVAg}`TX)^k0GCnvJ
zi~yrz2x1E-|1}W7P4XmqlHG)Fq%SyeZ-WyWHoi|%ZHL)BGlJ#Xa-FsI5R9=O?~5R+
zeYz<E2(TdSaz+K<b_QY3X5VgiBhR^?cR}w55Arp9g&*+5%^)~aiANkdn`RM7i3DYc
zXCyC at 8Bae+Zo-8mK^3<bAvVR)OAwRamVo5fDB|w{p1`RnhSS#|1`&W304k!B`!}k%
zKB&+5?wXf>Dj#`s>q^~Y{%f4z|BpNeKE=G})97+={QkuIY-)L**bC0djx)Zka1Q6^
zOoDd}^?8EpDo`-S>bdE>oJcv7w6krTcAadh0wC>qJ{@-LX&*&|_Gfz{;?tfM>JnJC
zs}c$^!S+RD>;SIuwH at ***@5#`3!t1jaJj96BGGI#+y8f(M}t6t_4#&fCygUhRf}
z1QOz!gr{>R*3sxWh=@W=l^_%s28thzCj+|n2H|?$$NhmAZv$<fgLSR$<9=`>ad<ZN
zJNjN@=e^aCy-G=Z#O35A4VB`hn*oED5tECT_CNb at i-UjDxwnjWEzVVpA;vAy;t&|u
zR(#BOG>b!- at En7ZzfO4Ou8Kmfb#PX3U^D>I_t*U19EG3aSaAbB6c+{u{#EDi{6|Be
z&S-unv$Fs+2iG{@&)R$7^PEs;+%fT`05^gk9dMHCW2`oZ=4CxzQ_jit#TE8S%%gFS
zJ@(6Yt7+ueC4RU8Ap2r#;uL4#{HOEb%s5kW4aH9t&L#e*0$HLGs5l-4t_t1{0g0$d
zNQRjFpoCUnE+m&2!m?rQx(QvVf;O*3ZLDcokXK<}dx>H^1p#{%su=BsVddc9x%j;u
zw==&wMlVsh7tC@%`e6AVel^Y_&Vyo at bsgt3iS-`#OiI|>{&5D~z6fI@#j=I7g!HO#
z at 4~#{H^J|MzZ>|C8UA+hTKIILzh0uQUBxthpEsa&fyFxC_g~sxvPn=4f{AO%C37fj
zSe#ko%8Vy at UXF)4Lmn=<*yqWp&UkPl<6hNUA%K;)SL>?<GS740W?dV+GN&@GTcAlS
zM_do?R{UnI)SSif5?|)nUu4tI$o)2S at wyJK5f=9y9>f~3_TBbi9;4<p*4EXreodY8
zdqE#(Y8-*GWpHK^whPX{7oA--$ITC&`&s;Vdlb8g;ckS}1Xuo}PKpOy^{|&*7x|9A
z<iIQS9oKNJ>jvG+7?lsGy`xTud;o_Wle8A|CizlvXyQojDfhUY{UR<!Y?^@>rN2gt
z%bTeC6Jxx5z1{eUF$bvFxQ3o5>h&6y_a&ma18P07wr-2TkHHH88 at izjCl<UA at LM+!
zbRH2$!uR<P9UjF&QB0jd2aN(shk1^^plI4lu|%Q76E=z?5rM+^8lH+!WT=q1UWLSU
zDkAud at 2*e*ahb at nUt}rqvrh%Y`4C1$CSnXBaW;iSivBYtHV}LW#WO^rnfQTFS|2zK
zAcCCu8XUCRYa_4CduL$GhS^*lx;Exafe)z*PPiQ+y9wU}zk_DrBppH(yGM#q2p1Ty
z<`FzEfx0l(r~MPmwf3<$0zQGik^~N`VtEhZlXJk41&chIGdd>(9_My}1RiI2VHVC8
z5d?I$@Zu5`&z$w8DY6WLg>X5)00AnfXF!aA?|10)x_%(WsPPPqe`!HQ>b5}W<m<66
z;4yP;UXOws0ZzQVGKJq&3Vc^1p2X>ER2;+agA~hIL<3&)*>w^ET*LKONo*a^7>vg}
z%za5~0$@Woz(6*^@HOm?VDUL1x at ZRA6P%IGYB$ii?T9+lajw}Q@!2AXzUR5lr6Izv
zY!L81TM2m1mS5%gY&lbjqOx1s>WZ|}fwWV{RWBkkr}qaCoVw0-^*N`l$GLX2^H?J9
zt8p09<MLN?TscEuOM<gBl*kamB(#RB2PA$-cy;DJ_rSG?qa}3aoIBY3KJU$O%%cRa
znP<KZ)|Kn5*A2BkuXnLN=3@=SV)%H&>nS#c8_dtQlAp}0xikm%!?yM#_$eQ at KkMxA
z at 4fQ%HGUR1;g*|o=G}U%9<euL@<!}z=yAKp=XuQPjj0g$tfx5bc-8n!-s-W6Jrbh^
zpOaI?W$a=**IC)VI?Fs`i+y5%<3Qo<8Qgf0*gohcj3E2RnM|+yXE*$0@!f2^m}_wC
z$8QaOv97^^BSGF%T)B>BQ?5VOQC!iy`mVTwU9b~2Ge=tdA~(<wbne!fzyZ#U^CTyc
zr^sJ!RA<3=TorsS^uD+#?o<Hv;z~u*Xa at 9#K#Hpm&YA*in8er&`LuQeJBa-%{FcR7
z6k at F~XMZVxssI~;jv~zYJaV{&y6hA=JN#o-yU<|kfBk*)8}9QMS!-l%!Cbw_4x#_0
z6gHE+yRE~{*rDvSDee)v?<-M%7%>kfK|hK5F1UvXmq`Ehj^8;9e!KlG=>2~#^w0CV
z8Md28pRF|yHktyneNMKhUkuEDC6J8(Y}+^mk0uUv{-}T-+!2yH#h<7L=QUvPDC at x4
z`@pCb8%IjGhi?W~f-iH<u&&_E!dHb4YY&4%?5q5=nng4J3|}m}tl_tIz}oeNX^u_Q
zFEi$To@=c2*16=_45ZHoh)>hr%N89&l*v{DL!6~RD`4LiE3o at G^F_=U8X#jv#EWVM
zMUEstj=ZRxNc}z@<SGZogIs<M`I_?`xvoFZa9uL$g4cZQMc;}Cw$^K^7pYBoAVeN!
zPUm!ZB|gsLykk6w{bQSnGilqj_na?ad4}s}URdMGKs6=Xdwy*+yMK92p+4Uc+4%bd
zy>1`|4CtEix1oMbG#g8Qm+J%NJKZi5mqFUI at zxCl*?aKPJPgiNd@;XtZkPSTw`c&U
z at ***@m)NRWu4N(B|g)LujZf&ei<(L_;AQ9)6nBH~(vzY2 at 1RG?m=f`M!Hi)a_AV7O4k
z+baSx&Uq4&jCr=m$@piwkW}HIqK<i8I6^Fn2qnBK7!kMNWQvLw&`y#=tO7!ItX<RK
zz}Vo=36#Q#1sMvM<Q)#4ARQM6co&HK=8oUt;LqG%59^D)hu~KcfQ={)(smTf*m5_;
zIYoLF$!E#t*#6uskk40vzt at 5<g*+nuI|ybK$2z~uEv_V{5FiQ;ocC1}g#v&5p3imW
zSE^7vpy0vTUoH{Gy at rbG%On^XuV9gn80^rsSLi<O2M5HjD>dE_M>+r1;uvr-EACxG
zp(^f~f4t_iLS75J*2Q`YjNjk0Uw_WEwQrDPd2Y?coY$&YzK)_<#j~N;*Xc9X<oUTz
zV_`@3$o{eKB`+wrN?hYp7gA8mKQ8!}Y>we4K<9KWO)`pX1Q;L)CwOh-cjtbIvz4Hi
zkDbR;+#Kryi6G8-pL`f!WKQO`FDuY<KAhQsJm+ECg&q0MXWaK8zJ!mzY#(PXub(xu
z&J>LHb0sI56C^5g6tR$;wa)`YV+y||N(i3LuOc)?!A%jy7NY5qymtddfdAzKtVeL8
z1worAJD&T+us7?+{@BvL)JR(fUUDOhy<Q- at Vq5mk8QR7O=oFlD#Cc<{i)jWa!2)c!
zUuQwQwC at 4V#b?v}#Xge$p>wcb7Ei at 9{F1YRmv9g+c3#>?be{HKIH at u0qxh%hV*ZOI
zj$@s#I4-caai(9DJ(82y%C<{;Vq5GCBBo>iM4d~=_&(2vv&r)rXJSrI4JyD|u=B95
zV-`)vu$OI>c4B|F4^5NuWBxATYvlL3o_mNrZr))VP%(<Jjf`b9Pdfa0yDsmGcota3
zG~$DsL^_vi6;rNLF6HdT`8Cw%b&lbeT7T_}JrKLbK7uO)*rjYEa9zbeuO<Dy_!DTk
zUGs2{{a^dV=J1$vaQu=_5O+8;&T)_Z{ssHz>3<(S?7W`&yab7JTje|F#3)c)99x7$
z5ot6L(u>MbTqc&E7k2ut(8oWf74ZWu<OLV-QxWe%-s`VAV9MdMJT6piF@&7!jY58(
z*Usz%s>T>XO^~2CHicTZ%ZL9gib0CP(MVCzxGb!z;H{!{68I9h{U`InQq<1{eG~Of
z+=C&y3tf0Gg?he6$R9cWX63VKtl4~P$aQt$54IKl_0I>eRocx3ylvWw^b(j=nCIDW
zPMlYW!HGY;4xDktJi%wG{?+ at egD3FW#Hm?BXz(XEYVMdn_?WN|`fD6A%%c<^gG>MD
zJ<s_RB4-F7^Q!$Kq|kXbUN8Tyyk3rz;8!O#pONbrf-BcoYXx0gMZ=)ZPGG;BU!7r|
zV?WC}PoHUv7en-Sv0qPS^E`aUf at 6WsaB2vC!;L at JKB{}F)}g*}&g5ZE=E=&D#Nm2)
zv!7o*k`ooLiSe!tGQK-^DCS?OTt`0RAsP2jzc9|Z8j~1K{AOO(fX-lTXe0B<JSzUg
zev3DqFA;av_%hjl#Gl3$W957Y%!fkpL!cqo{dDH9VCA0vneQ*~zGJ)3JM_KBS$tL)
za|69z*<1Ycqh^Q3-^p%aM{^c5z7DQ(4xO7V-UJVWf0zBk^IJ!qr6TxT3SNpViYtm!
zicpFm3JM5Au|XjqTp?0ju0rBc6+4%x7~pyY#swlFMe?~S2F_MNjqp4(i-9vFN>BfL
z6$C2cDfmxyK_Fs@>?b#YZ<5I&5WOd8fg^Y=aC|`<dH2XbxPs$A1;`dCj|C)K;h1!C
ziUeLC^XHSH3q3&0k at t;z0}dQGQx6&$I9L<w9{VS-XVAcQ*bsYSR|gD)5k<Cxg^Fs#
z4dM{-f>`kxONbyoC}1fLDGGJAS5sh8Y^w0&FYo)AU#7x#zqoPn3w7=a9tu1 at dx-`(
zWD%P<x4oW2;sSvo at yopzC;;t6K(RK22nD7D(#7Hz^Ie+jWDVvd#Ved7pyiscc}-$R
zqUSoG^<S&^-h&EkuA_OuUI3hCPZJanHSQX)%@r?6IO)0rG!ZDe+uT<ZSkq?Af9+2+
zukH8N)>ZnRYnhL+*aLg9-^l*hko~gnVaKHnDXwXtDcBn-w9iJ2N%YreG<UeJ?!gZ^
z51+T~nl{y(%suR>HF-bU3+oL#_H&=s3}2iqG#+bYO=l}%?5Tu7!7u)mZ^O-#RJ0Ii
z%-i(6$*;aFz5 at yn{A%*8ct80 at z1|LSPe=KyUZ>xVf~)&hA^ks~b(XKqd`<~l@#&;d
zbm4zW+ at Fo4?Z##Lp_8`~C^2vNBceCOF0m2YahBnmd1mPkd-*3*<qHzK7x8N<of~I2
z{6X=ze8T>V;7wk-5mlT_U*<EuGylb9`*Y)?&$sare{=(P_;uqYoJ`)CkBTwuCqSbh
z!T$0(?&<t=69s-Q_R2a2M-kKPPwSohF7_A*f5b0GjABnJZrs>d?1 at 5W!^dR*+6Qa)
z9+VR~qn%I<IbYAcx!2mKn-`iV&a?cm;+xL1 at 3YRa_Nl$~SR66!=i?mtj%#Ayic`9m
zW*+vkNEg^Y<Hy;CEtaV7%hs3C#AO}g6C7E$xuDM+OKp3_PhDTOhnF=!bHLqUe>lY%
zz^UXDaqFBf$^O{B>|Tw8Y%JkFXM8>%7y$cLG!*eQHyHr2r+`2DVZt|@Bk at z$8lTCU
zW7HiWMAS)$C%wkUdEL<;2)H)sSjLM5dfnj~!>ITZIlto6h-<BGs0K%W^7^4(WDE7H
zh!A8^Xio+9;we6$2wf>^*Ph-_g1-snhBZMwL;rq>F4h~?L_HYStc}%?bI;anaX$(B
zZN<F{bc*n>T^ElozGdrCbZ5a`XXSiEuF=_Y-o*h6zU0 at a+sx76t$Cb{?!oWOA#>#C
zzP9nd^Il^IzpJL!8j`1jhj6cWx5hbmwvC{hb8WJZg|_(?0)_^OQJm}CGZyyW4ket%
z>psQ;o};*~briIYof`s^u=?O1vB%h}_gzR^l)&nZMc4kEeVspbeAXA{LDul*fzBgh
zPSy^pmpDJy?>b{Y)KJW;dchBVlwaxrk8@|`6Xg<OxE~rQ2D`bd7)_ptI#~6b-cujY
z6u6Z7T``$^8HX6m_{_EY3+S}eXmChtG<T9WgEQvJ#FuIo&0^AwCzG8!S7yS0oY~?$
z*HB{nNcq$8UhY|mldGsTZJ at 2a`+>09xJny!yJ5$f;9oQtIfLL~)W5~Qib0$s=SkeL
zR at 6CP{iW}39d#*5n*>fVp at e=p5Q#2(@y)IMDhen(N#gsI#LrjqrVu<wL_A9g`%EQk
zlJw~!E5T`(g4d~#M`S()5nvL1ed|PofJEyFJrD`U0f<%jt03920D%D6Ix0yTBA`Li
zY at a!p<!65V#jT_BZ at or{m*aMfMB9-`_d`YSBKbfa$b=6b2Gg~Rv1<HwsC_M7Ck+RL
zO&+lACOcwN>}!FdA_x0(7Q09m1QeYUV(lynRf<zN{{`QCW$Qu&hR%3Df<k8w2d<>Z
zqsWwazEXb=sMv!agA)oOh{+2jD&fTi3MS?T0YxHaCKd$di)KIy37&dW1X7Gk0I-g|
z8fPDCp<vh87CaP^6qIn3t|i4LMdw(bM2!HPKx4lG9Jo5+_xhYY98lqEPU}8%T0Fmu
zLN$w3#=TVgVNXl=yMeq1*jJ`?3|nd5YY<y1)`8c8?N|f$V{VPbp0Ib=@5kQv1&C_d
z0^4Axvn3?XlCao=e<85{NriA0#Jg1xpFu%f(AjdnpgyBu<~kS9y3glMVU1WpkmXqf
z2VV9WmdFeqNKmBBIQIZC;SJl12H}VaS~ugtE7r>VyA%uHo at 0OtkrP#f;P>`<`+4|w
z`0nJ7o$G=00ek^8{}?FW={{w|`?<d*NKPA{=RNrIPCjYBoUb$DN5mJ$sOFoap`iT}
z1H(U6oRRn`*zi$`J_#G29cNbOg|Hmwh0p5D5R`dl_TBOqok^TsG<Jp`BN&UD!d0(@
zZ<Jr)S8=AVk66#RjK7y6LB44}o%#0U->hwk_zpjx`}zg^x<F(0hE(}EYk*(Nb%#$!
z^TKORKcabg5l=9*f5#wvNb at lN+<)XVvMIK;pUBR{#M4x4xzNdcMInBQif1?*f>F7v
z{f*c8eThrmQ)lSL4+S~#mb27c)re&ctYyRhI7=6ClP$Xc5qGhJg+FnH^UK(VEga9V
zh3;`o#vbXHjJx++vWaZ&^W*G{I=?!f`576AbjM|#7tmNVj?FpF4&D{upXQ`t%N{PG
zIZVSrds%|GG2!(@G_^QSgXRrr at 3}5MkG=Bnp<Z)M9}7Fwd=+OmIGr|O at 0`UsG&ALE
z_?#P>E{2mc|L~pQOXmrENP$Icb8RyOR;y{;<jk5S>yg!3V;S38JVS^WE~FQN3%HPO
zqH7e=iQfZReAd&bwc=F>@n7P&3;!jWs9r%A|6JSOZwKFNfu65Fy*BS$yc at ah*<Ln^
z?JBNir)Ik$`l_hTcwaG|bE=p=;(5h#ox5W>ae-Js3_z5NE8+V+_hyq2-&gItZH(;T
zGyJuDRo8Q$8)h2Ed{sQzj<ZpZM{EktW>Y>nyTRAY$-&i?oLqHq at pH-1#?K9o3WK9f
z^i2(dLY&ofZbyQ4e;cpn81US&j^)~7&9(lC6N4AVwC^Fhuu0ly)Bwvmpw|L$2dGZx
z4BULoyh3bo1BfP%&ae362L?Llssqdm=Z%*m|0})`_sE~*M&}IGoz5A`7guM#=R4<l
zVxnTU^Cj_5u at 4S07rZ6bu@=WTxI%0*PZ~#vW#-2h*SUeM(tZ;!{!z9Dliin`m~#QN
zb1t9$zXg45#&Ye+y9M`_{40N1<sG)frY$B-T$}5_A at u(`G$7|!oZ?)mLpW#R2l0h`
ze(U#N+dAqp6&jbQh`2~3x=@Mo0wu}wM6h#2HW&4}X}8FM$ls;H=F|)-CoAYd-V;UQ
z69_1o1f$5Gk|1LKn7;s#1TDY|MW7>rNf!8!A;T0fQh!}U+zte-fik*C3X-g=L98$i
zQwI%-yaf|r8<O~%{(3@?CCARW`urw}*67Zf*Pi>y{g<sw5C@=a5YT;e()!xgNfa&=
zt|Tmi4MnPg%pQtUk`l>B!DSysDTS1R#-#{f#2^JYVzxjLN at GCZU8(@HU)RB<O9(Ux
z?!Q=t8h^*<T%&8bem??)LKZQC(5yKKS`@kfA>H85_+Hmt<~4Bdw1)k;2Ijp;g(2J?
zsKRg!<2s2U-CJvAOxwWgoYr at MV%!1+yyMqb>NBq`3v}B=<1p at p3f6lSw9l9G;bSEB
zvuUO+{0yOT8i5#JlM|mz^8PHzTVlErxP30pwft@;_&ToFeJ)xxj=4af&jb{lh=$P+
zq7*Lh0%4$avwj!(+K+97eXzF>_SQZnL^k4x#&QhF<^b`7`B?|+VvW5a2zQAY5i2qV
zBv$>r`}895ls^}`Ppx6;cO5a-{~3QPU^DMn%kam^Cjon5PvMs<1*Oj;&q8M(Vv@#=
ziaT)wj_lznsq6`FTu4$7Al49QSrBjraIX9oK3<84MnJj=@V5QP{-f_Xzl$ZX at PP{@
z<QRwZJ6}bDd8(K&#F9XqFmDmsTFbzffj*-^MO5YWQShpWCAQ>RX?)QDi}gypX}uP{
z@|)Ru at u^xX{-m{rFGcgrYm^OwXFs%k+=vo?Pyd1nntzaZ`}^Rw3mfOH$XzFWMkt?x
zhvipFqQkfNy9D3chY$feGoC7^A6X1EUxM$^oC|;A46&7cN;b9F=IjvBvOnj*xw#>4
zJ1Dj+&rEi}->?JrtC->@tj4r0IEQM|YhL){Mu_dA7_)}YgKQ}Bq`iTCOkiI$Q3}CV
z+xT6=jTpvCcx=zPXllZL8ll=tHB;Cl4<pV^A?4;pHj~Y*jOmvsF2Ng`UGUuvP4WyN
ze>Ho;f5$G_l5v^Cjijo9GJXY*sDH$pjKAbr*E=f8N<?-4Ulz$DR?XtoJl?!N>x|7J
zd0ATsYlUhFex5`vh4Kz4VciAx^0S>#*Y`2k(bhWll6$PWs29-9HY2uY{2eiPQ4fK6
z?2Vde<V9j{iLt7UvMI}%2ls+=H1NWA<!g;^j=eO&vX;0wW7 at 2KfPV#QiTvE)I$aOA
z&+!=l&he<tsmc7nfVfxwu9)h$T=7_ItOp0IyBeSH)_w|iM@^COPj#W=TH|rpNP at 5U
zO#PnuxZ8CAZts+ri|1Lty4D7b_wOc0|1yX<`rH9O`R_Sh2=U)?d-7{)0xWoz!Wa+(
zf^#$iR(L0yyABhAd(lXW+%N8B{BtA8F>f>PJJx0HAkM)p;u^Vvnv~o at P0DBR3|=~C
zz#;LMvB*d8g&YOvBfg0v%4_rZwy4WmeDm4Y`RBuwI`7HGn`iO<7T-3s)OK<1u-NY2
z`h0;t=METg*r>H9*vn#Xg*o5SF2$>^;fhm(O9AtU#*2J$Su at hqE8dVh%@^fKH;v$l
z;sf;sO>oXW9xlYg%X?n?x2>c0>WlMq!MVEdERpL>-MCw1I9+5oO-cAv4SKQ$Ct#c?
zLYyE%951nNLKG<+B#Ibc+WN4A#AcxQ5GbM)SwM5H4+6-O1R}T(3?o)IX{D>QhCHPA
z89K}Y2Wt{El8of3<djKsncR8 at daX<SUNO4cZLV3ete=yx&Q8uG;6ymt$Rta<V&irW
zPKFhbAd`z(8Urd|2|zk?65kmlJ_Lt&agGYC^LTQizyW72Brz#TT`WRfqM)-M5w0L}
z83pQ(fQr=wuj_ri-gwV_+)toFlmH4df)=1aQ(|P!67{TMA5cKshj0;Co1p at 575a{1
zn|rw5`v8oIfEAd_4GPVFDFvd|=DkpWBk)y>UqMjSd#_z<X1%P_V`y!Re?b=JA%s;-
z$|3g<Y!%G0EjFeJgY(jqIjIUt{7Vi#{7Yv=Lno5&+^<G6tbD1X`PBycb==>^WRBv<
zvHU8hk`_gRlhvFjyLrM{qDDmt9AW=1V6cbmiA`w&@gAFBptHa>=gKw+#SOcVh?EFV
zcCj)w8Y}J`E4#2h?9y#wd(_^u$X>>e9xuQ~yx0NDdjlDl>~raN-S=eQ>1jcnA#u{h
zfrEPN>G-rSJb({nV+*44N5y9Qr0fNs;8ite;9J=pdtb^w;YjYnS9p8*kKgiV_?Uf4
zyq|Fu;Uiz?Oe}ts4>%Wcg3rbRGS0|I(YULiwHkUouF>@fPk2)6-=kuN at tKF*a~@A5
zh%Mqp#Fp?u)`@@F|M0cpZ*R)q;M42Dr|xT7fA=-!jde at FX<et{a}>h at Ha5p7cr5C^
zY5N}zE}*%drUK`bXJrwKc-367=iD#nMI7ztMe#;6E#qj#&=G5Lzr-MHG0sZ&VXt$)
z7Uwj4hkeS{vB&r|o{Rn3mkYXVx)mt?<yQuAM;s*f7;rNEEkpqz-$%}OF$lzC!wvpI
z#i~N*f4%OX1x5j_`;V?)_#r?Xiv-PIdCTk5IwOBoLvxBv=3t%ye8W~@d-(}sP4>jD
zOMbyQat*xVT8bzNZ_W`P at PiO|BfFlcIk8*Ws29k!zaEo_4I?Hk;?amRRj2eE4 at S|N
zH9*IxTRK|JuoE`MYjZ8v0J46X748GE{(-))MD4fsU$JwFpF+=5t`|2s(_^T4k(`Jo
z-3lk<@Agl}CYq`tlzS|4odZWQ9uZfFNmD+PuOiaLo2f>KhZpc@)C$|-m55)4?sKh^
zb&i|pnIm0~h<|X9dL=}E#5gxSQ~VQ89IM4o3psIgi2sV!iqYmQF at d;8TuA;pjuF!;
zE at T|QhNA{aZrktd|KW?_mvIL6*M at aJZ{R%f3nS0Dqt1VZDZiE<l~8|AD6Y-MT$y*d
zHs|xX at DFJ36}yCrU1hI|TjuFT-1>%Nb>tC=xytz!znt?kUlvEjg}u*{FIy}V58;^~
zn!To+PaYB1XhJ!EDDG9BbnX!ML+`a(H2DAr>g;{qoO3(ZwOR|izN@&l7SBd(s`w==
zwb0N*i_iM!%NW;RucFqa*8}xgLhD~`0^}ZR&xI+z<%4F~Xf%{MpO!pI{<wK$zsuMr
z&P1~^VjA&`2OX{rRRf&GKWU^nL}OBM%Z(v^!7L73q1ulJ3Ou;vLBj3QX-Dl-Ks#T-
z?K}mSb3_UXr!z&gGc?#P1&`4L5IIlOq$gw{eq06z7vdtv(OT$-6_CU6zZhb_NRke2
zaSue656B3S1Op}J2U!v!+IJvMKV+ec=OumvShQ~n_h09yYTNu=?LULxSwa50wEy%j
z(f>``z{>dj-?IJs>?d*aeGRf>k3rP3Vb~RWJE<n&hTtPe5ugb01SJKe6De>hY)P0D
zvm)1S at c~}IkF%9{&Ls(vAQ9apDH0aRi$L=t#kug(Pq!{ng1dwQmLLT58u+t at i*+5i
zNXd}<V;ljI0w~B3k3e&EF!w%0H}F~t?Yg|zYm`GU_QjfuIho&ULl`M|T4aC}_<Y89
zUMK6*dM=dTu<!GgoUsG;z%FMgA at 9M56j;w7u*!C)$wBcU?AiT at Mp^~fV^mZht>SU=
zq4J;fo$fOVCe`@b)>k^Z-wb|$cF$t02w<AS^JRi8{uFmebmmVMUla}mC&Vk<A%V#T
zXHr~|v?yL^zEDU}>`?fm?T2l3E}WBXs{qD5Q(Q`$Dk=5`0epqGWly+VF{w8QW-*C<
zEMijFxS)L--R||-WDnb<>;gD1#xEN&H-c#RSp at URUh+4dAP>R+ZS#da+IHg69*R5d
z{~Y}88~B~<h~Q1%Gq2&ZxO}O2I{0gZzirxeiuZeTJ{C7++a{9T{8gcNk~oW<Pekyz
zPz<;k3=}&yP~Wjn3QO)2KN#aAVhqJ6amM>raZ2N$?;YW+y`L?gVy)gcPr=x;e0qvE
z>B}Hvk3T17WNhG`3zX;ByG5PxitWkR*cOiBzu07F#C2Sc&vSpB3*)*_*E~~fj9BEt
z-tnicJOBE#JRk1!8i^@N=FCZBettgLm`8*T{s*tZ2gu72Q|tp^6z1U%9m6+(b9SP5
z4a!$Q_mT3A5tlkLj?CV#p<k0l6KFn%FAkq8U;8tV`>1$Cvj9KC7UH3OEOXkae}@3f
zxP<VNZ8<yqiQK_ikh7c*9G8 at nlrK0#uAvF;^AI<Q?eKNfM?4^rPq;RckJBhQ`Y&Yv
zVfV6Ytbb-l?en)<9fVDKJnqHjws9V8#QJu<##zSs!cOPWi`YP{cRH6jW`e5t(lFyx
zi<jdZjkH;wX`Smv3<Vi$9FrVhXwoUR(A1NUkc%8&6w^jyGGmPE8bmX3R&mfmTIWm5
z!S at _<?cdR)3?Ek<DnAFr;)3GSc-^k4`_5Bg?r~_e5<4_U#GQ;Sn&0tQ>+!nW*o!)X
zHM at z4SaV%IiF#tFMZI`9kJsYlh}jW`D_&O(Z(vV2YebWe_<_A`cj8Fq(*bG~xIK$2
zpr7NBVIFsi7s-(|tng|L&dp$LjE+8MttZzuVcMfbzBxI?8`sdqOX3ckB=(4tClP;&
zj{@gL9Oo=YeZ9!_#2Rx=B7d3l$Z?KS)K3ZCJD)i3Dd#DVaK9h!60^u5#H`96;tK0x
zjl~7mP1;wTW90yBY5#VdYVoOJOU0X^$)rh|Mk#d7RrvLRu6KR~NKIG&?T^DlYwTF8
zeWTF;dZS at 95`^A7kbNAx(`FT4=ZyjJuJg3>uDGVNDSqL{_%^;?btAFC4;*;dpz|hX
z5qq51#0fY;O-O@?zqd=@9Ce|K5fw}n-@=6=&^~>(mxLz*ovQ)PQUE+t1Mb$qr)vTV
zdnSa;L(F7T;216NXf5=^ZV0qS0FZNiP at DTek_mBvArPr$oLLfEiv0hAz at J3^B<SM+
zCn5=*2n%67AmKfP`KSJ7fzLI>XTLV^xj8<0IDB?`J-c^(yxBU&8uPz)n`@twJjmM{
z116@)2myt(uNwj+agsEI%YbKxC#aKPNeFb&T{tO`Cc!xO)Bj0{lf<MXh0r~VB$my9
z^C+$<vMFK}toDBICtLdnMx)?`V=Aa9stgGe;bIk97fZNY{K~&=T_R!{yk5S~*Zb?U
z_X3T>Jj{2I<{fKE at yUAkYV8+j59hz|n)hU}L at _RhV!syn+W&3^Z2V!D67#9}gaphf
z1XkJWBnA5u99$>gz;Q_u_78$=CeGm>1lr~wy(lanaS^u`bUVslW?j(!x?y%NW9672
zi^{>9L==CSWHVTG4pl?oI43|QKN25Bn2MHNN<e3j>_~L7<+&6^h$Y#3FHdtT9u+SV
zJ|lh3`M at n=Q=JRr^!UUaj!`;~lU4BhJSfnKRTM<xwa-NB>qQW}j{+z_ESsQW$cXp8
zChs#CM_}A4L at B%|!kC*ifKw>iWCzyAI$7 at -JZ1mN<WFZS at e_B;pTaisBYX&+$`%)s
z at WtW%G^t*Fd+V~--Z3tH?QQ#qZALtIEYBvdic`itTk#wL%Ne+-qVvG7-SCw-!q?rb
z+OS&`l54gb_5)>~74+)|7>6fL*iPen9*S4ZYwir&(Ig1lxfsTFT04F?;!%oneAV2-
zjw;4&ON4bH<CJ4n!k@|KC)D-aD=-G}fbjrh3(Nz~(Ye{SntwC`v9V)?iZ9!F&d*bd
zpW5d#mtq at iHj1)r4vu({`E(R#|21NJ#EXje88bk|jb;4ks2I at W!dl$OJaagZqw8<I
zK2k)1#e9{^guYhxkbCPfs>i1)rW~Irq!2UmV{B{D$kR93-XalksPlnOoE_)MIl~P%
zlSdwVW9!16C&UfTf8>TQ{V>j%yr3~FC-nGJ{!{+q*upt$eUTgDtOI%8zalKfjPnrl
zF|UPQLhG>z9I-Fr-|%PF-m&uC%+EXEcZci&?*qhui~|`*E0#_mHVDMl7GDdTC%%R4
z9XE)(8GAVsH_;6Fp at 2UU`}}ts#Ptap(4fXmc)pCC16m*c9iluNb{6G;cv>+vZIL!A
zTLw42;`4}x-jXAArYq;&MK!+A;Mf7k;~m>HZd{lAiF~WQjz-T;O`oVU-!ryZ%aLNX
zXKY|JyQG~a8+M-%WM?-%WcTs~&ctU_Ijb5^I at iiqa1VaK8#ix=E4^-3o;ru75;=-y
zk#db=jN%G)4*8utJ_9u}HFMRfstJfck=I{w-gEq^x)jceldQ*_BkqV_=2X?7+H3Gc
z_L7bKz+>pL%pa92$O{>dD at Jz>Hq%~RX92X!&@$+)Len~lNeh)e+6i4d#rv+=*3stO
z=KmsMEcXDkH!$=U$VS7Y#X4lCrppSmdc10G*V|J*8;t_zv-BhLxHt<(lbhltoODhT
z7u^8WxpV$*GKmlI02kgxUb{*8?5NXKnCup5_J};^P|%RjM67)j;S`Y~-bE5j7m9cn
zh at 5=Sb$e9k>{fAex{8`pRXCokiB8gl6mG}KAqf5?3la*BRE}nnX(I%W-T)Xy%8Y39
zC;BCFgKTMhVflo<i)JGadzCmP%7<7lAlijb{C|X+znTZN-o!-mX}_JM<&0&siFgoB
zXa$tXmQ8^Vbb?g?B<MNdDLIpv33Mbj5-Z72h0ZP!3@)4 at k|D;<6wzoLokd`xNTzUx
zTNF(^>Efx1ICfz*0>m-6cJYtj+PXx7X1~Nt;O(tTUVF=*Ukn$`M_r$y at WPjV>T&jp
z%<z-3nWKvP^AJ81Xd*nkJ)89)8Wnuu{GNaL*Ie(5TW2UZpMi+v=?(!@I8DLZ;$Hhi
zys>8-YX~C;Ru%08SMeSjnfn5Ei)L6Q>_tNif0z~VApJrJ(cgT7^D=aHoZmp6X`uqk
zcA|fYaj(Xj1tTH(5y&P$1|<C0Ylky!Pv%VqCG$o}=Xi=8ctf#9apvS0i4lA6mhCwM
z&V#ezoH#Si&u6JK-K+DRIFr0F4}Rv);KE*W;f)y&&ZChdA=f!@R&oH2!h<uFkl}1`
z0T367al0kX1NA=9u8n&o`rwpc?kmuq_08Zv^Pc;>eBj&SBb at Y}BG$s&y(Dz@<_1~r
zi$;}w;@{*GZ*A?jUxaU5T6q2E;V1fzYw(kb+2teqR4_39<R7vJcEKj{%V87NTlPp>
za4z-<<q7;7pRiw4(+j^)Q9XR46~DxY6Y&$ot%~&%%3nY>6yOEEGe^Xk;|dhV1MyiD
z&HbK06xAUZjL+8VoYU{~wW0TQ&tfdkhfr&UdHHrVh35X<3M!CAX8DNo-th16Z5LRD
z@^AdlzL<WAkG4GMT-cGtM#TIqL^3z7<;PW!KSthMBJ*gy-==WeM9)>c-u!<4KGEje
zSZD4h_BIt+M%reU=dfeuxr${YhAj)K5x3&3Ie+*8f8D?o*Q0@{LSDYHhbOm+Blu4=
z>muhk$9*q+&CSXYhsZ_5q4YV$27Jyjqx?;ACj2e)Q1>|+NBEt6Fa2*v#I at YRy}M}g
z<yedx&>S?UG#|cRajwTT*5<ejh;0?$8Y=D?x^4sgbM9YaG2RTs=|X+ByuZe_9T#z&
zSe<c<eU at FF<IASDC&E5rnVU8l%N)nV0mm<5M#e11hZYw~td~%COc;5;;zIsi#0Ka8
zQ3F(*fTxjjs}`tSyb&`Dah+d$7`$#6 at uXhY`y+*}Uyiv%UrVm9);nR^%WwJNMj?FC
zep#T#*g)7S8Ven1$HER`zs_MM_BkhnK4+&hbfb$H0662SeVtRjVLrG9rj`+3TnEeN
z at G-ar&uIR_NBD}b_j+bD^p)%V at Jl)S67oFxp8Q?8o4ifVu6$j&TAVkx#cTM?yvz at 8
zONW`GDfpeIw8zdr>|~o__vF^#6z9pgD~`@`&O(1}tGyO6eWtlOmU;^e4W!RM0orFf
zp^vdGG~PCAsXSG=YWjS>mjP=__8YHf|4Y(llS0qQm8UCrFLhevFroaf`&jd(sTP+H
z=seB&<T$*J=0NgT^%C)mnhf4v!T$x|WICb>fV&8Y1WbY}#VU!6q7)*kumrs3Gm1y9
zIa4G&T_itEf%FuS?<5UMkUUNS^4S0RFLI=402JvyDAFM?e at hE~e-=O$D2Av}p!v-t
z-BjTGy^NIwPLU2^*dkn^9Z($N;;;wdmJm7CNcDd!Hb`BFJ<l2g09%=OVaHj)RK?Pg
zU?d-tD+6i;PJ$)fP?8=6G6|8Qo=!JUwCId0p~4FanKLYwR78-##hY^!$Si;;kR*D{
zF at l~%%*7Hj7fIw?Bq4L5M9e+~NUk}b=97vl?&E$$70rb`DxlyY0uDiThHyGTQS-uS
z)^I8!-br2oQh^%I)36G`5&`o>p!J_niC$n&$ID?5DMN at z3>-^P6)Xf2aGk_~T|Vq!
zTLpl)KPvzN_=3ehAP|oNK*1Ogl#MB2RuUaP(@}}{NU=6XV$A0PB-fKXFi5a~wU0f;
zK7$+DJB5&Jf^96KWIt?a+rkr)C-$e{qFAL!RTAU89E%W~6l at g4#3hP4&ROw^Gv7n;
z>|`h)>=CjgNEPA4E(=^0-g79Cl1!J_?(>4Uw<CVI#2b#27c}fegb(~QK!P`Z*8T=A
zluukpqbnO at 0|<QJm>m8xhkU1??|q#Li*dik!>>HPFwL23$|edv*VoT}yf5}w`<88n
zZNCe`_UEd|v5)FpIHT^T!~y%L&UW~x&K?fHg_Fbyd=ZX>AAZB}1>Y;53tv-i!PkcP
z-p0>B`5Jy!zNSL5`&sv~;S0lGGB-ItWvnDewI?AXUyTB3fo0xG{HH?YFBcWd95%)E
zDb6>n<+6^o{PF)6%=VJ|o9(~yUCVi8-?aC14tYj(X0yB}jI$3ez>5*@hJYZ(WqcDC
z;UwIQ2In`kxQe(IF)c(k&1E+X5vgCF8iS5q-}!MgDO=of)1b!~Am6*dkWZE`HgrGj
zz6;zK?WkC^{9Fj%U&esV?`N+Uv29<)65>jaEe(!&Yo9Hy?{N|EFlr4OaV+=8`mtZc
zs*F#{7o&zyPN9CFP9ZLFUQ=A6R!C9h+8~A1A|5&CNkH}(G-6N1oLSrvzqX4x6>BQq
zIMys4hAkm}uf`n%(V at Qs%l8Ycj8Ot*Ky&u>1Y)hxd}HlxA1if7#oXVjCP2pG68Zz_
zgR{B=yV at U@$UHzZw*9Jw^EsMdQKY!%-0I;()hDiFt47gTlZVhWRj0VAhELN>s~V;J
zn)(*)lzx3KJ}qCSw!mlMAspSv=fHVbe1)gvRB~w5xEjxOkH)7tH|knyT5_i9Sl6%4
zm*mQ?1uw~w<VWp)#>eF1Jn!Y16!(gAd9E8dZJEbXV~iX&;&F-T#7;S?u$BXMgvP4Z
zYvax4T%fP3uX6*npCg1D0+EMCE=n5>n+f5EiQ#93xsOeLmA+LzWj_jEBBn$$p!{U=
ziKxp%v-y`R;`;u7d|~S-ME`CPY!AtZBt*e0vYs!p4v3iNDtMmt{EuCLbI++F;mLA_
z6XhHfYsY;?qF;_gQpDMCKnV8%E#kMdp!aKG2nv$xAX^gdH?^sy=qFj1QMN6d2H^@-
zB(*|mcIaya0s8LUbeguq#}}^$J`?yv{$2ZS4Sno)i`sJ%xG-#1w(R6f+xsj=VH6~D
zQAE%nc at dCD02aCU=N?rM at q~_M06~esNzg>pkyr_o2)N|hxyiK)5G05d3788dZuTl5
zp8w)cx6V`2K1aduECtgub<de9oX$|9W*o+YgN%KOc*r~_OWdENfOsN}s1gyML&$$q
z{7fO?<gFk{0vBHcD}sKB6dnEjhgYGX3n&O&6v!6<ffy`=ii7eJvMu%vOv%q6cpoV!
zHWr`F#wsvJ&bM64JgEv!sFhT6uiAIn<rvw~O(A%Iy=kCOG^Ox2FG#EuRU|K(F`w7j
z>HJRlf(kC3r5iRBU>%$_iBH8 at y*`yf&EWG1)Az!1oK-MiM}FpY)cfrb^VV7dyGYb<
zo}U9#Sc<a<-!n+$G^^aqkSInNE6L*%7RwZ-O8)TPVw$3r;-8qTqV at vCWBg+ug+uzx
zMX&!n{?eq?=X`&G3JUJwUdCX&vsL(>m7<*aXrg!x2y+P&d at I%%>s`axL+%4XgHOjE
zqABA&$iKY@)=yF6rbz6;;I;CKeOyKPS>JwDKK_dB;-<1}XulRe?9cLJ_%zEgS=<bt
z5toDa<eDgMM!u<>;{xYh<ebbq%Y4&gY9Qn705LeR7N6fU$O{SQ34Jzl2CqBn^Zxzv
zvxbkYd{&<y30Ch}nUl}@=c{Az{qkPDU$sf1+kE7|>5RttE%RR!Jym#(Jh)BKwVD$%
zmX5et at sd1H`4PcEBN?$lo}3AdZ###%A(}Ce*s at E$U}1^?NFNOUlixXx2o*;P2;1_<
z!@#k?sC%aSj|3ivxT5+H-?#r45HfzP*kkB>t~2VsSjQShTwDY9<s9cA>a+Rln8U*Y
z;%19G6+8F7qWGzrW1s%|y=z=uBcVo<fN>ZbdpaJ;-mW)v9^@z<a5yF at pCK5jDad<{
zOXNfHz3Sh}@0G)su_ at wHa%sdSaV>ebQ+zVS+gY5-SXG$Ctiz$*w}Bjc*&MJ?Y3mEI
zl0IX<DW4IB&-4cj={rs2&mStZ+QW56)>QaX)*Ke{)NiwzBYmsa96B%RjqYPnYg7)8
zoL%|4e9ZpE1Bc|fxh$^vAw%Z2;@AZ=ox~*`Xc^{M@=Tw at zlmqc%j9Hn7p^fr^N>@W
zf4}@gtw*&EoU8g)yc-R2#SPcB<V3}jP5#Md$-l~tt{u0{jd at lhF9!Dp|CZeQ-H8{2
zCreH>T{hQdYamt^>izPX!()hWBj;bP>)k?otG{Ef+o5c-Ks at p9_6ziUGx?CP^r1!W
zDba5q!gtDl%5P|Xi3e_Yi5G5C^XnD)gCEj<;X7MbeD#N0N1Z3qo+na*a}+So7OBq?
zDR+zPrz^pnCL*395}vHUcY?@wyas at D$H?J6tbsqI32;saI^nmpi1*8(S=d_f^_!#k
znl}CG1_lX|&5W0Z-6@#;nhUaClr=J~6=bu|+BIuM#k)lnDWibtSQa<^v*mZo_d8&@
zhK^Y=1j<n+`*rdLG3#t}P9&rm`5>K8MNf)GCp-ipL78BT at FVaNa0#>oSOP1>3dtLR
zfG{91O0?{I?d`3-694BbaGHzyj%&Df_cvb_7hm%Irz%LBj~NtCR8Tx21;4q8P at oe^
zL(0KX$@zZ)35N`l+kv&OeLjQ6I7SI4puk%o2pgKqXx|xeZ;iuT#%l9GJ_QKm0I>t=
zec>;F?9P*i<#$Wen4D3;^R at Zgx>zGg#mGHi%VX&<lVmf|+SY(ZOD5X^1sa+_Z~!3o
zPa=^~L;=oFI7P*-p>rkS4Rj$7^cmL}y8dKf9)M^foJ11{(dap!_Zntv(i)E^dBT(8
zN`Ydoqwf<w`S0Qy->bc||FS{ZLA<Q}v#wZU+pBy6KJUuH{&W=__74 at ***@O}@)vV4G;
ze6C_MesMm+UIj(@%svVKy|2FQ_cUwIlc+vN#l=}FF1R02eTIwJmmJHPbLKx~r)C at W
z6ZS|S+6HqDwDadzH8gfKK6~ZtPNT3wv>;UQf345{|C08U`zhaNzk4JQShv^AdO!by
z$7U{k3yzxCDiED_R5%ikh)e5vCkmU9b4EcEac{~mijBgQOIkj099_iMC1$a?$Mp&S
zPhz~6 at cq9F|2whW>+L>UyMHGf;dRYcn`ri4JCDN1{lYeRa8}?^dt{L|&xrvS$>hdW
zkrTyr&y$fW1#vZsv=B9L*m1aGE^*d=we+dXrEZo++>00zapW`!)Ln>%Y&PO+)Nl9@
z*sZu?-*aq<_|mZl5i$@Wp7>FqCNyXwB9P_3;B4@{h*9Sdr{vQe_&DHuBkwa9OJjNt
z1ov2v)`$2;5V7vu!+ at KW3$*WRuhb2-S2q%9KoCzgw_}flTf|hw9|^U+G*4B7?BgNC
zh)2Xz)x=ecXxtu4IR|1LXH<fWGjxupHYPV`lagAA`nclM`~PSqR>3E at 1yp}+#;d at x
zJ_bA0$Q9StKU?{ZG4*%m55oLuW%Gyf31O#Z*{B;4q^rI#)gBi0Jg|{3%pM>pUsZnD
z^n<w%zy~+SiU-AIcnc2@;^qSRHTZxgnmqs&4~+g<q4bluWWL)ElHbgu`HItUhxOPu
zwLbjyH06KRK60|_mqkvleC)g%wdJTGsoSXQuwNJb=9{>de4B*-iuf<?ab``Q%^Cm;
zEcv*^;Ah8zOS8|`zT1GtC0{#dGY9Y2=a2QRfVGeHZv*zIzuqf<>-D=t_(UOn8r$L@
z<s;=MGhYFjKkPG^Kk%8-TY&R+Lu|?&aKyeM?zrKlTtWRryn=Ub5-YyL{e$BBQD=yp
zrz>EdCPJPfGM=o9Po&sV5qF%5L6XtY5-%>eM6?fzXfC(_VqXh;A4S)S;Qvh}#oyEh
z+4OH{^F|tHeh6`paj1FNjTGAlwg_Cm24)3YM;32~Ly6=KP&Cxv#9D!|6MB)dgr9``
z3a~csSbL(`WupOr&C7Z6j5se7b{5Qa#*mVrQUwh}tl&)ngD4PpXc(PHu|j}`fFx>y
zA%T%#$y0tM-t!UuufFBie8zWYilDni)YC=S(-kyN6M0Wna6g5ltMN|KxaO%y4p(V5
zfa4S}nVaJ2SOrbi0*8+wa2^&-;0$pWg_y@=Y>;!g at qoZ2ShJ1-O$myEj`6+L>ic4h
zj<NO*2mcAjZa{lnLTfkldaQp97Qu`8a(}hQ!nDuaD at jWGI#CJBKz!>=fD;)&pp)1H
z5*%k&qW4susOUW5#i?I at aqCniZDP<IDzs*Z&$-s%UdH*NL at m5fBCYwD`y`69;>qF+
z%$Yoc+V42uVUKNW)IZnt-A+E+W~XkOvWM+}4JZJ#pIzD;96y}`0sj#1_k1Ud2>gWN
zf<l8LM1|=E68;xR_ at A%8=l}TM+(bJ^MF`jK(LLPn2Cm}zF6`C(27hE-W8c~bJ_7e?
zl;OWFEULID{8hw%L+`=t`@HAq|M at R&fH?-hJ=w>8BKzA0S_A80&u1V;hy at g3G&U%@
z6${ws+1m3S2?Va;>{&neV^_HACIIVD-1%TN0mw(rMXkUg4~-l&&pnZI6a!n1*~ldo
z``6-YVHu14gj?ctfmLyPB>3pcXaAmHz8NIaH_*S+U*EUG_d8wJ=iUZu_I&pZfXagf
z^5CZUnH8dy6RA at wFIH}x<;O*itUO8KO|GO6=SiG+>YSN^hX*M39U865LC!mhEBI&l
z&9}vS37w1`j-T?M9yiXA(8b at +L_{N~i5mdnD&IPrU)ji?&QZa4uHwYG%CP~xeo5j*
zz88?-ogqIb_5i)cPl-iK5P#-~`RaYm)$iFDv##?!x>svv?SR<EUSdzecfo7k>mG at 7
z;Jqtm)cb+F?kt3v?mb&$*(SCJYtUXZwpI)>RFAN}b0iMAkMSK>6{oR1dCPHCd4^m_
z(d~GuSXyz^@lt1PK~^zJeAtLnj#X2=47ZAF5wD7eRVybyD|Ti4+C=etf#UuO{|$Vg
z;JK#xH+?|@r~5(er+lIL!1Taqsu`U(M$X8lm+~_<t$N}V1io_SY0CS9_d18&2z#1V
z<dNijoNaJzob4;^d=uyCGrlXX7w^v2d7F3HNH@<kK6%wmAkE3#&e^JI5mw|`*5;bV
zqMn*$sznfD__6B&>O<Ec+9x%GYYx>D<V)%{axwKN`Ivu7ow>DgtvN;Pu;_<d*<kAE
z;y?Lj5R<Ic7J3a3zYLurX9+mhY6>JT{qWYgbmHidqVs0Pp_TWmsJRDnO|`xy{$S<3
zeQX=}`@CiaWtZ{VaUXR1CAw{m@^>N6VU{19BU)pOhpIf}(|P;sd4Q<82Y%R3$PudL
zB0u0C-!}*0rTv12r{W}BhT9Qu#dXKpH?|J`>zi9gQJ5X~x6f}KtE6*`$cG~`(T6g4
zh2a091^@fyyzkc{-=_snqQ8igWXjDCqov_T1Hi<I!!||}APcfJDERy*1))_`@Y at M3
zsLg`h4*0bJ6 at fs3avi;(5UR+Sp$d=%)(Vw1^lN8h<oIL$wl1$b_fvL|y}DgTAWuj7
z4Lg7^$QwlEyx&hiA+RWLe~{oqK!T72D#Rp#48eo&qoav9`xgajf+by0f+&ep<U3nI
z_Z-ANg}w-RmdLm#MgJKo`cD&yPo?lzl0BKml*T*>0i*Fxu%MHOK at 2ES%mkcxyt7D-
z&xV-e9*|=kk1!-Slh75cPatS3c%O)%)coLNl0Iva`1C#zS%!)NB?Q)f8sdvWVTrH5
ztnUhWZGn3Q#xNMqsPWr88=o~O2%JJPO7ME8_v14P8tun_`CMa->y~p2)Ec#RQ2TG#
zm9{utg{m7m;>76`QVB#a=e}D3Yd1v}#hkdX6S!tT_rNj6a6_|0^G$Y-^@M#lZCiG!
zJ%>GjY=VfkZFsG7=Y2=n3^dyedz1~@-p^3s!rI5aC^#r~6|C(i6rb{ub17B;;yA%)
z_8(n$mI`I=Wen`V*w~!;S=Y(`oQ+-k&UeCZ(qHfe$9;-cVt*B`fMTQ28vsUr)~<1p
zQgK0JxuKRm$6WR+`7Vtad<a`%8`is<r-2maB&V1EZR=d(L&gU7#Wg-V*&iQd9QJUG
z#{aOAV&tnYyBQg|Dhln$QIVU7Yn786?=lBfJnZ?zvA at Uo9>;rZ23>@L`iXmM1X#$H
zD4xA8fn4ts{j-^1?r7h89RBM4c5~JH+4psC`|Q1-#$C?0#K!y!NYqcikiectAoA;6
zMjl+|LY-;l!K at qV=~2&vg()AlLU5y?%iKsEM1FMfRt30nB*i(u+A6=0UpZIOknaAV
zJVSn|yh1D?b`UorUSw>Pf8Yn?$+O6#@(W at FKC%kp2eE-z!nMSe6w!MSvlVlQx5Qn?
z&x)IhQN(HDremkpLJS)@DdStkyNrpEr)k74K!aA_8I?0foXqAf`z02zXXl8X7X;#D
z%M0uwz<vbw#vTjUNO5t7{(VD?kv3rt@=4i2d1IINt at ***@qSifspDuD{=`I at lPcoj
z1l)il^O&?&GY9WV at R*aMMxHnuPeB8tz5~VeBSpVA;c at +>b=^lMAx3Q<{xKIklW(}$
zQMIEGe$fOCO)tf8`$IO0?GF+(*xG^`e<*I~T;K!e#F=q^XCvIjd2$AM^88odjt5FV
z0?H-SoBE#X%mZ;{oHzU*bwhH#bG`Uo+{RB6;{k(e#HdN9hYavy_JDyJ(=}(WM<w*D
z`EE$?D{mUa3m_X|C!_Lf!<2uOlL5Kee-(SE)8QZus6sXjh*5z!7eCMi;;Da42UnA?
z=4^te(T;fq&e`D16NB3woge?fNdMZv;lA4ueNT(MmQCP4zlO(d<cDRBKue80F*SlY
z|7rxo9djyk1Uz)zBz_Vn;VwLOY*(Bo=0^^QrmW*2T$jI?<Kj2*7EWLOwU at SzI+_AX
z<Rd{%MW2Mfi1UHJP%-uAL5%kUE&hGl#ApC?0t^FmBPpl>8FZi$s_+{?0mK2X!;ON#
zulsKWoGA$Xd*DAS$W1|S`F;%<D660#82?gOX>=?C at q}F8#y-+!*wJ=QyN@$zB*mF=
za*AaK00jhsgoB89K+xgmMsy{UjK|ZxL=+PM35o<rk?}N=Hi49&Dl(o4`9#FC6nxK8
zVD?|V=X1X2y3-YWcZrmzD#@NAL3XkNJ)-&~1zN^Gfh4QBj#r{RPEJr_|5${J)<fd~
z{u&CT10>>({++JnzGDc)8iTPMpaIF8;GM$X^J^Wf#lfEfK>Iy~!i5BZ$daf%O?zM;
z?B@&|O?%rdr`wGkfRfaiG&!{QJrrfw<=+*|Auv~hd1qiP2Ct|0J|9F^uGg=XH0v|J
zUc(PS?se_^9N*CVUYFOIYla^ZeuFPS$(z4t=il-DxHjL<_6`<%?sF$%pVMAf*R0?<
z_VjMSy=|;LnqvZM(B}hvUDG`^)@~K3 at Cja(-<)1TU%>ZHMI0-z!_AW=`cIPRw-5cF
z^dTC(@LNR*oIj at gN51X&pW+{%pNsz}D2NFivu1#=$?Lf{@!|ieVwflO6gKj`Y82wf
z5l2)!;ae3)w1-_3VTciumTWM%p}(9ZpYa{nu<ui}XZ+H8)jruH`*U8a#sKSAT#Lql
za#-cB%vY6{h?$O`Jr at vzvoKz73J6O<Is|JzrIxTAO at JjVgu4JwAwNFr?|&7jc{&dF
zy)f3Auh-D`T*7^6n>DO9vq1^?5b+lBoW;nGEgvrOpr1}<9*lY;&UrHj3h=>sFzOtO
z6%}V6_)BtO6lcZl5A$nC3Uv7l&8NzX=Clj7DQ}#_6F`KqbB2m8garbFTtTjssNYS#
zlz-#r5d-Eik!JabdHMN>U&ILImk}G3dmI-e<e39s+9e;M`4|o5DMrw&Bu+S|rMMyQ
zQe>Ve at kPTs@^8cs1P*!e_`lCMlCh+6r*pFNvT`f=weswE-4UN7nti=<v5;fbm|<5T
z=fl3lv1-guh_$ljSbKsqNbq_Cy2kOb at 6&tLJ~a>X^?i<-BO9h8W;(`XoJqk2f2gNs
z56vp>jC#5FSTQK#kQ<b)gR|~kaNAIPDjdE}-41P>#rV~L7`1pk90K^!@Fl=ra$nSx
z+UHbLhA(|EpJZYui`n5rJtuIkafWaaZn{a7e&gm8HI{wm^{qXsInKgg<QwN8^d<by
zd+i<n<$d at J`9J*R%<sxi%17{znQzE1 at QL(?;S1(T;|IJ*Zn*iAHR(Y4fqg;vEGR$N
zME|b*p?qOBE`W#3x2-QEmlHF8XuRLnA3C_V#`4|^_{ZEwmVN?`1=yhWR}UGQ-&9kh
z`wtu$KGgik&51<$)ZDKUaM1o$K6W^C9(O+1-|bL*7itagKK0bJUgeRQ(2xC24dJG(
zWJhd^?X5Rxl!}+deYi`mfY0QCvsDwrbN-IJKt6!u<N#?CxNTm;X`QRj&~g0vt&8>k
zsADuSI9iK1S_k!E1?UfRNLt*7D4;692_FPHqz~wjKHvs{iYlNDzMo*n;p73m4{$(*
zen>kWl!D-PAV><oVPpfLqXK8**9!_ at o5*0t-;NA`6cpQ`u328!KVQX|XTFwc%`1Ci
z&kH+jOTw~s7BUXNI1rA6Q{iBFmYgeR{9yzD4vMon*($-~<ODqxFegGB2t<HHWFR&O
zo`?{{2;zi71Oh_DAHTJAmI5$;_lTT)zFWjRUBo<HL3`JCUbA36RmI6E3cifX_{_t6
z6i&x0=&*+4BoYWL1d|y at OSG{5O2R74EM7WluglK?`%iHa(0FMJ=CM6A=dljBS_i?d
z0xXUs2eoY|q7Yp;8p(vDqWztwB(n=gw2hQ_5ONlK5;53H$qD;d<fhHeeoc16cJ-If
zfv(|N?Cbjk#+aZn5l6tqVZCne3w2##HckU`7&$Mfb+G1bF|B!t<$Yt^nu~e0M)(4!
z&M;?!H`oz-?)vttTf0;|2Zs`HQb7{?8{#SF0k?cM1 at Y`81=W+3<R?fd>l{zyJQJL4
zadAgf0XhCAKXw2d+8!#h0RdV#4v2S#lWZkg`GkDcNZ)|36w>&IedK?)INtq(7!H((
zhzG0j+%dgS33vs3XOO7ldM9nhBHob9GvP(dq42}!v at YeDqqW|MJKB@|OL0eb<qX2F
zGUn)vE8c`3r2r}pn=ch#UiI~-h!31OXUv$`7u(VJV18_Z9atxOd7omXW2ke|KRV7j
z&nPB4PAh&p&Z}_#Pe20n*EX60Lj6);DRNUB`|0*lICr7FA;h~le>d3f-ac-=UaqH5
z>$R9ajHs`t at H>fk>@^ec!ta6*BeOi3dD3}NdC<9k<iE^;&V4#F=RTcZ%X!7a;CS(`
z;ysPv<eq$IitqA0{L~y&Y)1?@c8G_F1me5$mgBo((CHHJBfcw65wFZo@?phYVsneD
zdw^oy_?xfe`-#uyv;@v>#uGeti-iXHMSOQmq#>rF&udHc*l5sbmp>WgtFICx=kd`^
zfgU4UY at Fg=#<PlB{2GT?Rq<)WsL0&|#Ha$fe8ejn_=;CEkdGH|j?TaD36<+J-!ETN
zOBhibMBGed?3}?dG%;dm#?g$MQ%#(;*{FlFcH4MjTKt~Zd{z4f at Q0`kH|oU|#P!QD
z8kTbjeH~+MUT^x`@Vh`Y&+LEcgQM>3dB9EKuzNhb2|u)Ogg4|qaSDzhL{Iu+JamDd
zZgOXR<tDg%zz<pQ7yA=+#amlvQ%k*?brXK&{6OPa{-b;F7yAdk;fGIID=<&vytzJj
zo*Z{gI_2RF(YphD9rxHrBId+?Bkx<B;aiSB%7I#k{ZV^&15s<O{p0WUf9;2cID5ku
z%XkqWX7sor+c|EiMpYaOXiSY;u_HjO-+;Yxeqzh~+CVfO1>z%X%-A%*T>e}4<k-}2
z#HFg)6ocvvoVy)gQVWPL@!%qSb at Ihl$GAo*-$RQwJvw}_0H?P at Uc)_w70w6mL+msE
zobw_0i8Foxsn{1<D<3wBW5IQuH)owZccWNmTn|IwGMqNQ(FmR2I&+`xcd|Cdp5}GN
z^VtKTh}jqOzX3c^7o4CAPM}ayF?@m+K>>U`&<)3_xIIn_JdQ&UNskq2kJZAD(P12|
z!#G-p at nJyGsm*;zoBWU*+y$04?jlQu_<#=QxBg1SmICDaRVdOhaM1;-SuhSJjjv$y
zn+iM=6!3t8)_?-suY(f%pu}|+6IEEu;I8Q={*#eK-ZmK5uZ`Q$1^-wdYt7)?_Av$D
zX}=L{lY~V)Y?XF%(}lvDB9;V%6Ug4cNy~v&$&Iri;o>|bWd|MwG|p6K%Q;*05cm{u
zPQnQx55ZAHJOx6 at aZe?1BEkqJ3NWXOl&6b)XQ*h|4G~4iGbR4cRPgm*z2B{%e1^W`
zy3<9{T_Q7MFy6@;_hc1S%tsTz94y}1>0c1f#I at oX`;g;*NRD4gx%OKeL(JG7e<`~V
z2%L<?H#uh5YZD|Z+YxZR?^hrZUm4RyWZ9KMU}jqdqR+<qu<x;%#906F2t$M<c13)a
zU2)E`sqHDpB{|{5&7RoqObKKI+tzDgw+csJBVb?dIRhI5&IK?Y=L8tP{w8*<U|e5d
z3>Bhd%svNeRgrtTz+Xe_IGwd5_^y9HyI<pvxy7l|WQS7`aM(rmIYo&94q`KG=U9~-
z!LFSraGIE8t}OUMqNtceK(4bSKnG{yyopU4e6gQRJ~sotI79mA5{tw!`>a0i-*5MM
zM_scMDtV1WR`DcJ1>JV2YkYklPgu^?*EWk$6{n&g#Kz%Q3x6V+Q{3y!IJ;wLZcrpq
z9Feq^enc^Z4^d3uKXCO$6?x*=@CgYjb5LA^UtCK(<9^0EPUFHG_~P89b+9hD at ILYr
z`_Nv0^N+|wiqqf^zK}U)iu2A3pZ>ccaHoGVmLk}{5&%sw3p_C&B704McWfu<{S*Gh
zb^ZMsJZH>5eyy-ro3Z+2z65>l739<SDL)EnoBBnXZB{w2<+{Ny^F}alk}rzkZcY_f
z22Y5&i=0+mp<vH^b|THa9(OaJ6>pr&D2|DH#5wVV7<$G_DyYPrim!+Zzb2-QSk~h#
z$T8p{<IV88`3Fz^m-hy-FJ8~Cuh?6t7~JBp*SRC+Ywf5QJo~)%;{7b<2el6{_VSu-
zI6&-{T`PVUu({*73fqe1Cn=V5Hjd|6b5=~p-=pTFM&Us~)SLmuc%65T^N#g2_S{s+
zxbM82a6<tg^nbN*y*r>BQ at N%Z2*kJ5oKtm5gW}`+9V5v>;R6HCMMsE!{qo*EW=GCh
z;4{Cj^#E$BwqD0^{L?-<!3~k}S%3|Uw25n{UOy at 3b9Tgio#}Y!@`YYUWqm5nSge0N
zn{ncrAGF{@;w?VPLksGqJ*q>2YbX3yzF;3RhgEC9)xl51lExJ;X+FmTsT82*<Xi_C
zZU__*^aATnu9m<bwKjXHdV9nuiL=_1e1pa{Yw`mm@|yha4COWNi&&HoN*s&uRef(i
z%)P`uw0<-l{)8_vH$GH;Q$B+Ii?2(r<{6H<IypPyaiOl~oI&REIA5X8S7+-c2zHT8
zdYqm;MEgd>=X!uvac0C#_WHt9BcA+?IJemEq#dyTQa9LN+3RATvpsgyejC5*p-JES
z*f&0JZYQtdwAN6Zt{erA#`%k9{Q+y`Ct|4uy<#ut?DJRMzlR5Gen|L^xczo;8!gcI
zz<t=xoOnLtu*Su<6@!`YGWpL at h`Li`Oap^<h>RzRP$%i86Lr%G6yPmrABV9sSRbQ}
zA=Zx8Mn9|#WAqQn=mf+MiVzs;0|G*o;6Z>HMRXOkDg=I01;HeOv*=m~{r{|jq6&;c
z6(8W&Ks})uMOi}?F~1CItUd=APd29YxT&yMFMAjbf!y0 at 2xM_&^kN(vQ6!B5n?RjG
zxf~Nx78xOY5|J}88A+f70|&7<JI;}Yj}tLxO8~*CNY*<0lf;9Q36kOj9DytF2Jw2T
z$abon^E46fG?8@|B&5JlkU9hLPZL0--Th-hulbzsxt4oR(Kyivcv*9bWAN*rlUwjg
zYc;1bXt5{w1ee$^`+mQhN;@@_Kys at vIJSn(X3Rj|KSa?0U_hV05I{L^uE9+%l4d)X
zQNZ@#AfNGB;74^1?F{fg+Z{(Pn=267))Z=GZv_C`7Q5T_4ekBuAg_DRcqy^=`RZ$}
zt-x9Z*1k)7fH&;NJo=7MaVU$%lf=PlQXXG1N4&sh!42^ugS`2!0Nfjo!H+N5R|Y>i
zHwGVy6B%<r`QwN^g%CB4Lo2ap1L^-8aI<mceTP10jB!m~H)}%H-$Y&4KRYtSz6Knh
zK<>NjAQ3!llkqBI*1~6oucWQ*C&J86viKy1Imym_g&g7pp0Uf#OX61Z75D*9PF8|*
zV+|of!GM2|7{z&F53vY7?ots5-|#E^i<rZBaLTd9ToRA84)`;g0j%F#`NzSJ-~~Jg
z8^-w%^CK5bxu at rk6w}-NT3`kLPh#!6!=gW(A7Z|*r`DM3W!?E?-sl`DUL+Ul{NubO
z=zE^(XI$qin{Jz*dT#1 at i3bxpqmh#klRY2#yfZG6hlnjInkx?hbAZOF^HB%{;P?9c
z44{1F>k$f$QE$X};*#U8<{|evUlnp4{<{QgTOw;M7qGQ%;j~;kF>&Nj)}c5W at w?Ve
zgI$GR!HxFFtz$35dhTH_j at 9g^pm8-md-Gfk-s?cx(tjs}jqAHPmg70bkG-s6ZC!CM
z<Ke?$cOmQ4VQXp<c+l!o^Fwf*Dp4^#*lM80ITF<Mj8ULADL6k*sP~?G@!F{SYE7zf
z{E)5TI0-iAw<86jl)Axx1$<@=#LI?bjTg3#rEy-6-}zyS at x0?8xi$Xg!#=^aJ^8kP
z?-q#D1~I!(pKSx~(>QMA<Qz1Ar&zy;1)PoSNUi9GUiuU~F$WR&j``sa<tMzhKZs{=
z%v{zzgHvdo!J#}S&2 at a8$*chY%65uZ#H<4E0qd at 7xsUt32MNFA7xSEy`(O=@3Eqct
z7k;DldJp*ckHfFMetd&i#Ja_O>|y?B9 at gM<l5L&C6l+6wsYdQ~Q022(4YW=DW8_22
zgkyjHo#ld#9H;7mnT~07fSXO3A4cw{StoA5LF at _7-H_2<o$D0?*nh>)S^Uv!$0%Ye
z at k2t`wyJX`UW_;q=j`S|_rKv=d43)BImqkXB=Q(qBVf#o8JsiodEH;9PT{;GKlD66
zo~eB}9ul`5`y+P|=YtEG15#62XF1kq9Ie<s?2xu7djQ4ME585w)={yLOjs(Q5PM~y
z5yXZwh-7RSqKV)`oI$wHb-|yc(}9xs-`B-i7yC(!BHJL73#zHGj$(L4*jLdqD`v95
zq0m_?hL+gr3CQ74#oO8w5+m1F>&@b76jr^6PfUe(b1FMgIg%V`!;yrvue-dxpw5B|
z(d>eH6kQ6w1aN|`&d`CM09FCFlN(}Z&~g$pFW^Tu2t?{-Q8sf-2eSyu6yXNNmI%vt
z7J#~*dl}E;Yd+>CSskslnPWYumAI48-VADKqZD<&(Ku!xV2W$WH=~5l;ZWE2F+h#a
zT;se1)&lCh>Z~&Gv6oR8b4E?{_-yK2@=P3L<dY+?$Yv2#NQS~nbH;_0isD at a2t&al
z1Iz%0BWF|vF{ty}1}-`i%g_3C{qymii`6W;TL7!V+XbKkRV8US<|YyR5EmV=WfRAu
z&JiV#Y6Pq{0Y(h^r%ZgslRQ5mcmY;KzT?ppm+HUW;n=hmpE_poVLSAAas-&gpEaz_
zA^6``gSNgFrwXeL%|+a at 03QA^`NX#V(BoJBe7k&Nh{bFMMC_ug9x=;BqRyMx5dNT|
z3Xv#YR3pH?fFFoMjz4fqeCv(KY6K9k+z8P9&T)!=$NWR_NjXhoHHxT;H(Dz(SL^@H
z?edsxVBYj!3V`Cw8gB}921kO~y*cLMtY+sVOmS>}MkB}geDZAiQ~8y=Vj-Wu+?bsW
zPrb+^{d`;u&Er*^Qx-vvSt&9Rfy68ddd{!n)-q-t3Ao3xCF2Xwm=*%eQ?VusBzSYm
zw at T<|T||ycfe`smAQxI_E?(FBM8#=CV|f4MOKgxi({@mtGiMRJ8M{xVkYlahf9{<)
zow0c%&Sp%tSXkPi_OJ1<E&HCZRwQaI*us!Kh{G9+M?rm9#68~IIO7C!YVLWXKx^!0
zTzkcL^X~?nw-SBN9b^A%NNzO at jwDaqFd6S<KX}tIv*pfkgX0KrB-gpn_xcix?`POp
zOZZxFf8u|gz0W<*&gWQX+8Qu$xtcF?zfi46z4*mw+#kQv at YsZ6MAezC)*LaT>PxMs
ze8l!7MsSWgXZX<Ti#mJG&HL3o at X-9#cwT?4U2A3?qY*>Br5xk>LL!tpEE**7ptBkl
z7Tk&P8Q<r%zOQOHa#pY7*so*6^soni;S9Vt_?Y`*Pkw;IesrGRi|V~)?wU6N@`0Ih
z=}e1JD-+*G4b*a2=CP5>GM}y0$UHPCjL%meB;+{#;eqGMnqcUf$~#dHuwK^fTA=D<
z^h?^<c}DiMEp11|*Q$kyrOA<K3d@!~wrmH-ibWjgKDL2~2_rt#eI7$&F<w3pb7QvE
z*i{evA?ZNlFz3BkTdnCd;*jQNf0G}V{|Xhm@!{^jiOatG>ef+q-gMwVI<OM931vqR
z$`K&f-?yjy?Wx-k{eQ6_+N{`KE0%&Ny-1lA*H!F{A{w+pww`RP{LFF){9gvkF_)<M
zDYie^*5!5Pnp at H4f_fBc+HWt?R-DFywK>hqVeB;NIM^9`m-8$OHx;nIh1jgZT4(0s
z+D~J$IZ)#Bb3kWYO at ef|2!IM`bU(!h7vWjx8RCosISGK^EpAodc0nPcI$+}zB<v(Q
z<c8RM4{5ocf(tI1hX_5*$r at Obn@#Y}oQvQ#igU0b@``u!Actr-W`V9y=a6SnsB07B
zY(S3P8#XSeOYAHQYMlw^;etAa&itv^vY4JH4HuLojuJh9z}JgNC;JG3r&W;pVFb7c
zc2j`b5q_Ffi2HWAfU4IO^d`9JFy>5*?`v+M=719!94m>BCIP`u_dDQ`{3uG{i5mk-
z;^Le+SV<7B$d194_!UxdWr|P9ljO*Z8^wq1Vw2-j^X={86BsdSC4MZSm{U)D4c@;O
z<o&C2EYY75uQm<Z{@81Z&S3}JME0pz*8k~~{bcfw^2I5BrEiq)_9j5aDSSO*Q~E_E
z|LzwQjV>6oA&D<!F=erlai<b5f6Xg#(VWtC+(U5-pN>}!G at lgXh<o##mra2Ydy-GZ
zsVc74@?J;94cP}99S-CA!fd>l!?0a at +{v{G{&iC3gUSVw1Bg8-<TKX0Xw8Ck*q4}7
z0-lB=ah+I$ja8Uhlq4K;_}eiGmWojVV^F9F9=D?l4#heb?Ik=4I`gT9i8^LHz*vI%
z23V|XPbF4d^R&7Lkax27fo~-Oh|7U|LJF3z^}T;_=f6z|ICsjXl{?eE;Qy`e?0z-c
zs`7sRu-Z1>R8tK}O-eLH5J3<S<kQC6-nQvi(xmOB-^Dgqw9#TKRSt at uMbY2^p+OW7
zXsd~OxjTN(7|)nv&Ud|g?{f}b^y0~W_xr9j*PP?y8PAw&?RT?T!u7S`&b*kX=3QJ*
zBSdVw846)1fyZ60!TH!&K0u%bXErB`YX{#3Qk3RT{m$!CcpBn;b9)L=uCe=-%>)b5
zLcOn_jXY<@#*MJv>c!L0 at r8~(&&zYbM%Co{$%1V|L-CfIJ{@NjR~<i&mu_w|ZUp<X
z{TaUt^|>2e&aIyUn`9a{8qxZ>T?dT!7RIrT=eY?Lb9O#-epKENPs%Cs3v^r+;7{y?
zy_~CIM{O9L{=;X({?-HAd-iMjR!xlku5;?RdYyh98bPs{n!r#~?D(wftyqlt%E#r~
zSYtN*AZ&xJuxt1w^F2ULR?e&Ocdk3PsRICQ4A5#<@aJ{BG_?6(^1x*cs|^8b=deF(
z;?LZizn!CKudp9$6 at SJ#_!i%5T~iM+AJwpNgM^-q8a8i|P%nmt7F5SpEi+P6-`2MC
zxI~RH>(gb8s;2_nvkZN#{v_7Hdf2E}jk5jlC-x(@U89KOs!`Zbu|`}~Oeu~+59sMC
z-(CMY`0Igu?@hY%o_F7M2Y%vf1017q<`@HY2S4xP|K+XL1u?%ZhhpBzXXdhqZSh#e
zI5j}^^QfWXv#g&9^8U*YABf{$*hmf1hyYBIN)l7>kO%}&1h0ab;I<G7ryw8{NZcVg
zgUA6if=2-o;-v*PB5{iB5|gi3WH*MueWmbNckiavd^|s6K0;}M?Da_?=bD#59*txt
z(B4FHw at J3_gaIpQoH+R4H6O9aD<NG;q(lO4{<Q%>^Y0CSYCuV{7q2$~lz1YsYa*lA
zwSbA(l4z+0H5=3Mc&@~FCV~WcyhkBP;!ZMK8v!B6gP^$<*H<h?Lohc3HbOg}4lto9
zCc~E4)YwSsnW%Gf1Lh>NfP7+q+-YdAu?qvX#E#R3v2GQEut7KZ6lE7=3b6_(1#^*_
zK(T~WCPZ|PLu53tedck_!drxuP5mOQMOqZ(i6XIrgalwMAkNRipJQ`P&B0^~X~ugZ
z$v9TygiS<vL3VmlAo#2cV8o~k;JzVX&Z-!}e<L1tt_qGCJk=ca!TI;!fs>oeAt$#)
zlYWJ*iT}}WAZpB;Yo7Dk9v2_$n418_dHd4=lixm(+$M}o%)x2h{5xmNVc`#W%bb;)
zl+KspqT(R at x&#y`LEOSOMQ#gQHpeUkh_T8Si7Cf3F%>aPEOPAHXv#*Q<BB|mi)L*k
zzNn3U3WfTJ&>GyNIw`@GqDu`q5LZ0`HX1lboH90cr%;+Ub5lR<W}ZRphRxJOlxV_E
z68;uU<l at OI0MSXFBjCwrxG1<i1xV&#3hi}wZ4=t~Eaq at F*7^8x)f((sHWgUID}m2{
z4mcir;X|JOfGe;e^$~jld}{ns`ga5NpTB<;j9M$d0LC34zGv-aK4k~h-J^NX1_HpA
z-b7Fi)F!bSLUJH$Naw<~fspkiH;vusRfC7`sng=(A((;rxRIRPViveg%((Fevf`&|
zg+a{#ZV+8Rs)nd8xK0R&U{JM?xtAc;ov%|6O9<20XKZGCRwFp{uj8~e at D{J7htE60
z03SJK%Wr=D?Du9I&R8T48#8VkOBGiFadrnEoyP at c9D4kY!I}$mBquBWQtuV-!XaTF
z#T-1+yjyqeN31E{!Y7I|`K;m$UxsgQHV_2jV#J0~8wZXB)&H@%BmWcE730hQ7f&rP
z=TC*-)%%q1?RReo1nm3CSJ=dUzk=;Iq0czy*D`K&Lyhq&uf@%$ZLOu at Xl!a*#(G&l
zHrX~y^g8V(`(T%_yX}y%pD~Zl^jf)guj^NjevjC2tVHZI2MP!0xeiS(tYb44XY4ud
zj+nzX*u^#}j+?#3S>N at vk>ji4s%<lB{nE9?Th^5m&1rdTbJ_ttnbhM=<T%$G3LrNL
ze635)be&bqSDtjdXRP-IK*hW4P<|HQ5%cD}h#!F6J`l&eFo{n)j1GQ+&t&IdCm3*!
zgTX-%PVNnW5F~wf4Y=vjF4Ep?SzNck_J%+;$Mf;YCAdp;Pw3Id5~GFf(MXGPaDHao
zH0+?RH|8KPH;dcZytAHy)~NrBd5GL at 3_%JyH;8HyCFI6kVI at x`jT5FwS_yL`jS{EC
zLXwLGgUQ86LTjQavJpx|h<Gd{N=%sG^G^VBCs~0dqEBK1BBvG;k%U3mO-{!h2oY6$
zPEd0f!@-+ at N_>7%bMoC72!ZvPoRXNrHjc#+j|gOo>?Nda{{fmm-?`Jq%6#q53*)@r
za0&F|vBP&sbhnSlvIf~6LZfMsUBjN(vdHYFS;2l`FYj13f;6^fybC}U%3I<H at Y7J?
zJdwVecWF|PWdY9d%b!K8joC~+h4b74^O310R=(JWT~<hwwR0>)$vRmN0zksgPX~<M
z at UXWyEqtK(fy=@_ at ***@8v+$4_<!3Js2u+p^VK7p0`Q7?M@{o+rrls)Z44ZEHBSLt
zjkjUW<J{yNjlQ|_Zo?nw4NW+lzZq;UG#`$QGIDD?`rmi`XCo`#E1}@W%!}&~C(Ung
z+YP5>ZW-b;35Vn_2~@-sJLBY9#7pzlg=i2e)+xw5NyBj#R$X}6e2Q_!k-=Nqv~=9X
zoc^KsYlugSEQ9p{bNdy1OxeQRzl-#=$>Nye8Lj_V`xKI_nVeI;4PjC_=FM5SN$U;t
z#z^JZrXPams6T3uSRZq(^({de{>9Jmw;Sr>@#gbqLW1)|)zB88z#{Z1%sJJ(Ca&gi
z5A&QJgE6;x)pc7OSG^Bx{x6@)@A7 at +g9LN=o?IApJ!^WzfCY5;i~7pnA!iLICaU%T
zazY#Sf#B7y0W&Xxo8e at M+yZyWc<)BccH>`-NkEO<R-Y2<E|+Uj0dA+kC+9|!uO}fY
z9xu_2|E&;Ku2O%&riG7Y(12UWtKu7RPsMoyUns|mqvV_MT8La#BbYvvKk+M1IbGz3
z;$-9oJn0QZYw!F%q|`goCQ-+3Hx>u)3ga`*;oPZdj+;o1Tg7X0^Y!Me_}E+=w)7 at J
zYsV3DK)yux5O?BZ5U~do7X{*lc;u&bNulG(pBsJtZA^*7iKQ7wYM_E6t9iQFG$4m+
z(?I%Eu at R`)=>EyE5skih&|m{V{-+L99y<=k at 3tpn-10g$9l1PsUG~J5u4`pCYq*B<
zQFdIm+VW3%w{q_CF0;Y)3u-=jO at A=n*KzZFz|&+`{udW`?tz%=(x1gG1vU2t{^W1l
z*uMw3jIo5Ug>h^?X(O~=ivv9eV`_y!Ygg;msHM8=f3+E)rv|9E$(!fR2+afEOur~@
z1NcN7Say6VKu%%v!FRdYnSC4a^8U|!`Qe2myA0wi5PKk-;4*kKP!~xRL7n7O&6fyi
zyR%V*LlY$dSmL at i2z*D?PYO&}Om3*ngPYfPv5&dky}f&9y-2aia0=8SK^5$<gGsOj
z*|iwU20MsQO?4m=7pG8&yP>{F5;?gNB$K3)+lkVs08!!?89YiN68wM?OQ-<90u7~;
zqY at y4a~vZQu5mk9V@?$9n6uZy`Zl4gf=k?0%!SPqZ&4gYh%fF1(eZ{K6mKqs#GDG@
zDu7$;y+Wvvc43S-s94Bv2R-7U#M at RBDfSR}6+}dZgjf|re2%~IulyNy!-gW6Ac7WI
zJcblRu^QiKM#AP2PO@{7f$S{Nlkv0{t}0$tz;wrB3Z5I}=bA6z9LFx>F>b}MiX`!C
z!oP at N2y2hoBSu-vh|LCZHDYVUSH at TuC|@tGtpcR=SFAB_)+3I~Si>(W$jxno*DA&o
zU&Ut~Pv$YWqc;dHHa6=ir at 2u8dV?{VX??%R{NlJ1ZpLRr&g=88yfM$6V0<u|_{Nx<
z{;qE}^uQaP#j_iaic7-|&7sbn%t7pCF{zv(Un*zR{Fp;QH#_AI{6Y>H2qw6pgj9;7
z6i60Yr`Srt9VjjqA6G86kRrBwgMb*0ob;FVz_r9GaR*P5mr<Ov$nS7oN{kYt6`Pp@
zG2V#DzWW$)>3ma-P<#e9F}W~**XJAuILA$&>WtSFaqo4(HE#5ZZ<r_itu at 6Ons4Bm
zc->qRxhFe}JewN;T&w3V{b2E%VpqOYj%72O&29O;8XbX{D2VF|^ZmZ7>2r#AJBB)r
zM$>%8Q^nHusQ$Pk=l6U}#$ADPA4QE1j&t*R^O}LUUVf2S#%E&qmsquL1CAGQw|SZP
zElxHc<L}&{UtEmu<a at _;aj<wbd`#@B_DI+wL at TaOSfCQ?#D?pA#FS#*wa73h(^NHT
zj?aJ|$p at UXp~k7#$}#E>aX!Ik_4#_g-qRTMlj|{7U01-C)Hk5qHA++q*u8vU*e8BH
z>n{1;nmc{nn+e2S=L=63t-7SVfICb7z^Sc&ya}K>^=h;ayj|Rl=8^WjzQNH?4a8iD
zcXCJ^OWZ0}lY`WxhAm}t$Dp-9X`a-Yj=j}XiEDXnj=h3oRjBig*{DrijdMchm)=E#
zSbGrXQ*#h^vA&Fl^mTK3_f$J4%E!acvSVxA3-FokJ^KyuS)ll2>pO}!%onZSnB(9H
z<-z2M at Q*e|nkSa8nlG9&%6HTe8dmvm!ZydA16THb4t#!$%hN>i4X8P&PRG2Mo8Y+?
zq?v0S_c6}#IQXBj>2<s=uWigP^+0Wqy7|A at 0N6H6zf`r>@utQ<xm9y6t*e{~pU6LR
zGX{P&f8o=?QS!ApDE$BaKm1bu2>?kc(lT^VkyId?gIi&u0wuD_0=We<fmy{ji at XDx
zVhwo}ftA2+h|E9{+H)adDsnPv%v+&(kk&JrcGllQD(r*ZC=gDTt(ZpO;IJ(~6!=Gw
z_;&|T2XF<L18xSP19K+h2nfT?keV&v_v?3&))fe-6WSHMv*QQhRiW%6Nc@~}<7O-3
zMWQ_Hyhx8Yxh-yv2l<!6rs9^3{Y|l=;g}msz?(}34a#$Hp6Btpsad$$7>Kz#_7ry=
za}{si5a=QaIrAkZ>u+pD#9>=(F29D~Ap(&KBmr4~Dul!gaiTZ~A8U6OBCt<BmA;rl
zV-+EA6d~qV`76- at oWlZnT;TQgSwQDy?yI0VzqUeUA$*8mI7JA%kb5d#pyocodMIcc
zh`EXNSvEw0bDZY0$!Qk_T6QU$u+EBCH7D>3 at j7C5#j9iXh+98p;#gJuWi$QQX6QmT
z;p=bkj?cR>AI<rU>6>`YIcm<;tlz!!^AwMkk2n8TW3x3hr!VAFfWH#*-+3IsZ$gbX
ze5kuF_^&~{&EIQY<e<4;^Qy6llauesOB#lQ at 8M;Mp5k_L)VuwDN=3poJ|~Y=$cw|p
zx#m`jM>QC3Dykl<7RP+xRPpK_+Y9wMbLX6+A?!OuFU1<-nz at D)a#{oRiZukk`0>Tw
za161f`HO2}{)peOgX;lx0I|_E0NZJ<Lp#WC(^t!9>*tB(-yTD`9P9O3S!b=0IbcUM
zbJVEX#4+?msnj)uZP?$nF;TU&@ZFye|HS)-j_G=t=L_}OdVh`I=hf$DO}<6)c)uR=
zX}In`g*smA at VT`a-*Z%rU-n5~?y)%IP%$=riQg*UdXvQU9n6~Y7>YX<VhqNq++}=k
zkSJFj7oJPNF)?F5^=-vPH9G4C%MlxB9mPiZ%{DV`Y<z05@%wo$h%vwWvw_xAas4gt
z$(w-krq-og$(khF+NM=!w>re5*seoWi&T%$(^s0>@0;fh^S!t}0M|#&Yo3oeh~HJS
z!w1Ac%y- at 4ul&QN5o5APaNg3y0c&CFVE9o_EvD}6290yE8?ickCI6M}R<lE_8evBv
zxpV`zb}TT at j)&w1<!4-1ycl!Q-`>ak;Bg-LreRal7SI|(zpGJWzTxM*LvButxdazB
z4~9Se6qw>1d*a8|6k+cRO_6?FIQ`W=13W!<*6Gq}smq2R4cF_g)s<h?UgF%WLCUYA
zu3*b)N7-`ZllY7rP=17+uvOSseNEU{vEdrjSh2AIn?HrQx!}!$?LEfwProksm;rA<
zNq1Azjfw-ugMa#U#|p>tL;xEDV_dGCec#^f=aVWG|IHr(xG8Mfd0;pn%-!Y`W5$0#
z{{~QoKcESKa?VP`noLbdMe&@>k(9o0C!~vr2rfm71YZ$&i#dvlaEgHvcLeD8xk1Op
zxezB~%^>bTJ_<zzvc<#P2~!Xgz$17&P%9X5t{h#W$-=1xAVEW5K@>Q<Nsc5KPF8`y
zo+sIrZOgvit(Ki9ro#hDOylC%%l8dkBgPr;^|*dr!PLHm=<sd%H+>qw7vYl@=0P at H
z$ZiO*idm6bKk7CbDmN>unJUbNYBp8XSPB07<9eM<)_rWpPk7wfVEOu<&up%|QK053
z3odKy0!t$m_P{O at I}mW#4m-N2%J&fuuMa^7L9khr1=S=r;)}eExT0`!4*p~e#=<|&
zH~HmCT*x0WFZqL_vI<QWo)Qs(Y<7)WXZh*|^Zh<H&SQ*%$2~XoR)I_06gd^TqsXxy
z;6g`{6QT%rv71Q#*+iy!iJ$#C?bp9g#ChVN#u&eNifaqngz=nGJTK&&QxGrA_p~NZ
z=WKTt8Nb%o|56E at T<F41(<adr@%9H**gsu-Nb_5qXsEbT*j?aVABrbk=v_;Msxz)N
z`Z+%r1}}oHHz_E34$P-`5I$PXXJB%WQCuY0ck<&nX4Z$=0Lc1KJXkphKQotJx7Rl6
z0*^=|1oB_Ctw;R4dAAFIc^9?TUPXV_TEXjYlwJ4?8`&Q~bqgPqADH7&zjCgHc%2&-
zxw)9a7A}c7;Rog+fm`->J;F9!6R=m>?J>B1bRANh1uD+8*0QhWe{b%*?%G;*9P_oE
z at SW?{R<CB9I7aT}aOLj;98xGg(UT^;c8-tNH}4k at ZD>BYMQ&ylHm(Q^J`g{c`v6?1
zS__gN#qqAY4Rij{gf#C*J%*p*Y4Lt?`AtoJ7JN?KZLWHtvAKqt)4aBMe{nusUw;}j
zo)$_De8wG6)zpl^6?;3!DZgo8olnZ80rAx2t%dw-ao<f&&pZNg-I+r(KCO|ZX&sBP
zzK#b!DLH*^e+$&Ys)xYG)Hz*0h%vrcO|}cWVLNeR*lj$%&pdlG6x%32 at 8qWQbMhND
zC|%-y;mk|(_xV)vmY0=-YN*c~0=&;!IF4BGng-u<jamD;2Qbg$f9C7;1uxRb`EKso
zAoZU}jW4o}n94QP20&bwc{4Zt`4>JQ4~gX~-TRS<f9opr5_xikdQ#&?R}C$-ZSvgY
zQ)$qcM?X2`IH}mkoWhPXF3Ns$L!h|4;{%XK#p79vGAH2b%RY))Ir}L0Qq)gA=Q!%<
z7Go7>Xko?#G}YlVZ7ww8+7X8vn2&!>oX0!?b3yma%Kt>aX8mvh?}-zh0ycXtuFenW
z`fGk at t{?u>KYw^3Cvh>*Np!**s24p9G#>#GD8_cgc<uKEA3Gfr<K}gaxrsO-;`}KB
z1&9QQ<YizUpCn)7a*bYl&Y{;@>(hE50RooYoDsBY{`>Db@)64X4AD0NR)JdUkF~RI
zIY<s0^QavkLu(D(Y!F=HIEM4;{03sNZCdE{-ve{Be~j^Y&wcr4n^%d(RqTrR5rqhM
zHi+&KKV%PiQuu<Dy5N<lSz-nebGwTwK~dsGUzCV&xx71TjHce33KQC30LNy)iSxXh
zO at bnElQv{s^VTjr>tTZcQihPD=&PX7z=VxNz>qJ*8}`NTO}NArc}0E^!}U{nhVQ~x
z?IQ$o72)0_2-~;VXnSMpv~w4&wy#Cug<TEX^|Xs&oBNpg`(`&|6u}`NwSizey4Y2r
zn|H1)fUbn2V$q_p?ka7C4&gXOBS17@|IVe#7i<of6lcC%Y#X!(#J>~fR=^z$cuTyS
zjnW&V00><$<0rf{q0c~`dxee1??B&2!Rz`nqC9t82bde-Rp5rSIJU9zXn?U8J8a;1
z7WX)&5!N>iYBs6j98f;hPoqA|V^g5sYgF6!aH{!q_};ZLePdhPvqRZpd(Z2w-`g+y
z at A5^DTi{w}eKlt@$H~!yo3&YJn;?#(0qADg+-!ap$d`dbXahZggJ5(%m7QC3mpz$}
z=0^REd24;Ke(I=%x4r`;@4m5KttpPzI`FsVA7jTgbnTdn>IOBV_$wc?-9`6oZnYUH
z9-~GW=Cp~Ei(VdH)31ZSJf^s;_-umtT%zU+?@d_zzY^4V4R7vhE;+xu>o-R~2RG-Z
z9eTZWea&e!Fy?gCM;e&k6xbV><aTN%8z^oDBQ`<RPo8MF;(2q$lX));T}2!gw%^t8
z$M56Z*ZJm7G)&^DPuI1?RTq3^ZsMoGd|jJP_&oDi<(l&CSPS#q>sI9;+_iBQF!#VY
z$uXCjqVsWRyyB6i at ro}1I*$#GUmu&~6WTDJ7#n1DjC@>8e>be<>*OJ>y?mV;LFM1F
zhiqXEV*RW+_$KxKy3t2NDsGO?IS!jq|F!lQk8$OPShKl^c}Y*PanpLLv}@^B^U=mh
z-VAWwPi_D+cMKm(4hhcjHGbz)<<!lM6>BBuQ)y8B>7Db*xdgu#w<~u>oTWB$d}Upv
zE-9X{ZPa%4OIsh6T#wylXUAN}Ta3kcXRpBq1pXwaoKMQBkxLUZXYQen&3JKMR$etn
zR2(_CW`2Q~qikTEpghACX^+$ikxy)1V3(?WX&+<gA#0-g%*Up!0 at 4PVvy7)a4x9h*
zm;U_Wg;mgxqJ9r5;46WWFr7$M(92LV%t at Sf4kT!iyb(@{<TeD8y&@ii1!|$Z4xC>w
z_bRar9=}hc6QqsYp-N$rq|lff0HB<;UFQ^VUNb>}4GP#puzku#hK at nxDR{tey6x6>
zTG!9@)!ZHd>!0WCsByK9d0nrCpe~F#gZ6hI8>AAa&jE4c7y?BC=gvB at ry^7Y&<T&I
zCH9H!5UUWGHW at _DwZVXpXo3zxJOyJly-CoJ?j2!tC4TrKw5#{ea~TiORb+nic(#QQ
z^RobgtfRoN7S^O980(byCO^qd^0G*&$q4&bY;FE1lC at 1a9~;5}jEn6kzN at G$f!(%>
z!jm at g9ivzq>%|Uk_9w13Qw$%Yb8DOnyUAW9Ag8_NX22?LYZD*^;zdD=b#He+T+G5=
z#Jcl~oN0dW?zMBtd83 at Ee2H`YZ;>(|@IyhoxZqvoc}#Oco!g%)SNLi0dx5!M<q#W#
zh!_g0it5OxOJI*x==6FNzI)h2vx}nV6!Xh9#CmL7Y-RffZ*3eb4Ew^Tr$~tLxmM4?
z+yD>?QM|<wh6M90^l-=eX+hxk<}t>6f5BrPsOv7Vvfew#Sl14??jo*<Rcdn8_U1Qn
zT=1I&Xz`py_T)Q2{+jp5V~bP4!Z3hHJTX7#`1$DRi`AIbb+qZm9Y=(E at e^9acjIQR
ziJu}K6bJa%wRz-`I4gWD{tutZPBE7B4Qr1zBV3c8Y7=t^ZgKhK at hdK$JT2~mgAPm%
zJ25{$&zs}UYu*5nU)*MXD~=OX8;b9W^Tc}w^`gEQvF`vjhVP#8d7Yo*<=DQK;OoC!
z%yVn3bMD{Kk2%+zHSe5n-o*qJ$M_o%a{<15kC;~jIqnc=BU8B&aQ>)fy1}lTBewbr
z6a#8D(714lxbGhS4bJ1w0mQZOvpIP2UjrUD7Zx81)>LS$dq5AugK?aXUo{4dnqZD(
zKFyQSz>6Qz3&~B*IdF}6M*LD71HWKT>{?BE+B<oso5&l~lPrxmo^v?Y-}54W9UD1r
z at XL4dnf<2T1b<aeg3rV&<*QiZ-k8?Y3}sjK7_K#6t?x#mF)eMc-hf(zt>GW+8RPUO
z0HC%Mhudz=%jRRaST;)g+;H&B#mYVBoN+Jb at +sQe*Biz-jmZ;}6PnLQUOA`2M=O^C
z_6L5D4=P`5`-n5yo%jx$tHx8`qmFyCcW(H)sm<D6wsx$>n9})i4aI11fA_f9S}_{7
zw$0gyp$<kotr+!d|6Xx7LHucrwNA%hUE?PHiZ^=gaK&6dd9S$3|B$ABt#wXm9LHV!
zl%7OOwmm{WDyJ)#gG0nCjz8zGV=(6OzL&oI at WT3At^kW*F=ZHmB%21h2R?74QEi+C
z<J(Y!WMwcA25Z=GmAo?GAYVfy9E&mud-p|zwUKcdqR_&#$hU>3i4b5+p$KyV5-r at 4
zZIOpbcb?azTSQ at 4oX6`Hy>(2!z94^4*H_YXgC7AwU{n(2X2sZ`a1b5eJlPu)C8ijc
zYp4ly<DkG=k5mfS_Xsct*-Ai*(egPl&`Ai0vx=ooydc62m5iN~;3x(iV-;79rP`cw
z5l|A20-%_fad5^0Br}SlA0_QI#&x(Jb6`%8p+v3;Tmm|p;UPAYjQ774e??;R#P%hY
zAVqBM2A4=g92Ut-L_zKdrV{7aSN4<*!+x?|_!paDt0FALr(?0=G;LLO3Omb2ZJ+TU
z9Iy-j0w#)?ZL$RT6C(T)wN9<o>s`&ii(VGC5{@kvy<t*u7V)Gwsu)uI#5%+^w!tV|
z<h$~ZoFm`JHUFEJ$}i^@<eqs|ImH+qTgJ#O<yZYQ>hpOgNu0*H at Y<_^#>uhg_)lW~
znG!hXe7=7*hEQ{ex$L}L{79_9wX;ZueZ_IbZ`fZOE{HR14wsq77%#?Ud|y-bBI-sr
z-R3W9PB+y{Of-)fC48HI%xkWL)I`_H!C?}&Ep|r(Zn$x=7%V<f?g-VK>uH=qHA9Ft
zK_V{WehNehK{t$B&P^_QB=1gcn(xo!Hq6|N>yevoRF#(j^AUL&>s4c*oc!F%Nj5mh
zM|eE^2j4gsiH}u}lbf7tUAy3Kd>sD$&QA^@j-TX{uru~AdnbQmUu=tA51W=<Ev^$~
z+Y{&e{NBiMY>x^1F`Hh*I4GZs!)`@6kp0YSfEaXKmPV6ZrOOI4wgK at DhwEoyem-Jf
zaqqD^?%l{$tb1NH$Gfp^^q(!v*B6-Q3>!>4WbRciq8)0kZG&1<YX{%pD*Y*aQ<^iI
z{>5djD+h1oH`tectJqAvHZ&Wx;RNqjz2HWQwPe=~IINq at n8R!`;V$^9beGm7-;_^=
zFWUC9b8(8}O7R{Lj}(^>i$`oaX7~6{bUYj5ysX6m#dPJp;yG}{^A^W!8Y+e>?pp7a
zUMYXI-osy^Pd8uTCp4eyi at 5_0-@Zv-WPK^<|G>{j(^F%w8ehJ{Z`2+405>{1YqjS?
zO;qm^apetP`O)>Kbadw)>vpb5J7<17zfQmEhRj(j>|br7g at 46u32(0PUVe^mCh${^
znd8^BD({xBGRHJu<{k6T4K=<La%l1L3I4!V$`jkZ^pxx!zti|~gEM=RuxIhQYB+Wy
zSK}JGUgR`!LavL0E at EDBe`A}#&6*EXoUZS at 3V8ix1AL+$r8&m2TALy<S2hw~haE~6
zu^w>;F-ea{JRWh_`i7Vz*0do~_K5g;%}0JsW4-1VJ{~psMcL)sf9_WvzWrwdAO7Ws
z_eMUvpd=vp3<<Ps=K4zn9EbqJB8DNC7DH7SFt))WS#02 at AShS^1V_P+*-%DoV~*D{
z@(G;j0K7t-zr7B4*RkiLg5{?2AenNWz?wxkX#*9D37mU^WHzv+?73dgM at zK3T!ki!
z4WQrzDo|ReA7rKkB5+)62oeIQc9YiMq^>)Y{`*fAoDQZG%q^Tikf_D7?s7RMDjw4R
zd(yStooFNvMB`!*g+T&nG{gNk<S8OsbRG at wUEz7#47w0WP$|jBU0`A%{4bwFR`@Oa
zA|Fs_5t}5LZ0ur@;I)c$e2!1>Q`#wP6yqpnuua5P+Xb7%^&ws6)OKhQ9&2E2td+Y)
z{F%XrfBWW3;?|eJ<+rpyhW^)VhQHImcct2vVLR-G&9GMpU)zd2l$~Nd_?<QCPY at zT
z)VL9c7CeQvjf6|Y5w?l=>9`?gV$9wo*kT4!4qv%Ql_0){@8BoLsgM<6GlmORafP_0
z@*lrw6EyN1F`+!J=3k=kC{z{=@_!Wm&M$AYSs-|GjTo^VEaVs`^6Q3+pMd5-&R^Xz
zs%BZ6msg1EHxMY~JM)4wK)j!unEAPW_wiTb74n)EysXbS=QrWc$MHIUjcYDzVRrCY
zA~!k3X%=JTW1OpbUGW$-P7Qx?Fu6W?thh{E;5tVAs#@VX)v at XtM0{CrDQ=C7Ux_Q=
zcqO;sL8Aq8aDf{|xJ&$K6i at aB*&V(F;tx>yZ7va?7|AQmE#jBK5ryY+jBxRvdHk<5
zw{brV@|ye8J%L(7-|^Oel1Mu#x5KV#eoyWW-zk49cUxp`b<(jKaTc*HL8-W{*gW&n
zB0a{-I$d!iO_Ty%u>;RLeiTCi=2UT%vGfFdJn?7DF}X%ui|eWBvF2bd%!#?NcIyfF
z3oY^K;xROY;q?u8Ls9FW(EEHokB>1*7w8&opVE%gMmPBt7`DmvqZ7S(aG at 2SKp)S!
z<SPPPdM>Y#cCG6Nn9pXvvYYSlXY8b%uz@(YI7|FQeNzpX+?0a75nR=E0JupsKgD=#
z9LS!;nYbzJ7y1yJX|6GEX=v6t>m%GkT`Vq<o+{4RbVPGO<yLdRk at w`|%+CWiUpRXY
z<g;<}<X+(7W<_f?<#}o~Zxo0#tB&W!ecE8J;q~+$KE}7 at U+MGVTY;Rgrf&bj5fS6$
z{@BRb>JoL(HK}|r-CR&C7`2h3x;5eVuh7TE`Tje0Bd*IFHlAWLDB{wwqs<`45BcX9
zBJa#i at JZ*|%Cp|2^CsvOh&wRf(>Z}S-?`WQQ*oE_j19Hm1Gp2OXkI3-!q!>uv1zQI
zJR*0h#`n_}*noVYo@>3e*2rIROXRlJb(tsJa9U5Lu3Q;6<6K*R9%Nlz{m4RZW>?HA
zZmH9ZSFtM)zmDPRH>M8l_$`}t>|!s+tYdZ93g4%_mOipZ>Ubo6E at I{%$9pd*U~0fE
z;5+Dz4E`>V6B2E8oX at So>G4Hqqi`xH<*ZQ*TmXvT`cW7lQRV;nZXs27IZS%fp$I37
zCkdzJpy{k at L=fnl<;ZO(v#uqF8q9&_$ifbI*US)c8LXkeE)wgSJ4qIjU?iFYMMaK;
zok`X~0}uohvmpW;KvnP+L at s3EN0FLI#=)atav<ers|gr>XGhci#@CV5TrbI|k`f=w
zzoWrxpO!DNE&jV#yj;Ls#9U17!G&%Xn^ACdw>W$*Uz4!-65oYi<OhmNB_<@MgoL~x
zu2`q;JVpFt7syJRD$#^MSP;2HW!Oiy!7gPJ-E}IGk}cvovO~lSb0FS`!(O}B8U<7Z
zI*RKi#1Yybs((9I|DRs}m;EW|- at F-h?)X=4OQ=^7w at qcguwB><e~H*^v+!%%D~b-W
z_qvz9EL#yXvK2+nLWtN3G7^ti0CoH<0n~S05kXbB#1-U$_#&|hK*PBb$Lq`RoG&E;
zGiOQ!R&mOFp+F5`06!{UT%;)Qv4$v2YW%r7FdkV`@v3zyhiJ4be>4tU$(X^H`ckC9
znHJfb5a+mV_>+H?i!tUb0x2ZQzQ!p?ncoFgLw${#b3B&EMd<pqe>dtq{W+1|t2x#0
z3proSS;yqh{%o#Gf+=IjcEwNGpp+O2U#=#<gb=Y*&4<K7#gPS&_zCV+?SYpgKgrR)
zOHjNHZ;iWSt`9=h4DnglqJSHCLn2~|jKxun<~>k(XkIWZvIRtU<!xbox#=#{n at 7wg
zg}*;JrMU$ZXB3a<Ut9wIedPA<B%i=MH?Z^4x at ONwd}LIE;ijT_DK`slIX!&EMnU+K
zI;y*f at PP8)LaXjbjT*U{fUJ>Qo;8TUj6?rEYi8$t=l+FeDjvu>nmlmZXg`j{8P}g1
zT31~sk4^5;`+Q!wITyPCMEhtm5-Y!wuPeutXT`V0+iEyIQFr8=Z)d|n?io`Lf%(}y
zCy at H6G!mfsr&io>e)0Wm_+vdSvIF`8!0-(|li%@e)vo5Z!Gjwgh2QaaYGnLN!?O4t
z8(I%^;}Y{?;|DHU8fm{lkbIK-(OiMHF$XBmo!gl+E1#Xefy%Yay^GugKfPXW|1x%9
z9`hu))~PpyHAnN%T0=lwR_i0rS+98!8`S2YbbD!baWA<qZC+a3+B<l>b#}$j($*C_
z)Pss0>4lD;6+;{FUjRP}<N)!-rjmgk2jmG*+-2-(BO1*C;2`3VJS#3zOp>2y0P#`4
z^}jgDPsSxTRU9f7i;Jj{=Ae$t$vYLBKzUw$Tj(I=2JjpM{RQDVCUMRgFt)B^&Vx&t
zH*;Z5bpyg&nUAxVMvC)1A8A7D7Ixio1^x&>`oCg0SBL{O_39%kUS{u5b<&!8!f|*5
z$LYkyah-c}+z<a&)?&wU$FpM@)TTmc1Y&uMV|vONzmDCCSH&tZ8n*eipZRE9 at 0VpS
z-TD8y7vnmCUwARb{`kWOKL53c7go|Zaq?omU^cQBNu!J2*|DJURB+d>GXYV7AVTee
znt`x_A`tIWa9sfPBtnccozAuLE=&<*%tykEIo2+y)=<JL1=b;~ET)8Vf`ekh?@y?a
zEa<&sEaCk9e1D)F{~Xjh<|YOKzWHzkO$W{e0cx|M2vFpQKhHoqizOr$zR>QS{cEzC
zL<NehvS}%w8}Yk7pQJ-UEP`pDt1u41j_(l>y-5 at ***@5Z900{wDmw<4OpF*v-)_jt_
z)~yDyNS<}GW^JP6S|LOU1DY_J*&r_wZ8Rl%Oi7P?|7A8S at xBB=#5FcxjS!?r%$p){
z9j}G?<l}esNW9{AkQcE+yb+fz=5IFvzRgATLa5*1{M_Pz^ACb+5(^}W1(-|4utYbz
z_U4X=Gwjb!vUcU!5Fm~yc*KnC7;({dT;ghbjE>@<Vh~&bKa?#6Vors}ag(vLfbSOe
z&p at 8nF|6WMV+YiDpPWU}RpH8FEB_-1X;e!LZq2eAT-G(A0-bB at Lfzk)QHa<25;suC
z=^SixHuzT<b`<7#n-~~^U}EMhAnt|8Uqj--KQpKGTBzT*_c#uW&nE2K34Fpv48DdV
z0^6hdi1^4=<<#H_aymI8^If@*NN~NVCLVqiPZGPuo30_s!{Af_ekCW1a|Q8m{Zu1w
zq%eK{pRg2WZJ2Q5KkE~ah?%I|Bu5LY at lVb$HtsO4IAn5$ntX7G`=c at V)}Q{hSAj9k
zc^we*=naG7tI1W(SM_9p?4;TqHk6%f;}^aP|H}6kSM at Z3>cd@)<Bh_q3vfrosp?+D
zw{iuZh`c%*$K2E^UN{=a<_U9O<mvogkk(6;i<wK*&{0P%+^MI<jq_>F&KW?B1>_I4
zT{)C_)PEidsE5?uumi{jzM6OP3ScvG%Nu1Qzog5QV|ViG0zO9I9RBQrF%B(rertJZ
znOi~3oln>E_FHLFY-pd|)S?r?zw!&U9nOsN#B;WN*P_xe)cVOyvS(oE7}?PF(*`4)
zly+E6%-|67K;`+C&y@$Azm+F9IeX^m2Mhn<S0BFR3P1HKF~|B~;#-X^_rcTo-`d4`
z<sJu29uPN{?WElU=yKb&xIz42jV*0m{4d~>BTk7=#i--+(AyK_hGN!nYlQzRhLul+
z)TgO+9n)8vS-sgn%#r7%YjhK1YIABVng*V-u9-MBfceHhC*UA~x}Nph*AY~=i-%^-
zW{zlk|M?X<Sov`Db<)Gx(2FmyJw4r>d|;ypU-!*1^5ADGKB|_vcFcGp#)O#<7x)$s
zIpX-e2V(kLetO|*tcAMnm`{U^Ip%uCy4JPge2?|80dc;?_>6Dx$%nUp?9&e~%w!bq
zOl+H+ldmSS63$7sUld0vi72$;L?uU%91bS932K5_kK6`X5+EjK1t@{1VwwfDg=&1p
zF%-JIQ&?a2gZK+#^{$Za+!Uc^5S554!M2Gr39Vr`jCh4ja7`p3H$rgv^)A9*4$85Y
zxH>+-^|-DHZ(^>)>-6SC2gpSDPbgt)QX~l_h!g##L)h4)*u^@C55gM+m*T4amg^uh
z2`ofOH*G0k)abcU1B2K$KtvFo;l|^N^h|PyD`KlaftPrrS#kqaqCj_b5pp5g{C{Du
zL>%YkBgiG*;(E+Ma}1FtVO9-{1%ioC at e2`J6pYO+6{3>_9lMUtih(^|7GX4;!v~=l
zeYdTVF{Ze7JSm1oybvQ6*UtHf0TsMh6C|(A7H<kv-pjXP8x^PUi3D`mU$!4MZ`juH
zd5UE>w8arBQsw)zI053vF;uVr5sjwfOQ>UX9N^e7Mq$R<<ArsPvrF``12KjQZ8gt*
zZRUmGcagRDw7}P0hf~}SF-q>inG*OQpRCybU0Df`18M*eD9^>!@w|8QKD8kLPaIHA
zz##xWA*N>20pB1PDpv%ALy3nL5MXQE5q;*m<8>ix#lrdd75aFOr<^_E+{ygef4=~^
zW|+e#ubTtJ|COua0%PX$y^Vkp8>5MMS<Sy2iqTjYTQhKl(jyX5{WHe6(kFp)K0ROS
z6yITNPOG(_9M(1tKSf;hQv_Alh^d=;MqEbxcEd at ttU8u8Oq=C2o5gKxDryrga#}S8
zev4W`O_`gAy@`1892<jfKH&v#1b7obe2`q=|BWs_Fc(O8S3~Njs(?j!ae(r^zK=&a
z>D;TFdu$WUdDqR7^RE$kD7%(zL7l_-tC7Oify*X8Y#wt{9f8AS^Qa{>LFfkQ1#JEm
z at ***@H{7klZ?nf|0|3ZSMN^<LKOurHizt__=Jy&err)of`OaVXrGHk<q?yG at +jWjhYu
zlAX*|Q>Siq-g$kS$Nlt<n}^7U?M^>=(>XNq$~ial at oeU=@RP3+=Xmq_%>&GD%(d1a
zjQn?#mmH8h2A?&zojib^X-zXY!MwocYjeXw^Zd}o(#BP18jANB{}uBS75~nG&IN<q
za$YDmMt&%M3gji+q}XCZE`K(NJH=l8>^QteZ|L=tZ=kN*dB5Ve5o^-gU1zb8VtCZI
zEtdUsYsT~WgzIYL)3?I(dEhdZXB+{?m*Vc at PvFHJKXDHqdxeN|fBYP4;Jp5ZtN9jw
z>f;aJ^e=ug at KXZo{ic5zuLr*G=YQwng}?V>AA4y0c;Z{`!4tlk#7tTebtY&zXBK29
zA&yqURq;g}5ikmVf*j%xvJ}xrVbUf+kT1mzQeGPb+>y&WT5h)TNrJrVN<pCLLDr1J
zj+%>E7P1WF4qOt}cX}eR*Ik?=c&7k!AWvM0u<>&Vvd3VOnm8M?{Jj(A5xksZzj2sz
zpNREg59~AThAnMh+q>+aWSbihQ=BPgiX at v958;5%X)IKrX>#UnDgvTJgzprn&`Ust
zm>}k82-OIVrf)WU#A3vr{yajBXf~u1et&E95OLkqRWmmmxv at czLM;Uv0;2_m$(nVW
zn9D8}6HmtU73_x-H^;^}G&xla^X^*ur~RUWwKf6}N8C-)Qx~ze??N<NykTo>Tscl|
zOQ0c?Llo<8zWH1G`aApFbn&D1Woz3ueAIWz!hdJ8+)oNfB!_ at RL=poflx2H<I!5rr
z6UbOPjzw@!(H-c|{Tb&J=5Yee1+glTUV at Xx16Zs}bf!pdp}7_Lv!G`om!KeK at D(7R
zDt;Q|+AG01PT(B7uj%U-=65+X5FGuwj-BJxb(6;v+N^{#i2q06V~F2{I9DPrkz=px
z%ymrM*zdWhaZ at bj{GGo!{}P;leCu2u`ACk=KNr|)QouE+>(Jum=56XUjfC!=1WHt=
z_}T^7x`T3xFmN;!&w=&CJ*XiVO+hyXIftvJpqn9t<j^5ojVhaTO;Rlawk;eNP>dA6
zh0i3)BbUxE70r!-$XRkXa$39+JOl5jrc^!Arf1X;{h8FcF)*JPm>UA(ylh<iU$Mox
zS!b%gc;k>wg1K?XX6E2R0X`Hbj at lzm3|ws-6d$p^^*8%-gRuBW$lv{0Z~hmTxdsDm
zp1{FemwJG$TocM({bZJEXx3Y;J-A;R_khj&dVSiY|J<rJOIEG*-%F1*4zBIB%}o(=
ztzo?}F^>&s6Jx&T<BF at ***@ml<xe788lHC?<V9ys!U%X#Pe$nDB+-A$}~*qW=0KMT0b
z?}F}j(r_79Ir|*UF#?_A+x2Q5$Nb==*=KZ)k38RWGd7VvAGW&Go}lvH%|7T_F*zDe
zST$n9FP<3Z@$dO+JlCSd?-Ml-@%_X(-+<R4)Y`6ULBPD%wrMQewJp85q?jpm+&mIL
zM#m92d^`O=<H7OaUK8{N(rA7+j9&F at uHDm~eeQD+J at fYZ{Qcf%=lf5f`|}?inD5We
z&i5a|o5G(jY=d5bgX?Ec>RiZ%GVa_Q0JE5fGuzoCIFz^qR3$6Hr>2=et$<d-MIuQU
z@)SW3CdEYsBnp!XD at Bz8L2(GeS5e^ZpzaXXqgzn~vMKm8k-vzazYQ(ISA$g~FLE|1
z*Jgo)G6*7;$cs5C;X9ctkslLi6I-GNoTyILnY0rlfqSFD0rMXW;J|iHYUA#PLhiV&
z*Ol-SPW}_~k<pVBEV#fR2l;yV{?#GI1Rh)0TXWgwT5Hid`?0XH<@P985N!BPe#E!<
znV6$dBJL1)6!6+iAYLr+w0WS7gZ)cRQnZ8!>x}{n7eCpOSg-T5b!>oh5pz?>O%YcO
zt%Z#K9uvV<!fF#U7Hn5y=B8=Po#aI1zyN|bU+3q2PKh819fUB#X^LS9y>a)Syp6T6
zHmx((j&O6+zad1gz8P6!H*AE+4MDisBSft1fG<kCE>RcgJ2uM>vV|JxJL1lExq^?G
zm}3+y{5Ehspz9}cF1N26HOC2EgX?-u<%_-HFHz~npT@<H=2j!!yf(OP!h*)H&(9lU
zoH?$pV-Dr|+86>gKh3w|YsS;W9s6$fe+uKg{ufl$us9wBH8!=;Ld-NGj%i#Bejo3>
zc7A5mG1>SKe>wJ53~p;Ge`XCDepGXicD28H(_ntF(Nzta^=8(Sn_5xaSv<OUe(~-p
z_-;gAH|i<sTMs-3rwA<QiGm(CU|mtyo%2al?K$d%YFO6?uQ~Kb*g$oZdg_{st*}|y
zP-2`q5%%twSFK<}fLf6^F%)CrQ~5YJN3l at 6EFP?em(9p+!`Zb1USyL1UDGwBYJ_VB
zd}vfHxrNUuFvhGg&jHsz!Mu2~K|h}Wb<k at G^ah20*XQ{}mDXN1 at TNsK?X%u#qr#gM
z#q*%@PWcAc&m2?UA363M4F1p<#TyzMj;M_d<@)fkv;lrDeZbrW)=|(#2erKFdDiq?
zXRmeCHE&Y)pGnr5n_I?OZ+Qg%fP)u*B)31p8#jDW+7dlgd1IZm!5R$yC=S_lquz_p
zD;N9s_<4 at y>j=(I>$oF7rRB&`*5VsSaAW0a=j&x1TD3 at d>{|2~biDZ)BuCH9bzgVq
z>eVk?^K`Avw!dTl^Uk?!X&cW*{q6>CacFUMbMNHen<jkpdV+hv1Kk^r-_?x!b at Y&r
zVfLEm at BcsI?5Ss;U6 at UK_v0siq%hw5TmSSY9z|{d#6^Xx3ju%5<em#V6>LE<g2n|r
zf@&7+n?ha0FcZHw1uDtas6`?viAgq+Fvw1K7NgM+=>}oa6i`GcU=&C-7W40DX)3<>
ze^nGIL at GEm5<$Qs+<6zagd8NB!VSTe1!0mbNCLSfgNgpzH~=A;AWlG9B8?LeS`kT+
zNfJttN)d~Qu#hBk5KWU!z+`g}PX3)u;ND#$qX>Kw&my1c>p%&%jetZ#6(c7BO&l?G
z1D{*tY~ypiIgk3Ao3(+E>u~ICe_K=b!mfF@`-s7a0|`Fju*9AlUKM|eJ26Sqi^xIn
zAb=24h%5^>#2k-(60gE~RB?ZuxcNJB?tYXYycB#EZ-}lCTtW-3J3xdPek}fg)&zW~
z#_Q7B00Ok;HUw+VF+Pv^<XANHCG;eEO7NV2N9l&?M&zvATmR;!axHL~XOF=7>GL~}
zr+CmNkp)A|=Mao=#wi$ITVmB4Bm!bq$R`o*!Jqee02?uu#}#K;92R#8d*gW*G|AZ5
z at O%8^T&-!WP3z-MU#?Mt_*h>)DG_-w#qku#C4wc0;p1@^@FvzAzbDA8Mm8CVh%+}Z
zhGSH4z6>~S<7XmYXA|b%10$wEe(v8rUR{Ul#(dQHe0Hsib!yFO0=%&|?!?N+<x`7&
z`K014;!YcLod;Qelmo=C<JvWZ4TGu~`Gk;bLUEo&r}+Qi{X1e)obOHA$+ZFV at 8bT6
z$<q_ZamSb&s@`}WtKq-8Gg!3 at eF5B1nD1Q|Ws|6(0PRr?g=+KQhTH%MdsF-20doL#
zp*SEn_nd=+2aL%FetrDTG21zSah%`%WYCI at Er$nR3eqbDbEg`ig5T5oag2CwG)Ihe
zVtx-#z?;Y0c<`rC96jT+VsvRAYn^K7tas*<F*mRt8s}Iq#dxRxa$~Z5_{+7vSc~je
z{3cGr59ToVt7^M9Z{QztTzSva2>s^=^=AiPs-I{5)(xvTXXBCNoaCAODgN;5e(xTN
zZ;Xw1;L7CD<e%W!+GsKV=t()adGZgy1{HT1bHrNs+wpb8*iC$GsLu*M$M*018Ggv8
zIV&ezTVj6clkqf3)s^{Fr~XDBU(G-DoAqVB2e3(;!?|gbb;ISFmk)gsYv{ET>k(_j
zUGi_lr#1l0Gl9vw=uf!!4*za{_95<DT(~v(=-^W)qoKEc4ba1le(sev-O)=n9{c?2
zv%hh~x*mHB{~qQ>hH%>MIXK4fxaYMr$E&&D$L!r{`1|!g%hzxE at NYi6aC!0hyWjKc
z^O(y;O;lh32ij#bmci*@T?ISfV%<fW;(Rt at QH&#bAaNDnNG=EilIV>9$RH9`2 at f$N
z{(@8?T|H9Fqr`lJd%T8_AzqQD8<CeR#EM9^WKR;zgs*~5(l?^;T9_Fo#w$Q{MRwco
zF9)OG8hM8{NEKo=$!_FJv8zI?B79wlRfMYmubtv!=hB-9;U{ex)P})MSS1vFC#n2z
zG+_xDGu_aev?hTWGwx3K_(0x40=|Z^$72ggZw#Em5y412j;9E)iG*PZ3fUFg<D2k5
zad9Ic*c^!1qNq?{T!`FA`{@CSzaA4sP#_j8D89twqV>pVJvO at iO(`+XWAl1+zJB&&
z^!3g4KDHh;O{`6_O|0}r!xAbjG-9p at i`TiKiM8m9sYVV_Fj at O+!v^F`7fE9Esz5s4
zh_&9t8u50uOa2&6k>9BCJhtG?vxxN)k9yP(|AO8Gh<Q&x$C^?sa`za4f;b6($J%={
z2!C5N+UE#In$_8qhTmHZV((2HCRUT_rt=Z;H-QkODdw7mz7yB4=X>jYHPif!?Hq5r
zUR=M#>71)#*y|YUakIS5eay4x7B*6BJqEt7LBcJ?+x#LyY_51zOdfaG47lDvL<$H>
zV|)(Axf-*skzx~}xqJ+AgQ9F_d&yR559K&HR!u?XTzocjPIfB$#8{nk_1zF_eKkks
z9in&>tYFqK>edjgnUhg3yn)cQpoDAi-IkAFZX77zO1y4&3oka04S4p%)p5ca)10ij
zbJfVtIV!KKNvyoqn%odl|Dq1&CZ8L^xxp8}KCac|yz)MCKR3o|GwcRvh4K5ZrOjI>
z%-UbqS~YuZ<ftyoA8_RI$740w4MqCn^vSU6u)Xfe0ve6^d*J4r`Mck{fX=O-+HjZN
zqsCHe^Suq at oJ-X8wnx1k4}ooS=O!L%Q%BsMye_}X-(i3JO4Es^j9g*!5*<ihsa})M
z<Z|R9IZCahe$Lve|6&rgn*4R%a!ztp at WR!G-&L*xZ}1vu34`C~v0!c_Q-5fV;ezI^
z;w#p2a8+-x2Jfpri1Ukc%su=(F+UGT!vOv?Z`2&|xyKbarha;iIp+D^J^0wCP{+R^
z>P>F6B)5uVi+`nitbv5mMBz_9PoD;29M`6K^Fsa$pRoZCCn(3sY4SPZEOkym8fWC~
zRnE>_CGN=$Y3V at e)m=xImPYTE_T6;zc_)ANd at rZ*pUwVbxH|V0Va)T{jr>^WW3X)|
zY_}`S{v>(|A#Cn151db`o$uxG<NT}fC$8r9Q)}+u^v{2?e;V}ce*NbE^4s+#fL8<F
zy+C1}cY$oG3ItuF8mrk{1!l898~!BnByR=(AnYV+e_z08up+4_rV`shcn};32$4xt
zM{=5+)znm at q}P$)Bs_$mozOT3GVBBn(iDk8rV>k^*Y2Yme&7N=(Z&1 at e9Ss0#*laz
z;s9_RpdHWJ^+d4oQ>0&W3-sS0oA6Eg6YPu{60^n-iSw9=IN#%LkDpO^u0&*umk=(a
zsq2Prl3n=PB<DCFCLY@`*zY9Gm<u at 3;`RPTm-n#7y7^mD?qm_KGiF1qIA&XTC}wM8
zfHl?n)I@${7a3|EiQiu-p;0kmpX*=O;a}`aOyfIzR858oHpQBltwOEhsiKy}OpSyK
z7_qL+f@<~!ZvvE9aZXU=s=%r7aDj`$JpXN-8Vx^oA9K at xZ(zR86JmilAm&HWWBnNi
zL#)n%H;P at _cEv*%zT%A)A5UN&ALy~lherDG!k0rd61%#a6l)L{(JZjG+62&_iEtO3
z992$!L0r<0`NB(KKM9=>9^xkagnzVw6aM(>U*+aayw;aZ;;-7Eu`j2uwhbEjEq&Jw
zcZnM}*}9vgM!OnGfG8>vW^pC~ID9T35JALW-x-+#7O3g;9g^aW$rp-|j1&KzZEl)o
z9*932J8njWt4+*%pm8hsZX at wmkkFq`VgdX)AphROJkMilLkQFyYSUFY&IT>(iFGMP
z>TXtU6djL<E8l~2 at 8vt9+#=TERl+s=tr+0WV#Y+GM60mJiO!=2Dkd at x)S%e!Y$~WG
zjwj<{eq95a|1;<F>A0+k*FFrCU3Pyx0iQz*$ex9=sq8A-jyf8#)pc{!OFxC8*u>V<
zH|*VwkwHu+w)i$UUa`K{$kq&8&#_**p>0!k(Rx at PF%+>x%xR+~>V at uL&syn*-aOe{
zSsYfJws`URb at SOm)bR1oIqy6+uxmzR)?{PMcdR3E)Mj)2!R=|I;PZPm+M58C*W|En
znuL!OOKjYSFTd-PUx+xU<{us>4<l#9;qZ6xG at I){Tpj$(pQ0+asGr53nNO)Pi5tbt
zJsm}yDAp_fl at AA>nTLp-mx&ubgU1Z<*^z_PxjXr{=b%x!XcXVyB97&}6Ju;$tMaCC
zJZ&P(&w<bL`~u0pJcTp(w>D8!v&rZ1kNB6(5qKA!75pfD6 at ***@3;&<JIshSMOMm*qi
z at o1cfzu}ATtUo)pKGK?Ee(Betlga(i82tCIo7^v*v~vHxX4b~Q$d~P at fI@$l!_3$2
z{YG<q7tvt9VqA^)6vq6ti7|e^_ntA=H`mMhCm)UeVZpZBG41;|fvamSjQM%awU&wg
z62P02UKaL?Urkm-+=QHD+>hT)G7gb_C9tzu8sZuf3gS^xD``tu2N~;&V at OcQ*rG^e
z9Kr_CW073oJqevS#-dh_TbhU^YO-i|!H(;tFfAgQ1hkP(kRk=czw_GYV?dpI5|YTy
zL<lJzq6L_k0HTFCmoVAxI3dolhY5>aR*S`I4lNX0AolJi;Pn9s$UOEGkZv?AB-Lmf
zjYT&R6u)R1Bqpo)$>y<6iY&GkDTb|7a42pO2NFbV97Lh+rjff%BEuzwnh1*w`)|%n
zh!#X5M*qBy<$Ro~jw`I#uJ{fpzN0DC^(xNS-G~d(!MwMI(sv;$?qjWrecy$uhC=Z}
z>?mFW#7YTVgu`CE93P|ctOg>R&)O`g#-U?@#}mnyDrkap2)~D~)jZ-;zGQET85#o#
zneb;7IOR+gI3CAWaf|gKY`5nBX#CrM_TeaKk9{-wlQ_>Y`cFX$^64{pOFmrw(*{oz
zaS2HLg|Ea};UoJ7&I+IC4mG|YH^Zj#LFC&06i02&xbasm;)nWf6E|%kF83U(Z?L|(
zvs4XA%teTpnaxS^9pW?NY;hgj^|%1Vw*t8uag2yjOe=3QcXj6#QKP#Z<BrF3K+a5D
z9kU_E=Q at 3@@KfRX_-_PaeDb;0sWm_L2(oh>kn7`)Gq&DphVs51ft`)*$op<)JNJ(}
zd{rC713dnFY$O10CWzm8JQ-dX5dSw^2jcjvI#6SFEtufCC)j|xdLLYkL7nk6JokdR
ztpRsYue7dx9a@`fo%wD;8*Oo{_^;|4IT!YmJ%d}Zv+~R}O}TX;^doPSFXRbAf7Ub$
z{N}>qpWvZc$F at g(gV(IlTJ%}u8k>MF@!faFKDKaq$L$%IV+eEn!jqz(c at _?Ve*NTL
ztpDWnuFqj7*X7CIU60Go#Utb_zL@;2{0sh5&hZ35`19m%{fCE$O=3cE6tMzd`-^JT
z6h=&muZhv9yN(w$o8!fGQ}I%pMB-j_kT~~v3I`4;J;dBM4m!UGl(iP5lZ>jhkHNNk
zx!BL;HRIU_*O<rNJl%7mHtB)<$!pi;3EN at T3-}qk6(7sz=3o0A-nH+=wL at F|Uh=BH
zv^cd?ZR8h!^nZ$~n<{XQcq3v({tq6We9<*IuA>`_vj$iF%{a)~d)C~px30C?IB?w?
zYrlG861&-khn<%X3)W=fqsMN<R2~+V=05WE0=Jud*YD|lao?*09HQ5Z=W)mD$HAJ$
zI{Cd`H>@e=>!)yzQCM~~)?EJ1zy4tVH1zww`ryOg4!kA&|3VKCkdW5v7@!Nv`n-=b
zic}j8h7OPsJOoseY`_6n$+wX$Leh6aBj5 at CO)!UWCE?t_tb}vZ5+v*0Hvr)};SdS6
z3#U6762vKnd$*p%^Dcc6a3)|j{c2(WguDsj0Z7Bdaf3Q%f^ll>-T;uWD{-d{0Pjkc
zSO+m**#wb?z$<Zg)A*03A3LnSDNlmxo$9aub^b4VcB~;R+c1umV6qLlD|j>*YW!r+
zY%s8EA~z+rxmB~H`LQX14=w5>+@^?&pS&NR`z|Essi}c9qX6p;RQZkKtb!SK)ZHaW
z(ju$KaXocVgh)X!5fZ16-wgp$ux5Nej{V#!PLQkf;9fy$RP*5C)CH=Vg(7>_rMywY
zK(nwK2HhEZF)-tcBBt1?%>rUdu|$5YhCxM*M!|7}pYRbr2?0$`IeuoYEnz$a4!$BT
z5W`%H!WMH-9?3`PpKUY1KCwT-j%{BRoGL5<aZ?eWP(<EjjzH`k(F?SoJVoV1jXAE9
zJQ#?%@Yw3<``#RAVHv(WHU{J){4#m&lO-%8zT5sZLt#_h#V2=Xb29l(_8)hd$QN>y
z{H)x}?@<UpNMzQZUwE at E_^8DNc{7D3!s0PeA)l4s49B{GKc9<v&K$#IbG<EhVlD{a
zYPQcNTaQ<gJD~Ds!}*ziAMhACUX3kqt;|#LOF?rmu-n!9jX7SRuH|e00}%5Pl=qSI
zXWj?;@$|E{jJo1GT at tgiu80RB{=9j>lSXVHh!cv>o68g1<H81c|0p=d$JIGBLIyPj
za2<pC0+>T#-Ib3y7F5$g&3i*1$N4#4u4UCs&^5F8&e}o^-Pd?3hr7Du+h1f|jAJ>E
zaTwn<iQ27t^kUW`{Dv=yf!vI$d<m||$MBOw^r$-;Yj9h0S)dzxaMjdzvmFiiRg?Z>
zAG`kEr-|{UQkS0(yrM^Z&&`2t4WQOG at ***@5y;AUx6)rZuly(vHVxofgHrFi5 at lS<D;
zJ}HmH)tNJ!CM6e$9crbt%-RT88 at Z{ilB?_PaOl^*I~?(&xQ<x$Q*_dyaZNRWk<Yye
z00$IL!5>@m4=<WKS*L2~(loB40?pfO)&TaqXe at 4^n4FkC`9`3|y}EXz<~#hIH97sg
z`TVgbKcu&UhtXKYvEtU!^6C5f7sjQVsHMq^#e?FG^gp~Hoz(uX|6GK|Mqg_~$TfTF
z>#>1<eiuXYU-1~621grkb^!iq_^G?V_O$K^Hji0XA$y?egM3rK{m{G-YK(qJF?#9<
z$7`VLD0Pn5MdvDhj~I5XuUM8Y53J3h<zvAy?YOR3Sn&;JyyWYxx2 at kBag6>Ke|>fd
zjdfmU!1K5PbM!oO&dpVYNB`t$KsAH0^mAR~@BW+rn6Jlt-tv*(eR#pfd^Xg;RN^>!
zHUSn;5>?YeB88KcOnyv%KIW`PA4~WWd?7w`x3Usy-&Gq4RpOUBVQN%sXDvz9clJX7
z(=<AfqPR;?R01h^X#DFgn3Cg8LcDfMhInthPGp0wBr%*U6Z%3PBZSxu>iuf`X=bNT
z)3r%X#F`QF^rQZ=9cwC~!#W|37H5zX#R+jEdyZx<YziS|k*XcbfNVN9QHD)#{=P{z
z8&6DV&2xPS&?1ib+3&}3SDPHUrdZEdi(`U+>$Yti0Gb|v at BJS0^_>~!44Enh(*G{9
zNq8~mn2!V-gk~bULt<_cZkvG%kO!3u%7+QY1bjK25ZAfEI8Mi|&(s7Ix+(Z*<Qm0m
zLQMk5MnPY~#QMlbFdK%jLHh>35PS9u&4G8m!<NLCpCovL;;Lc_ at k6cxid?*>$Ie?U
z=dQP6C+yGlxV9dH^%DZoRNV;W5;72elbwlt2!l<OsM$~P*uoi{0`tUqym7f<Fhxng
zg(2oAQm-N<ArgEl4)um8yeZBM-^RM-FN8;l&h$h0z<Cilhy9h?*gkA3yL0EEL}!Ei
zwa~0h8QWf)GTIDS at vqpA>t^iln*jbh<Go-XMSDZ7(S=+!!>^BHJw`xx=g&so!VHiP
zis^`9HM|+Sj$3$hJ_%#HNemIcYHmT*0o8)}8pLs at fU2<s*N21e@~Md-j>xGgj{Nk5
zz634S;QYkS#{6>xuX*4;hgAN1%$f7VlXAW06LXWO6(47=FD{O?u`YhX$>!zafJ at BJ
z{km+_c51{mxK3U3tcg=#ZX(mLO|LMHTkBhE?Da9Pm at D;DzOJ0oriS?}>WR24@(7(V
z at 8VHkI+x;H#$sJuPks)&i^C#*J4YhtrKQYYCCnr=o41lrnrp;GqcMJ at x%Zbn?G5^`
zL=%4pKXUQAzft<)+odnzrhj70=@PT~zkCwF>n<BK=RU%>b;HV>E8Z<}+`Mb<^`@fu
z$h?!<RU3I#tCdgWk8>yD3;z<Ys*A-hvnFcewr+CxsT#$RxVf}zZwLftOj%>axo|sU
zrM}uX0~FtivB+!qf;fvgZyQU1^|4OsX2qRjPfY_2L&e~#p~kQ+w(femVpLFV1+IyK
z at YhYPeHpmk<N<m8b2GmE&N^66`F#03d~UxFpR2}H-NoPe)Ya-y_ at Y~J27Do|NI$cI
znA*pF-Zu>ACVl&wn{4{dB{l%+CL5fx-LMR>F(kc|n#q{|%}h_*#^-MYT+66y-bHCK
zkk{a5U|oYvh?sjLVzGa+F0{1}F)H}A-#=g-j$Mf9aRX1Ne#|<=^%YxVbMYu~-dg0-
z%18Vp-Hi_6i$7<)OG}iG75AWgKjJ at g;9>*8FmF5qcN=t%bB^7}Im|f;%+qkst#uSw
z*A=9x65ssqKh!@Bj``+)7q9>AhaTP*`sszYL{WUpCqDD=mT1K9g3lWq|JjGPMuYm+
z5Lj>h&Cfl2e-P65M<IP%5aHXxd2f$m`u0zL;o<GS`-O*heCmr2?+EAq0Ep)8oqzbH
zhj)GED-S;y&i}zb`m=|3fBtI^?~VX at cLd9OzW9G0-W!4V-aq~GhxbRIzW*zMNRSVJ
zuMWiT at Bg#-ERyDZaoqdjc%2vLzb69tJu#NX1dRW=uRgpxNci2Kjcdkr-z9vd at a2bh
zz4YaWcOF=uGgrUP^H0oU6JxAc?>j>r{D2WQ_<=w8Qvti&0DBp~_s0t%PTmosbjKfu
zjmP^@B!pwkwEdrI9<qO}PxB9($UgGH*B{;!$&M|tDL(i>_(1mm+FvHZ{`f^U4|{VC
z=gST+vA$YY%wI7;EJREY8;X;N7sXA)&s&HgVyR+k;WPcd;;dqgb1!2JU<bz<_Kmf&
zPUiJ)#hKR_aYl?(tg#N^OMg+w-`^X=$mbmQo-af^vCjWhu at pA5ujS+E*RuJmLizvg
z<zLzHlWVPS`yJMvHu(PE!luKnzmfKuw(L9(B7G7*Zp(Y;`yaIr-c~+%d(0#4AGuBp
z#{AzIws at EG9NUN8v7zi8Hs12NVo5fRT;&{W`HtU@^~bp1AJ@=&Vou-p;!6*2j)v(?
zQJ}v!3c&aN_fI{%@xT4v!yA9`cOTvuMc{k>>n9(+=NJCx!yBRqB!1`N4N(YQA0+tt
zAimfC+;1m-_O}*3{F{j&<B9KnCbsh!r^n at IU61Prn2W%?Vt(Ia#Jrim))B(<jnU-h
z`hNf6O+nIc{^dW=x><kw37?P?;fJ<=*q#_v+>_UEU&K3he?PfAxD@`x7w`F#%HcSc
zbHs%a&l!gqd*m7MhTk)HE4C_Dz7Kr-CCxAKhYxR#2KOFx495$#o{qO1JJ%L*rWmW(
zpY;Sjix`8OGrw8u%5T<89U+f9$Mt)>zhUM2#QP?EesjdY823G(Y7p~C&IrJdU3=h+
z;0icn)&TO|xz1Vxvb%EJ+!^-Y_%m!}l-=5X at t$(lfEPH=92(=AN7}w2zOrr?ml~eq
zbKyF~xo`sGv9|EvT%VxW8k`208yM at p57tv_0`OtiheWS$uC3-uth*jcBjB&WRn)o<
zpf%vB_#OYsuMu;^A7e1Ccq(j69E+!-VI+6SVe(nIUHnAOi=UdC;G_VY5gc-I%<KO1
zZ#=y2XTYyNyzWDVXmmFGr%$|cMDx_R`JAx_`g-FvIOpVfYTgUq9cww)H_<#QTNIa?
zM+cX_{@~J$Ps7I8T7Xx at t<;I)*2%BGlpOn}|4}>}eiKK5jhiZ;M*W*{<(QHNu+Duc
zHCFSJ^@p at a@`?0S at bM3Q{jUUREc9)B_TJ!T)kV&W*o5mGb6n54l(F}@m}AZtUKQ8=
zN~|T;<Ty-FGl|EtN7*N9=ZepcQNeaDn-|&_ieWJP1n}D{g~yoJ2=w*O8p^z5{_S(}
z4Q*gwm!GqihFzjYQMc?{I7GDuf5H*ixOC(@L(i{z8d?VZXnrV;pq_SpJ%NuoCi;~R
z0D7A^?|spTXYB~^lUhPtOz<AZ7T&LOYb?fPd~{UA%@2JYL>&F^zfQ#O`YevgUdh*s
zI(4T{La(VWh**OY6YgaS at Fl+wsE^XIqo?SYPyN at LyVlY3A9l*PkNJ(bSIvyLcfC{{
z2|vN@@V$7~u at B&1X^l^3K9d8X8Od?wLd1g5IT0M~ytn}|bO+*-iL3L$el4NqVD4dl
z%|9UYp60K0STp4sFZI$<<KG$_)wTXWYKT92_$QzG<A?tT1e_sWO`IY<00000NkvXX
Hu0mjfAuR9E

literal 0
HcmV?d00001

diff --git a/data/fullscreen.png b/data/fullscreen.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc5a302d55f2d7910729aa8d68358160ec8d869b
GIT binary patch
literal 3406
zcmV-U4YBfxP)<h;3K|Lk000e1NJLTq003YB003YJ0ssI2ZTjGE00009a7bBm000id
z000id0mpBsWB>pF2XskIMF-vj7z8Oh`N<{x000c_Nkl<Zc-rk;*=`)i6|GZM-95wM
zaFMuLj49Fbg5)7F3_m1*AN(WvxqLwWA+V76$xB{>7!F{FG9_}jh_jKs)Xl?e-Cavp
zYetl%(TI>BPIq<Ht#h|?Zx{ahx4$RnXM_Lzc-uKm8598K{UOE}V|Z=X-|dH#qAZQJ
zcGmvzd31l9;+UySrWc)T&{t8jxxKr&+KPgJh-fJV1R_SHqDGP>Y4=JAN#OGKzyHp{
zMz(Q(Z-4Krj}8wu))SRwiWadW`G<Q5NPp(th;lM3&bgH0^u_59-+%Y4^CI2;AX{0L
zap$zLy}Pr&fAsOk`w#ZE+AFD2ifED2VIC`|sw)?TJ~9o<7-NhJ5rknJCu-0~@8#~p
zkD~1 at nE-pO)>n at Y_a5wB_xfj-mjD*Cb+kAE(Sl%Q12s($6a*(P&Q4x-rIcShJow$C
zBS{QVC?9OBZM9d<E-yRRT_JcaOMO=+bfE|`iGC!YtNySTC!4M2?pph3>z-tc5wSE=
ziBbTB-~zltKIDOdg-aL<lAujz!8qrfgL80z5lfYdvrIC^7*R$_DPmv%0Ompv6$Ul`
z{w__ddsaTzPwv8a`Qz0qQkhcH1_7(9$;oa4QeuoTl%!RX9*mX-xqnH!m#nrZKL;{S
zm#o$d<;gN~*g&p5Z<#*^#gQOP1&bWkY<2}+#z99DRr(}UJZm%#Jp5c4n?8Dvv2 at BZ
z;-wqkBd8<;Ifcy#L&Q+D?>-Vk&2O=waTetfO6o#J1TkQW;N^x<QE+l38kF_6;ONN`
zX at Dr_*T`vykh_GcBV}k;63qV5^7P_e&NvM;S at UG^x$k({Dq@)dG_ygN*`T~+DZk(4
zJ=dd00 at FN{C8~nW6A)vJ2uA1-bRSg43;ZbpxV#=Cl+ZbXip={^&N=6Tb0F{SDCb~N
zM15XLO#8Yb{6|scU<xnGi#0iIvOInAUn0le<Oky5x@(fNRRBWDAPA=NDRVerm^{ui
z at ixZv_D!sjkQx&kGVhY7L7x06LUUxK0nXDTzC1fSy|^^79i#A^v}GZ;D)I>P&BhyA
zuwRud>qsJtYFQE^EoTK-qtRU5*Z`lnbL0dhr5yBnKmGXqPe1=$j$|uo9r7k|$a{pk
zPkd!!fEW=27zeiZAAI)37mxzHsA3}oC2`z&{`~6nbZ2L$)movctZT7ZzkLDe+5y}Q
zhnMH)D~%}P2%1eHIL&ggiQ6EeOsTD{t*^iS`r)I8S(*|Nm0}?Ox!RSghLq`5uXOyf
zI1SE)l=9^G_+L-HiJFar&5bxqLn+m$a)FT-!$^sV7_GEgkB*K$`Rvo~U=SyX7x`M3
zY$r!nJKqTPpCyC{!XQy9Y%~PttBvqB6#~eV%Edv&wQ;aGNl&h>uls|M%cnONJid-c
z=f~uN%OE_yygKjoT2Yi_S*hqXi-Q0NA#R3)XHTEr#L53&oL&uvd_u3Giq);Wz~33W
zHPYYI_#l;YE`;p7c>c22i^5PZcggAfobw<EPM^R0_Q{hV49~jVVH`s%armza9sy1@
zOEfoFs>cM9_;%3k20J?(P(;WjU9uEeGh)O at aI_myLrOirc=rSZ;8uWcZv!bgpo|D&
zj47p(Bx$d&fBEOX93CDfNs_7Tolj3W=TZhI&yK%+@}$8z7*l2&#267NrJ^X>KR9^!
z_;G(QOp at fTh{o4iFmio_;6V_^X&Qu~G66#7kv5W(%F_N|@bv8bdN?xD&{k1JL+4|9
zr$%CyP1;7wKb at QbCu)Qd1uqsnJ3a4od#lYxrpoOtQXhmA#YuWS9A5VNV(i9H?NKmu
zpH!^lu<E3g$_w&0SK8A(1w>O73xeyxU=YVq7!XnE$r2`(3}6CWa4s<U7DkpYH)m+{
z3TM!kM<v7*ZicD+L<WpNLn`z!wZaGr?9I&0b8ybNr6oaHQe*(&qrawK!KE!Irt^TQ
z$^<R^flh|8B5zh*u7xR`huaunmc{eYBF7XDn9WFAQw9J|Hh20PULvcRg=p4lu%?0?
zSyYU4x#r1Zs`lzEKU<6k&GTgWFsQ&uqZksQmQQ(ub$M2^F0WsYne1VWq^F`m!4wi>
zj(#E6 at BQw9#nq!;0zAjwnCiFV{2h$A<LafVZrG|h<y3<-?BUMU<c&zjf^P8N=8WI0
zm~39`RfqJU4HrB8MU%OXt9UJo`mVypAxv4wv{1HM$VY&>8?><)uePgo`4Jlsa!%WN
ztI=)eFPi-DnJmf;41~89Pk5zUTsCMLBu!fw$P~6)Dg`Jf at 1$=coN=>{S;!SH4bc;o
zosq59Oohw at RpBnTixU>!;Vp-co2t=r7 at 6M(J<ov^H~Dy%jHxEsgj?8DvhkosOp&d3
z5tb2h<Ijj5Seib-h%rJz-5dy-qucE5Z8Cy04nip#o;8=uYzoLH7dI#E#=39rTXO9P
zS$b>%XJmv5KZpVy24fuL+VZ7|rX5}k-l)?{h|Yk-Kk at Y`4J^2oR%evVhL$g7)>T9L
za-Q4C7N^%V at BaNW{^OwL6J5F3dk{H3veItB4_SB(0LQ`<#YF(Q*T~;v#4Ti5|7P-t
zIB4#@uiN!E{~XMk<KTlZx9YqLiNAy~Ttcx<RKXn1VJmFaVzM|wB6Dg-7W7rO_!X_t
zG~pW&MaXf|v%Y^UvqvMR4T8zOmneUN*&x6JxK=(8WljM#J(~?vUL91W1=Hlm>BX>A
z at ey(_qf~k^lxx&eJ3+Ow9ve`I+1`&vWo+#~!iak?CHW;kI59R;V>@~;-q3LH_5cR2
zZ!{Z%EN?ThB0=PS!@w2G<az5lZ^7CM9mHMkifMDUV$Bgrqr^$$?Xf{%cQ-jlBt6#5
zk`02P8PR9=W-G$H`4jUiC3qQ2<UN)v7hCSisuMwO70g*C1N-X}*32VqpIWO=>gJ at 2
zs<Zj`RFFFtgLx0g^!jP7gxROE?mwm*J3h#AcMLdf5Daf%FDDg5&NxW-VWS^woC9B=
zSg+TMTBtM{75q2VbY*(WYCa9+MgP07h7P=S;DIxeE{Uyphy`qgBU_LTt%OcC@<+?F
z@;AWZ8R4{Is6$4AnR<eAP>~u|!8sQ~<W6D8Cn02?9Tlcn3=wFmKg0^HGO#6*w&r!q
zYaZ~i-iAv#=UfQR`Rsfp$Lmmx5jbQJ1YsBiK at cQ`w|(5(M`X#}wb(j$<-{tLJB&cK
zK4~g*QdZ8ud{#|~Y2sYSAP`dKqCCu6$^bbtjsOE24hFv-A17IMe0JWQy$)4ON-giG
z80T7ea|PuqC&>#YJ2VCztZh7g2`@AOQSKO&LW2*NQl6ch+zfBpjfOcFo9ZFJFVD~a
z`OQC~M)RWAAI1qU=xE)L<8Fx2xt=v5e{P1utMl`%%?*a~TQQ at 9CP^t3M$y*Z{%stG
zVZ^~!!XOX=<`XL5Iug}2Z~xv*ho!A`h=50=NURkG_tx5nAAZ<qGzNpdK|ooWv^O_D
z{o|hwKmO!{&GpqNOqEiK*fM=qTCIDVo7XR2Dy0kv3WD(d&Tf`v+w1MsC?ZC*H1e4$
zN<!4Txyh6glk-hv9;K9JgPYrvG?jwe9HdG6$sJy3YNMZ*NUZu~GykJ_P%9Rnt^%A3
zAv)cDl4VkavnEbV-7Ha>roA+Aw69nmN#u<Cw0rfgZgL6;8o5ihsMF^-5Tk%N7c!8;
zI96)*7L?2%{Wh&8f_WXCVl~Otjt;&fSe-#7m58c0uk#`$Mx%3p`Sh&l{K*Ri0vd3H
zA%4e=VD7`8^=G{bHw!QKIyszedKPlYi<$aB;n#3st=U`R;CarVsC$Y9=?dqJG%W8`
zaxda?nHV9aA1q*ij~|5rOU_l%t_ojR*itU&-T~FKa*sLwQX at SiDa9DgGI%k~;HyK^
zs`Di*J7jTYhOP*D6)S9;mAk)ul(>$TKZ*>;0#a$p6p26vQ4~a>Oj8cPQCass+LGBA
zMSs?r>ZK~~S=kRXm<ULSAP9vNOevZiMI~FiduTRKU!2~?$?^F`cQBk<aw8u`T6{uo
zn#yFjL7FO~D(EsC at L?bf3_&VYM+jrZ;t)b~&N{5wYOJ+o7;-SV_xYEIZ@&NTyQF)4
z)*lSxWaR6p=p|v^lPd5y-973gmSbXsY>Y~t%%DnO6HL at 45h;aci*N7UKYG+`uSqbu
zvb~#JU7S7tHSPAK6zk0fF)g0AuaWFjS!I_49NMc32u_?)PO(59`dmC|WGo*=Y1UY8
z-#dD=_uxS{O at HZJNEP3*AP5c~?mhnG_aE$St+q0iDIyP(;CXnL50BwPP57L~$f_09
zZ3l>C7&h8#-6Z|_v~$%TO3E_Eg;-l}-`hC+=;&Z`J;^eqRGmoCXC8|^LX#GBrOB6p
kNydKZTwL{sPcN?i4_e9s)xMViO#lD at 07*qoM6N<$g2DV?+yDRo

literal 0
HcmV?d00001

diff --git a/data/home.png b/data/home.png
new file mode 100644
index 0000000000000000000000000000000000000000..af9f60372169a77d2bb18decbf52bb769bfa0c59
GIT binary patch
literal 4629
zcmV+w66)=VP)<h;3K|Lk000e1NJLTq003YB003YJ0ssI2ZTjGE00009a7bBm000id
z000id0mpBsWB>pF2XskIMF-vj7z8CG*mP$F000rRNkl<Zc-rk<>uwy$bv|EJb at gy&
zdbA=bi4 at ms?<J0ZSZgDZ>;M7sCV9C$K;Fa)L<Uv at Y<M9VAjKi68_AizRMp9kzD(bz
z$r)+oC=?-R$)2xIpFVYN->F*s=YRdTdvjs_`eX9?JRx!f(C7N)99ye)_ji8tNZs9|
zBqrw+zkThN3!_K=-o1nAbfi6I=Fd_;U?ygx{e?^7t9Mo?7DDmgo?Fk4f-m+D5C7wz
zzxnF!7m2lw-DjvEA%v3Z)#>REKm6(M=ci`x(2S?bzCQQ&?(IE%_|13!^yODa2X}(R
zy3bQVQc6$j#2ADNd3|~Kt8e}NdnzH^pHBY$*WVm{breR?UyiRoQ7 at D(dwc+#+ at T05
zJWv1q{Pp~Dp|$?EZ+`WQZ at yNJXykcc?cTY6C;02}^_#0}A;hPsqHQTCg=$xjRGzt9
zhKo3v?Tik;n0<GDU!@l$)*5RG5MqFSx at 0YG%v*YriVNMI2GJ%nNC*f(2ta^|jB~NE
ziinumId;rM1Q3XjtB8rH64NkPG$twmwWCqDrduDZiPn8_mu|571j;uDq4>^%zO&A$
z9xbQOQw#cB`d4l)-12K?WD)>GOyCr&iiUQrFdBM7MMdCDwDigr0lMBpdVi#<LW<X?
zYSm?eOe6uNloY5w2pR at c+_dt906Au3on>an67ZA~B{Vb?#U<_3j59?`N@%HUShwbC
z_hLdrHdnq+{@tda(l5cxO3A(HWUM`cxP?y<K$w`f%kVmi*(IKkdz10l*PEcdSw at Q}
zGR}BH>`lgF|8}xLfWpMSU51M|cI=oLsp1;ns-ff5W|^6#5M!-(JQ;<NG3I6>fLMs=
zdNH4$EfO;cg6V8F9{D?JBeb*mc?nH#h&G>}FO3OiGp&7QuGvn{5-YnjL}7G#a(sPx
zS+d#nuS^I?Dd*=G|MTNB=jq at 6>*M=-dqT)9p*`6a8hiftPo9hqrnW=NsxP2`2r$-M
zUtV5ay&vt2rBcK^BycbRKpaPBuTGrONgN9y2{0x{8;zw>L^nZ;a<nKCLR8RhAzKuk
zy*gn}$5AYVuuX4<R6(T$2XJv&7VR>R%%jox!O_up8nAP#NYtHrNGY}UV#3a3vNSgL
z`_zZl9rvY_+Vf(<&Umsk7B#e;UNr8OZ9EBWrWusHa9I-7zDA4Clt(}5sqr+J-M#Cq
z<<+lxA4%&;5O|&!T9+jt)Q#4g&Pge?rzg`uX%8t{>FK5FK;!nTHIr=`c-o6X*S{#$
zdXwbbZ9C_zb=L8KQWiwcTDGo|0$`>66wW!v>^keCQs8jXvU3e-*U8rQ76Ee3GCMA;
zp*ufSZNF$uvN->8L;6Meh1?NEs%X3>m(DIEZnM^2*|<ZtQp$?nGC?&%TRn at tbybDd
zxY<^1fQJ60_BRH|a66gv4~juI*s$`%hEn&6w6&_3(*ov3c~JhzK|NS>{wH_7DOAJT
zpsKZ2iZJ(9cI|ab!@RlcZlYwWwa=jXFk5I>U<(*EG;Ghj+dYCRx%Tp1v+#(P&)46{
zIx8p;QCc26WXW;+OX7xVGU2)2*BD~zm3WD~?NPCy{&$Rx-x5%+;IR!W!nR~9C4LnR
z6v(QoOYR8~Z6=5w4}?|P)AAI}cfQv8YuZ^ST{F2t)6s*_6E;Cm-GcE}{LU7`%m+X#
z!J-{r(Z~7v8K}tZs8W55r}^}WT689TqUNly<>0<;sH(sD2%1;@E(ipGga8wylv2vH
z@>z?UUM!?sLFJsmrf8Ku?B-}(ZZu$sf>2F$1%#9mfTumJbzg&`DunO*p63Z6O7Rg}
zL1SWofUTfWdkMV8NvB*5b7X9|Sj;aj;wVZ8lc1w1)y&YP^gQ+Q#mmKF0YDI#DKchp
zdo=Imix(Lh;M&lfb98grQ1t7WYlTdzAhcJLfN}2aGMvxPp8oi3esVINOqBM9uX`b|
zSS-)a&h{Q02qBE)cVTogKff)SSS%LXL(645I6yCv+?fY~$TBaYcxfzqnmoNU7S`2r
z;Z7DhCsy|!96WgV(Dz5i*f=puW7+e|Xk9V6jLb|#+=CWY(YP10Abs~A9Na&AsI{M)
z9*Q1wkAhaQjvYH^Cc*5{<0o+x0kufTO`TG?O-n=sDTMF);~+?qm>o}pAVq5w9q7*s
zm>4<QBnXl?cFdC;Eia!i%!V?DD233zKMtlQG0ZGPOPp6!?``I7Od<hjAttln{@!lp
z9l3TbS8JJ){eXzzm at K=**d&h0IW6U67Tnw06+-4_(e|>-#V at aJ;FzrA#F!*W$T?ri
zTsGN7fVaMa)TcNm>s(@O635nB<WaWfaa5_ysZ=G*>?yfB8IOG}goFTbdq=osjc}GA
zM8>`i!#FX_td-oGjCXu3q=W!-TWhsuja*952$3;w!zfNDMcbW>$0IF-1h8H^bp;_Z
z_FWjp#`O0uRY&E`#4I6pv>r(rMHzd^H75@=)>PJz5Xju>tNHoT*hvsfX2FiHca#h>
zG-e_&+Pko*P&-J`u5+|mFqs9Dksiqmjd?(ec-7f~fLL5FPR`ClV}scp?faG0Q7X$+
zU#Xs2K@^=HA75XU*h>a=xuZP2&DhI}i>E(6W92`3{N(=bu8=Y;(74Kl_D=T{T<Fth
z&)D-HJ$`b3Zx<p*8_ujEO)pnyr2XGL{=;~BXcN<FeyT;qAY$aBE3n2~UtL~Zz8~$3
zm8ZC1FS#w-U%8Hqy_}z%kf-A)O4q3=&_*RRuB^@0&RNRS&QDHASJ852RjHC})Hk%m
zSfN4taU7MIRaDC()mK}h2z)%+89(^)Xfhp|+DR!r?IncqB;!IEOxYhEjW$Lr{^UIE
z?a)$Ele^nms>|1++7nlvnoNT`ckkN4>3qtpD(%75*~^X4tgEesjnKjvAe1b(mP)He
zM~%w~#p<Wb?3}$Jv+A5HD!_7zQbHT_NENh3V{3ESdV-&7Yt0rw72kVfW|dc*4C<{<
zE`M!+hRtOwN0(;Vr5fcyr9XX>b`y7WfSU1zduW#K7m7xM`4$tceIG<y!lXL--Wc!<
zH*IfyTD{a(U<~U?V{oSwy|v*$z3>1nV9mJAP`h3u1~(*c3~^Q{OVAefCEz2y{|{rB
z3LTU)Qy0rOq}$P%oY%~u8Zo)o0|9-!BdR=bD>vVitt$U2$6Qf_qETAqt>f+OX+a0A
zg`XcSC*1Q1`zE_l=_vBLa=78eFmzq at lEhtIGu#TTzXR9sk9CFD9E;j?jeZ)T2%CHk
zCC|IEBivX)KflA=5+<6>N-m{>JcQNw48J-Yi}-)d^na;tee$aRCcp%-5f{25YCkD7
zzO90C0|QacUTW?6T31>M-E%TId#Qv#HoprJC1$k+t at n|9-%oc_Wo71;(AKJ`Wjj>X
zOC)m4k+I9g;_TugiXuZIV=rm_EOLpxT&|c^Yp>U$wUq}#NY7I*U*>4Y(UuLgt{G!)
z$d;jrRTSfD?+4AEG?kM980X%G(fsWE>9gnalaujyqO>=FJy<o8Q}%NI;6MmroqHdK
z$7knHe|)~;Lf87sVqO^~G$|~*cVT!^md*2q)?}${%jNm`+5UqA)V5|;lSS2%TIM=(
z%*!}l8cW(ItwU>3+u6YVZ5INte~@yazOgn=OxS})eKia-K~&HZQ$=%bP+e5?zJdLN
zgZqaMweNGztgfH#;4)>w&KNhH1>dJ!XtVXzU1O*HVjyELr$La!v2__2n#56#H7MiZ
zf(yk8%{iU~CE3bo+?Na0WSazmF$psZ$aPK{mBj|Y&zV(}*~=jtu=5>51$)T_v%0 at 4
zg=FHJ?pMyxN<8hjDO>+i#fmsd(M-Xt5=ijc8AYseOQw;McgGnQN)RpM=-ut0v;s`o
z%P29<v6kX)%F~w7hWFf3v}G8vam-rEHE7&d@)feh#xPM&o1kNOfx+wq#7Jvj$|wqN
zyf2g>gt%U0?Bz5FCbQYt-xk_zG7H9j%B*gL78x7d`NH>oX4hH-t6m&}Koo_i$H!Nf
zm&HiS5Ft|b^6cW`>9gmg{qG+?xwp3`q^zS2^FnQCyK)<7(EjhA{Bd%4nC)4u)?zKY
zo~v{Lh+vJmy1cx4|9&(s*vkQK6$P_;4DBaTEQADvsiM)q!-`PiX|+zGND8qHv}5Se
zidk(t^gxxz&9l{29&AbfX5JZ(9~^zzH8jT!kEEp3o at XJ(lWAnLJ*$}`W!@Q&501V}
zQ at f#5Uxqe`tj*ZoG_-AmHjN5ql~*ZXd7U*Z2-SS4xK61_5Zvk5W!e-<6?;~-7l#hj
zCTM|ngW at 3H0UI}Y+FPS(FAn28FIx43%J|JZ2>Gtk at _Ggr`$C;#x1POp>7LbWmuYPv
z06ExDG!WSot>xWqfX3zOsym9IwclHFR>f%|?gs2-<w|T14YW<!P=A5-a=l3l4Xn0q
z(2e at E$sX>0V$t2G{f8h!w<I1q_Y#T5Bk%`$tSy4^_HC%aax^UnMW2HUjp7qt79XXb
z-)NZSTH#`x2ixDQ^9kvQyX}(O!~8$UIi=W=uszglJ1<sa$GNX4Zcm}t_6ISn>$i5p
zZ0nd#|J*?9Ib2<vbF+Vl55LawflU)zaz5?H2GsjOyvm#MW4(C5 at Os;bH4(VehS6;l
z>uhp0NWi_v1fr!o(RDSi<~VD&7LD`=RJn4at?Bvx7gQVL8@%({jvDaR{13{ZX(g^&
zjeiiKIYE!|Bu~ECqvIV^?66k%=4V^gPdLC0ABMBmGcs9Le9a1t*R&N;J4&GSY_2|5
z1NB~KdiY_sFBI+UC07@!%)iQeF4B`7hwn1wQvEHJ6a^ZW&;SOcD4}s*SDL6Q8yYp}
zx|VBR&=IG%mjWyH(%077^ysGc5Rw19U{)bk)eZy+0VyN^tvuh;R@(XjOC2Yo`M$4H
zw9?H5AXP4#r>(HeymkebW#if*nW!#;dNsd_aXGVU&2q6kySRv>$RcMiUB@=qQeaKl
z%NH+RE*A at e1i(bGu~%iZS&0kn-^`Mtz0A=F%oH1Ywan3ac-k(s7cZBK1%#}01)3d2
zfXl9qnE*~#xpnS+7 at wY9{Q24Q`N{FlWa_2tB~zaT6)!<xxmcW^o$VhS3IXf*T@;<1
zUHtiZ6|LjrwVzhdBrNA>HQ9!pL|jHg at 6=pdCe0ZI=a|Ddj;s~_2znG-m$-On2ucI6
zkoyOR*)CISV#8ZROAJTW!uK~s(|*2Z6=)`ps(L0&xn0lfoMWEdx%2xce~9C#|ER65
zVP^n3-(^ZfWi<3=+*H}nUUZC+GOH$zIYawn97m`eX2t6~WWMVlm(3cJ(p=QL6`{om
zuyfk??;jp!d+ at u<fu54YIcJP<))G+-t@&Qdfwq!5<iF=C+JnPG2w6%4c&&KlpQp01
zwFD3YJUEIKYoD2|Nl(A55clojy|s)=4}MNVv~xLH)iZNz0fm;S|CIJk(U`5V1iL2b
zs7b}E{(E``V=23-_r+8?*dT;RhpvPa*(ua5CorOZB0E<ffNRwP7rC7vNuoAgL6r$^
zG-sL6=5s+{vErKB&ivxaW?HJU55!fK0ma~&5K<@!At*bxF;$Q?U{*?czV at _M){5rX
zMg5jd1?AS=)%It!og~lI-?puT_Mp^pmi9^o&3jQVU>^Rpr<5Y+oHc3wp?2;)aQ^7@
z)oGlVS8v{3hau2$FmC$><^0*WzkN|Pz}DOejq7<}#}$J*DC<5U1f*2+`KcR?{a~uJ
z7J%A)^e;9J|MbHT_WJVmA`Fd5i<}M4=KmnA3LY%O?KT)?)UR`HG&Xnl?|l8WKMg!$
zwX=6GdH3e@)v<ejsXcG%`_w&4f at -^AT}&G?j0Oz2p4*MN^LR+yP&;`@W41;I)7jTw
z9~>RMkIhf#ua!$;Ql2{c<^FfS{@pJg-kVL0Z9k><|GWjIM`b9j{b}$nHh+0Fe{;Q1
zY%K|aU^d;~{pGjcezp5WVy$(b=l>syh)4h)@lWTk-&`+#x_I-yU+}0HAL5J?00000
LNkvXXu0mjf_(~g-

literal 0
HcmV?d00001

diff --git a/data/icon_ivi_clickdot.png b/data/icon_ivi_clickdot.png
new file mode 100644
index 0000000000000000000000000000000000000000..711bcfcbd616fc6715053a87bc2cb7410caf3493
GIT binary patch
literal 39523
zcmW)nWk6KV*T?U&bax{SQnG|}EZrRnNOvgRwRAV=(kUq*Qa?HcL{hrDyBi+<&#Sp_
zX70?KbMKt<J)enESCzv;Cr1YW082q$S`z?3ua6)A75TOK<Wg$&+8|m>s7L at nO#;TF
zDG~r=kSj<_XnPqQwR!$D{GEPWS!UpV at O(EM3uZFs9+VTr$d6?R#Z`!8_$5zAp9oFQ
za*e0k$qK1)2AD<o%zYiq%@dBCDMyFuca{z6+jnN{ujbo)ZqS9Z3SEmT%d7nBZlae?
z9$N2?Iv%z-1IeEDKXmNh%yc~08xzVr3B3sMjHL$+dm=v{pFCHsygcT<)ULeT8^2Vn
zyxda16dHG&1l+WY`<}Fsv|Wq{XOE|cU}HIecu$X8PGpVm20s*32R<EWbl`~H(yYf|
z18%@iDX_sCtV=MG5b$%0!!Kg4qVmrFW{Jemb@=`G);HtjvH#8o*$Q7r<o9{Hnklr-
z at n&k?`f5Nfw6c7%Ur`-z<ahRa_o#6t{<!1ixwxvUp6|;dY1{pNh3uGXCI7M)z0cj&
zx55D9hxr*zVAZr~&UIAun{ZCx^WCK+6<xWk^ifvHjFB&g&p~CQ{=ZrBCgjlW)tszv
zH}4*?pXx3QeS7Lngh){&<_0={wC@(gV2Up}^<a$?sELe^-CY|EwOM|wnj7HxuOGoe
zP3*2nk9vAP?SoNNPQd+M>B@(W`zb;IT6uS|Bi9p-^_S}5uvX3O>^F&{2gZ_NFEU8v
z at w8{pFQ}KZ?J`+!(mL0F8W%b6L(@y9V>?-;VGAEZXa!}i=Mdw!PiDj`PubS6E^7Zv
z4SHKIRfb+e&n2QIkA=_SUhmp2|3zA(8s41sQzumYw;ny at c)dg`ww-s_M5}nbz}i{Q
z&HvmaGRoh67Pq at 2{^BjQk^6F&Tj)9>*x$-?(VfBXgBAZW-PmsF=LS1y?07nQ-AMP3
zA^mTBhkoGL56p|4576rYAKU%B>mH6<2+#+pavv6V3SKv%h7rMG2jS}4p6kyyLl3?3
z_mz6Jeaa%5Tk*ojkzbnkiU(bzcm=K|wF*mee9F%S^X~)?e$)=}{MR9o*SPFcp`k<V
zvzxy=B7DNDzv at 0?XpKr5Eb)C9T!BLE2N8OCyx^JH6p|MQHeWr6FA&V&J+s<4Rq=ts
ztQtLfsqJ|Q1Q_4{`&K|7FF+ at tDtyGt^MRPX84TpnPhSV2yotPTdwG5+d;Of0vjn)v
zd2Q5>cUL+BQ2_E&!jNWpRa7)4p_ at fltc{CT-!gUtU`Ro?cW<mD>}bMFS&QhBNfCEm
zm~;JpfdF+%+u<|Hzg(YCGV#iW>u;aKNQ at veFfzffGU88{6Ffktx4cbf)DDnEgUgG6
z0nFCCI#p%T$YQ2F7~ju at ebi&wdneuXOUIMPh3HLB!1mm at fY*mQWq77Fg1SKX%6K at y
zND4c-ZR3YQJpsV}{5NL+*Z%%~ImJd_Tnw<w3Y>0GzX&w124f5f<x$~|x7=-K#&w?6
zV|@UdwCSnAim?Ip6Ah({zMB3w3n19*lC5OR>16cYQgTCx{^0^JT0PwDOd0)-fHu=N
z at usJu%2E5HHSd5^ikZ-w+t9mPDr5xUza7z=Me`~U>Y3;&kkUjBtajZUOjlM+u(JaI
z&8vGhB#k^`jdkvd5cDDfS>D^};blqdUz<Q!aMZC?f<#zN6ZMSj!K(fc9t>IFYzQ{C
zjSdJbB?#@my%>3h#+dn+BLF5rdLvne?o&GBS%R)ZlwUyrY>0dk1SFU3QX?*Mfy#wn
zOi1D2ZM`O!@1_V2r$lVJqyWsD#)A|sd>u~V*ve&zOG>;qbXK}olI0RT4w&dyA+5WL
z7BwOPY`^u`j=P?k-f0rqwmHoG!USlN02GFZYRw0rQ<TqP)`XNKF8l`E`NJc41EXO3
z4gg^Q5FSiy`BVPj at D;&$>&@jyYzfzd<<7?;8BZG^ba^~h>~1qfNOmhg2efJ}{-76%
zoG>lsdAw-T8;Lg#LZQUH<i8~ccoEy&fjp4ya%@}FAf_oeL*AP7jTO>&(|7QH0Vo<K
z;a$A)HZWihwYd=VpBT`-!4Idjk|e4FU_w~ne2^0dZ!`vH>saXtgk5>p4gfHE0rPJl
zz~py5&07lHbxOcw at 85UiQh+01gY*L!7;uU`bAU_g@<1shrS^c%(cvuZ*X3`Gmp3eY
zX|buOY~a42cHs*LfV^V>$`1y5<0BqJ2~;5f3{lpM{*Ng(Y4XZAu8FiVz(A*rsWty{
zk^Q<8{409yizop69|ABGWzk2uX4H;sQctMunS<lLbWbQr4nQsIN#eo1KhOXO$O$6M
z%5*Z|_=zMKYyl?_<I?(3h)1(A2Ov}2d_i_v at K<%52G|S1yD7|Sd`ZH<weZTFY8e{r
zYvlE8LMk*9HS}^14opowl=p@=|EB8-g<ukle(J%6fUjrEbt*9L>4%dZA#6i&hVhp>
zj-)9_vgT0B2sA<B at Y-cpZ5w#Bb;#Xq_U}G1MD_oeP0Xbvuc`i{9{TdxxkzB9tE1CB
zaYR1gKtk3sqN~y(Xw6%^6A@<O<S5p}iOtMQ9KVt6O<ncZu@!|0=>!SlG`x(Db_xRe
zDeU;6JMo->cYn!>+0enszCAvs=zh0r5$Rnb+EYNl{X}j?J(Y;p&-4fS1d)HYVE8CE
zH53JC);n)m1tw~L;-*}6cALnH#Mg=eaICUOpD!xl)@>NLKd;+0Hmw<gJ|ofH9Sa~T
z_c!TsM65Zaf>zgFC_|P`#0piggEa1_XaK;AxC#df2=U3{(44Byo_+dj#}45iwU!E`
z42i}m+=#8a*%bQp?P1m?Vk%tV&F517P4F!ME6Ki_``oz14TiX;SD^y9%{Hb#>cs)S
z&irVC(+KfL)4G*_2bqXBKBaoD)4RKc3Gq&oBp~2oNFS<1h6RL1$csJSZY&0sM^%2%
zxp$AZS1p94gHTap#?$+^w`-=nFF>oz;&)L=vo`L>(2NgAu#>=-2lt%?dr&dMjt&UO
zf}tWq(LTdm<@FH+G7*5u=GU{FpIpGn<hXMqQm$z#>L|-tc?^yO5o4{(t)EG6$pM24
zcuH^N7i5u at qr|~wv3Fs7Qv-L`ABT|eBNFFf$~-fxl)UdNoVV=&s_uQk?)@S66}Y`J
zDRQv}Jvaq(1*;g-POMm!erLg)>pP_EhwSXodjS*zOdhP}0|1IM|3W2uLJ^zOsCui0
zTFuAfu!I<pWL3Q(B-LcZGukDXW$(%+1dM at ***@o0 at m6R&1$Sp9us!{Bc~Z`*&rg#eg>
zBvCgBQuGBJmqji-YeW96_uz<&=>O-G-(*xfv&XT6=d$Mib0>1+=IhSBh};El^Y<aD
z^b%=abbsKBIDn5npc~>X7f-1-OHWfB2q=%L{0XKI_HfXedAqMNrqvNg#>1pvXOpC0
zLE9@?Jg>l<J!!pCQnFp?n)}#JE-K2ON}ckbHW^?woMCxBgeIYq!CS^%bJBLRY^zTf
zh87AL5TOtc at Y}M#yxb&Q!olqcQ8c`kqxQFubhS~?Dp5U3Ihn}ZZn$6<MZv`a1MYv6
zzOr+9|F+I at 4lfg6HTY>eQA{>Q!+}?sUyT5qD0&bHKFIs3r%dYobFv=EB8ww`U+(s9
zaJ&4%cN8zsx+)@ln;y#+P$o~#4aT1|f_vYdu7!oFz2RpSw~cS$t*N#JHnr%tqE?bE
z!!9GvNZ3D))v-*{c4F5$+L7C!119TaJXUbhg3o-3H*^t{E|Cf!0Z6fOx*4p1(*}T%
z^F3egO{j#^m%%Lpk`7dvW)A0ShfgwnK*BdCFnKoKF+#ve3JOE#fm3J!6P<y$q at nxo
z{$Y`D8f85%FMxo&0<T~*3cKyH#DZHS733Y}ljXr8&ygd at XUF`YVi159rJ{^PsH5-I
zv-FKz)TfR`j`43~F-evGq5%kyV=Nal@?Y>l?_<`M+~r1eX|tpi9vugzS=r>-0zdhM
zZ&yQ9q+yR%75E#w^zn*1_?oF>`43KQARuv_fJqr5qY7tnoBI9-nN`d(9RToiJy|ZC
zd3nyVU4<|gC~Wd90h(CrmSF_sRzg<Z%B-K6AcPkgenucKeYHmJcVo6z+2JoLN0wim
zO(Z_Y%Rf!Bt#<)AVcXY!tEN9sOz9|t<%hsHB4hG_q at sl62etroeu5k=LG-9`z(IOY
zOI9K7y^dk;=^y9a(mN_-d*+bWxU3!t7(+0jYaUEw8j=aTX<6A~Lcd}F0O;%quMC67
zO9=I2=O$##3SD8vdDoq^y^+V(Q_R=^fT1u5qB at FSjR-si-2FBF;sU^$6c+O<(7jRW
z1`9fb$Q9L?j at +QdVD6<qy_KI at J_9gf=rHWFgFFUZmP3BT0U8#d75WLu=O<p2Q%_>0
z@<;leb&=j3m~O8%{f<Zc5lmKX47vcoB9;PQp5juUUc(z3?w9k!y<=nmJ$6ifV1n7O
zF|GT%E^!cq<qG?j3<%P#ni6aTqb^B+KO+H?c4phJk*Z^%n)uUX>OlCft!4_~^mKtK
zlJMxVsQDy9xZ|enBt5iD<a4PoalPv>_DAjSK at A81KjR8D3e7XnAkfX;*>cPy>p6)4
z at X3GD^ia at Z>RWO6<1&RdB#eC#Qb2oc#>_tdhjABTS;0F+wd08aj77sgwk&C3_va1c
ztui(%fjcYIa(SAwz6_=sW(D+9d1irV at niXjP~B0w+^U+qL3)iqXF|XwJ^fjt9}1OQ
zqN!qcD8o!ACB(Xg7dQ^7lbPt;W at dBN`mk$ylA@~occ*>+B(G;TlcaE`(%Jw7Ll;!E
zibDL4zZcoVvjc?LemCsMH-+0fO|v>>ZNO2b6!lI<!NF8U|D+hRW$nmXOIDvli($&N
zh$AHFeqX2&3pj194Z+>(fD{YUdi6LDX>dYQ0hFbV=Yx(6>8x^m{JxT#H!3oR&+etO
zgmlh^`p%{v4vO15+2daZc#Hl7FTrc7@#S`!_ybSvFn~_Ce(JzhmZE$=zTQc%br8a&
zD;&;kO4>Xm<%kh8uu#ICKxj0CQir;K&c$Y<uIZ7TLt~Yd=n?3v8SlHElkMy9tURA>
zzeo(g(3~%6)0<4 at z=a%%JnEZd5ob|v5}V|*K|=}J-<M&<MYB(qH+y?4Wz4H&wt=#?
z&T1<it{vE<yoz8BFpx}wLaD-&IB=xirIDSKXG19OD;XV1@@LPn2+y`KWqj~Vgl8US
zL3HibVM{;TRXBE0i+7A0Fj>%2{A-m~sVEAML at B_gW+oqzKC~52$SYwgNqShl?Kwy=
zE=;-*>i2;AYyE>N0nkR{BHm2QhGhE$;-JYQS`;on(x{^Wg`J}#{~L(;sXY*UDavqX
zqxH^aXPF9W8;YEP3~2jPy7t~`%w#%u<8k+V-SKmHyjckp_c`rCDKw84ES at PDnRjBK
z`ORaFFs}N8ib<UwV^*-C=d^MRIspJZwY4m?|H)Fh2;7dnF>zCl at Lchqkyi)4>+lq$
z{ju5nG(@!iNJw$^2nlqY(Ixlp7^yKp{>h64;6A(_$G%dxakv<?l6IF0q;y3n;Bk at E
zg6#HWZY5J3mUa<gF?6#Rs_hkS(qcUQ6O4X7BtZ9xF+C!>gOwBAmHxfjYYL_HL#m#}
z=%T$LjW`461d9LfHO<r5TdEjR+ks=l9MJ#wA9rXIjg7rz^L1*WBHb5jK}+K7?91~X
zH!3bgTP<iKwNjpI at eDYDcsLdZ6$3E7mEINwpR)BUt5JY7d_-h+SZ5;8ccC}`F7JG!
zx-)j~^XQCs4)*M;X|X^+1E-N=M&R?`j>nie%%UGtL}I}=%f6$K;eX$i9%8epGvuQ)
zB6V at A4rAt(h}MBI+GtgSOAfFyD;OwiaeD|#2LXpB%0VIp1yrP>*DP2}Dsa{|?w_TS
zd70;=E^oY;0}E4B?v#)IYpiVi?^Q}r&L_5CRIu59bxFsyJ*KH|X4FE9xEEGE%A_Kx
ze-kW<-n>c69qBB6oE;qAM5_z=Z^0ca+5glK_j-}C`Qa4%2imZnS9R{o<4$qP1Ww>>
zkImKols^;YLe<rhX0?_cIIjl_O}O;TJ0&a%=9<8_DDW_b&lh3jCGU5SjoXZfdM{Kn
z))<uhIV=5=ogwRCT#lOT1-XfA)64;zW at culj5()+8%QiyBIT?mMUgdb_iJ*#Od9c>
z)Q}@1$gd{AA02&2yp$#~GfucM?;C%=w~-*u7yA-p{MgN_nV*~#TGd`vc7-_Mpn6k^
z323i}8Brp4IZLO%Qx4YdT0UV at 5S58hctJ=`wK-7vYGz#b1Y&>W7l3G7z3k;av)m6m
z2AF64cNiba^ivRSlS!a;z1dQS348)}@Ootk)Ex$M{DO{~NwEL+U<(g9Fd|<}to&>_
zo;p78aCav=!k|Hh at BNeh%X at 9#*~c6d)yF8>CZ*Z3QtR3_O_insg1OVI5#+hx^wX4E
z8vosAqoXM*K60A;uut%jgh6agkFqh;Xs=B^AOHK5ynlPd+4vVB%t;~e)s>(FDR6q;
zvl|*^(-$Qgwc+SGuk%fs at ***@Of+QSvOkC|I49yy5|7Nc#MQ3fCgSl)%+IRn at 3
z1xF%*53mYT07~9XiAypEn?$&r8fq7jENBF^W45lhrO%r9QPvVNjnkjKYB^kaelv!i
z=?$9}cHOt37JEIjXUB~R&OSVbyyp(DF;%kFRJjgQ6N-w7>)%MJ_e>KBHnNU7De0~S
zT(h?VEDDRJYKU1rn})c9g`BjpYKS3qmaPx|qI46erk?SY$R4jl at NI7o+~Q)!$_T_x
zZ?);%^SlV?J1fr at FmUsrbs>yE#Hlh)hsX3kyPp4bgEy0F at pG$TfuZyyC-(hxXLHs-
zCfPy<zo_`CG{br?ff{eDS~%0NCf5h`Bd(rVinY6)T>hbiSM%Lj`b_9MsE+;v0SW=c
zgmTnjO49+y95J!;s>wteXqs*sH)QgD74-mMVY7bLj{+keGsx+<pgj6Ef0Q+W4KM)E
zCxi!_#0mB9y-nFMiJlyX9zt}5$33$UvAqFU5E4i0{Wl|@GUq{~z^AL?T1_<(gPk{R
znKczvYA66A03jdwHDesOw8^8L-Fhs9U8Y8dKP=~Ts8J+kGpe#EVV?gE6c;w4Y;k|3
zTVm-sthLiz8KVBbo<%*Hck*7f{J2C7Vyt4CPY1>?&Evo)-#2nJ4_t}ka$GohQ!`4H
zzCEpuQKLU)z(D+abQ6>3G`0`d(Vqf;-Ij_-FEKl#xb~_ at OA4E`@XpuZ-7xpgED)qM
zNcZitowUAo(Ik3EH;goCRUu=Jh;rW4kd0%`ea7&*UJ}755<wHA4!F%n)4{(!fCL`c
zIT at QyAA5~(5CcCSYRXvRCBl{`uX+B+c~DCi-~}`?X8FEKkA*CU`JE^afm#T<p19^a
z8KO8=2JAp0jnoz0ncMx!XI883WoE-~&EWIfIqsz+LD(eo1`bcyZ9s`%<4(GTD{?Uh
zK9Km#%bx#2W#_5JJe1g>7Qy(hYz`Ysj#^cG|J*Pwcf-W%(4X~Q9)S+YODkw<dkEEF
zzvXih0PF4lYGo{?{gPwxHY<MfWTUGD9^DEqXL$-{CI6Y278%~nb^A6t<L8$$#6|Cu
zY2E at 3Y#{Mx-F1O4URkZE&Jf~2Vx814Y*z81;bK-G_+*zpCE*Q*0OCxgf%V8i+0Nm+
z at Lz4{1Nud^_+YG(>c)=;Rd at Sk2Va~4Sey!u2)=_)^sR}J-Ic<8S3GlTzw2!brfcHZ
z#h4ThS=viC2InGsMtMQgm?4 at RbC}YkKIE-_L26S;WSeWQ&u7yZ1fU4Ffloy_x|yOe
zMg5eY-JoHpZqrN)FF8)Kg=Hh66Acx*N&&^#Jzy1ok0}7L{jO at uy{79z`PK>naB}$9
zpO<|xTn{-LtGd^uX!IDBm^%2Z0YEjeEZcESJgrCYa+&`D7ZV1sS+SHO&!sJaecS=L
zycirz36$;j;&YzdO~$;r#P6tM1$&U0R+2R(Rzi&@5Fh!U)2c%fy|j-P@#d<|dE6bB
zLPd(nleT_rl}5g<;(;+Bph$c!pmc4C<B3+DG|0z~GEQEUA>Ywu71oOr)P|FS`}I)C
zz@=+olX*-EG>qJVeDU|8^Az^xC4wa#XJ$_E`1dgXii2{FE*z6ZO*(85m6v_{>|y1l
zeJ?<{&w_1c8GmHS3;_CqAqvHNBR{E!5)gO9LQiflAJFNRl0NR__*N-A2iefBFSkdb
zk77;G??ow|K0*Xepc5L}K7MRAJTQa|mA4L2(^CC(+f3C<eq<MViHrpZv#TFvTBP<b
z_>abbrC$dQdmWB=0Bo~qJ(?|+;aIhV08=>x+ri7_E@@XRNa8<vl|wU9<d*+hhLdz7
zDXnA%yN6mS>_moQu+*Lrz#T~ASck`~Cz8bUCPR<B<iT5Bes4FOab+z>k at f#=STLjx
z-fZgTC0)8xE3zHvUM+GU0H;+3C%&G7;p#gI^J`+I?T~24{vPGjTl^Vj%&4aY3WNBC
zoDdro2q8XIKTC4jCJUv{C1YoYgzqoeN1|5F<-kr-j(pbq`FMFk at j2wuP0b%4Yr1Vd
z4vD+Q^U1`^IqvPLUp?_nIcJIjP=VR!(CLAqgZQZM+qZLJf<JiA87cmuZKF`W-OjJE
zb9}p5(}v=OlJ#|y(xiJ#hE(?DEFsY09_w+FS)7YcI0MjZ$184h9eG$M>9P<wX}w at I
z40)K1m!G{8f7(+UUcDQjU(FB^_SN<~|HIse(<#hbuIGkgco}B at Wg0M<l9`ldkXddI
zAAUzTvy<V~V%v`ta?4lwc~3 at pMR9a_Jv-d{R7Tx9QYc<uO$7lHS>7}!Z@#hcH|b45
z%J{1=ZUP0wCFfc<cz=7#b5FkN^`AFpTb`~L;tB~(Oul#r=zp&XAy|GnzC1}4bu at nT
zuSEtNpoh+rAF_0hKG8%bco+)g%_37_b$;04xFA5663SPU`g!CRZ&mf%wF?@0fU5CY
zy(qErTz!=ihYxpSFJe9IOR%uilczEBv^7T0(pD{co8%`5`~+YX74P$F@`(Jl*o?VM
z`&&5<GSdq=wz7ta0UAOEq at h3WWRFsx<(aZnOEVoB!#HB1Ps+0!7U4z#^4k9re4CGH
zq<clcTYYuVkh3$H)z%PiFRSfg#TgGSPyh)pW|5m78ILO}G?8my(M;3S<Mx5vNrevA
zhSi3!tt-oJ#_wv=ozDP(21|$tMAMXd%!LYMsVn at MKmknN09|cj4Q1}~YXbCGq{0n`
zqhstriLTJ#*sDbX=KjLv>>=<5f<W&!sEdv$d#BSlWD*5_yHK6Bx)fCaxuFc<%*$R~
zK3u$>y5Lg+VB_lMuazs~%rTu7muC=u5jJA<KG{6~So!yrr(;i*Z>E%*0>gZa7ho}9
zd^GUcH6>a39BXunATM-dqWERo7CQY^&S0G^YNs~9yMH5-rXQh0)p4x+p7r8lF_RI1
zE^bcIKP|}6G at vp2-=41a?7q_~<fGq<ROzvpZO(L|S7qR!N>FdpNI^@`hy|NpA#O;0
zlDEprg|OXV$za3f4n6(wX3sa}Xx5%mZ4FdV1riPCW*Qt$Drsu;5CHFOc{E8CG1~Xd
zxVUeoLKwcS4$-H|i?#St9fMY(y`dD&MV|+=!%#QyO5|j=(@p%c@&s5~w3cpmz80}T
zNjotaQEOCf6ad7|C{CmWF+ at VY(Z%k^P3qGZl`@_8igImNx5N0r&nDUcm*-4IFI3_P
zBK(Lreuep<nopzux$_pR<FAKAjwA5>{_+QcmH%GStn{C}U+aD7?Ww{gZ!PYAFACV^
z9)^aSPnO5hHCA+?Uq<bts?50 at 2B8^Rskt+-M_3OYw?Y9RZ^^vn9g2(!(by<)xFl0;
z at C1evO#})*txLPhU at _L9JY-ycTwkoTql{BT&mlqX&zGajvJT%<ui&40Cm|r4bSO;@
z$zJrNt4;hUrXVZAjG6rn>yO{UvC6F>{6qy*6<4KTEEG at +1}5d<u+&9aM(UxMP07!U
zYSiz^gReIJ&Q1$}6(H*=uIJh_#|+4i6mSLz`Dpirrlp+EaWOl)q`l<5IlA5ywMoN5
zl@=tlxLbsHi`+yO^aIWX2}~0TInFv6KAX=Z0&qEtyD{ac%JOxlj55E=&Z4dN`q9|-
zS6fKUn;|Ej$qBKsiraY>>dRJyBF>s at cT$RQ^6{$5<$T{4ZoJ3z-XSoBHutQ;5;+p-
z?1FV=HHq!DrWaEo?*fSMD<K^|KJhK~0X_ at v{A>UXQ*0qB%g3qf2vc<}ja(2mgV6V;
z{IPr;V+Bo#t?SPV$3~wRXiQZ!6O!(2Smh1sa&q`YA3eh)(C+dDLES~C_(&jaTgPzY
zU<a|GqF+DRGqC0nR%Hpnt`#ji9!hP`R!G3?SAos)*(hB02Id^QNu46%h5#e5D(NUU
z75<Od$ORd7zQ-_8H9PjZ`_kT4HhsWK^)*L0bO#Ll7;cpSIaso?0t|L(3`1AHs%4bA
zk>a6gcLWvk>niaHtF at iA4kH6Jl<;89g<ny!$#nT9UU0NA8iq9Mg!M^D_uth}J_DVj
zf<wW<fE__oKWH at mM>yIGa{X~z7}uBxq)mN-D`o)JTZ4l8 at iXAwerO01^5dAj|ACef
zw}jkwxHxh$EQiEL0YJN<p}59)60_L#vnR77r4#vXT2-bkBb{zu4;uBp!FNgfr4zFg
zlOq>dFdQqCR|!l+im3RPk&mRC#VM%0^Z~Bvwh8*L9D!(P^kMy|zp;iTrL?^DVcTWM
z3IvpHKzLOPMOqfW9(VW3Gn+jSqHPI&GYMe89a4KtzYXvdDoDH*xcQHn6;hAf at vwBF
z48r;ssC8nvOCWOb=Rz~`;#<e#@6tm;lA0O1V#TSqp=pmpoJ1*Z=#quApGbc+cJ#l#
z1s6v%f-YOcnzR#^lDJ{AU+{(ZQ;0e_wghRSla8n0+z-y+4Bsq^(&5rhd38z?5jjVC
zx^H($k1x+BFK?c9<;1y}NEL+R0LIR6J*3q&sa at NCJIBn0oPZoL900=9z-3yj-r*mK
zM<*o(-7hRA_D&OglSz$SB#7J|d~6Z`M=eVzSCYg`PHFb6gR3WLs1e96Ke3z49gDoy
z!mDEmrmCl^&s&Gs<}xnTdeLI`CQ!Y!o8)%jW-riOWFRt3`@^6C+EWvk({qEJh_iqB
zg^ijaA?;5+nEbC3za3$`r=8{ym=_-d)rbhXNvUsR_Lt_3fTL!n(YPqd?G5VZQ<RNN
zljY1Nu>j0z>>bvcXRE4l!4mJC-0T)H3;>tjW1BPJ41>VlBU?ov6?Gwr0A|7H7cppT
zAqOTV!~qe*(JXG<BY1;P|15_ at y_Q4F3$F{ESF;u;6+~n(f7hB8(^T%^$%~4`4_a-P
zR#g0D0I%@_fY9>uG+C1#<ggZiPE+JKzea)HxTPxlK|cdt9#$wud0ClQJ61IMvLONe
zoB(|BRnlR)oTjoZ0dTQJvka>{o}14&0Nu9V71VTe2SxN%qpmM|YJuEqTFc+(b{c-`
z!%$t94&5^t??=4fckZPCzyys<;KRa7Mlki?AEAH-vvWaGs9D90Wb#x)dLNhk8&S+C
zCW)bDva+vo+KUu>s(zGZYCk9+n#eMnO3=PNhY=F3nM>^Rtc31Lwtp=j?aKhh_-+ca
zT at A0ug!-?XUvuNR$~uP_mhu}DNCpf6UH(dB9Rczma%f~BPI#}y+rMg#;Z9y+_mdl1
zd6MxBpJYa-heVq<C?%Z<Nlc6L6rS!z1Nqhzc&n`#`0ORT-yekAh7*rz&804JiD&+O
z|B!_YyTBw$z4v{V?M`+IK8i1)ru$2;9xvmwhS~d-aZ`2=vQob=F?#j$h>PVvoHG|m
zpSCtv4p-@$H#rneMP;nMV93s}uE=~l+T?S}V61rYM7!_A+|xU+D;5CiGQW;rgx4F*
z5Y&abkT&(QQ72hG$MN5p<O7!ILeQZAa}(c)TpcEUyn4w)aI=yu<C#}-ZsOzRhFpuC
zu5kB<&i4xK-D?r_HFnAB!qWw=al;Ils31BSjSGc48S*)!3*DnpEfx^E%aev^8KkGG
zzOr~hg(j5D)GH^&SK?GB+GPHTGR`PLup1NMC*%XF%DTxFJ-bfz->U&@=z^p${Y-x8
za>2g4aDV*=*Ifc~V4t^K2tTdW6*Ub)^~SwOJh?+YOm3 at p15+wlZN<>G9*z%*Jz at y;
z__u&IT`ZrH0^2MJdOMdO at N6?Sr~JTCr4R~UL3vN;QL@~g2fDhxvb(vsLIY^DLsigw
z2&M~lvp$L{f979ARl&^bJduCz>)@F-dLBF7nrABC;z?(B)4gzDnlVdg!SJ3{yg`Ub
zx7PhuK<Lk&+*YGuK+D0M at XTiw`dtD58ufNxSXGRB+lDDhF-nEn<(4)m at ***@NW
zVRWNw1)GxBB1S*`D&mH^VWju?!gs19+^l4{me;*P3X`9r;yWhgDORy>pvpV&YQg7x
z9k;`$Y0|nDP?Z`0BqJ6_{EWQVNM&UuU*l)}hblN88=PqD2 at w}VIn?h&&7 at ZIPMg0u
zHk$l(un|-O8=MwiJ)~z$Z~9$l7j6qO<7P=m>CSf3v-7n0e%L0|!H>=7j{qd9TI`KC
zV1%=|T(41v-ko8YOnAr at r%yplh+$|`>B#Wm*}tMHb$lqf&Hk*nv)2>};;u@!)ns|n
z=PC0_l0>Y5MjyWC1k8*)4TADtXNeiEg`Otns8KnS9&l0mDF1vsFA{t(KO`3Urf)BP
za?OJPVkerM{zI-orDsAdiBK%YN`<%+PHY0lgWLK`fbDKtueT0fjnnC>_Ni^)UA?LR
z1NZWd)#NNIhOH~!&l_j<`L_Lvtd_F)nyUx6s at JXUs)QXU6xOz)Y(;%yRsnV%OI|;8
z{MJym+~~UE^2c$fR1JV?q)~b>t?}Fa>v*jYWPG|h9^kH}@^#8sV`2W*###E<upQ)P
zZFgh4e3rTL*f+a(DP*I2zHmxA9-JU{KhXP_*`^y|TEXMcvQz##+OkqhWvRyRGa=82
zjXy%ePS<M&u=Hl79-AEm9ul|R{Mxa==bgX|MX^JF7b3|~aqYW%sqg=A(o&pC(c$5P
zH8YF~)ILlLZ8OKwlOsFFpDK2M{80qJj_sQ1A8BUpW}b%<&4PC5DgE`Y&y3R~hyL5a
zzZvUp0$)yE;+`KmUKUCpz1POxQFT;qy9x*O#G~7O;T)Sa!k$?o+`c5khazg9{x$jH
zPTH_T+OXuh#0&zEH at jXAI-dWAR=;hw_2j`SV*Xz7zhq41hGH-rjkAHmV!kc!6OL1_
z0-C^c$IH!2>}4ai(92!YDVXu-MPhzJe6aN{7C)mQx%P^OwetC8^1CP7QEY3-_JSDm
z&IT`oA^h5I_#UTuqfL0mfim)*5|~XS;0nl6JNlA>6_i3F)s43lIv_z~6+gK6C2<cs
z_&1vxL+IF^@yq?p?khKvo;2;9<_AuLTnP$(6t5mP9*^ttc at a$&ZTf~^g1npUiI4gm
zLK)VAjw^?TdiWeLX{kL2`!2j(<2u|&Ch9nHPYC4sn03%y{rS(nLFBz7H~U2*&Px{x
zH9WvmpfS1`?TX1Ply=WT*=#iMu|E**O~;u2V*u9+OWVHcsCP4vbDKJ^=}2+%sSObT
zYxj4)prEQZeAE3|f34UmiBD~k?`&IZ+bt?;EFJHoWrH7w26D~jWgFtLi3`%5nsDuT
zx_^aff)u!G9+n$x{dq<Aoxb8p(Cokp=oLTu`X042lEO20N;Zkr#1*t0-fB*}+i<!w
zEbF3)w3PpeICwo6O{%Kx6Esq{*uz9SWQ>8&_j43{v>fKd_!)qcW+qqQVEjqd%J^H5
z5_(T*Qyvad8~bh1e6k3p<gZ8Sl-ib at LN$9po=;nq_3zvNY;UT#>PYB$;)f&#Ka^P<
zur1k*sg}yn#C`i}2<MO|Ij0+pwDk-FH6~|^OKbiSokjxcex#Y*pA6#sQXCd3u3&RA
zhJ+1Jfrhw(ARB|*1xp<ZeXL^~?s(D(Uhx!P{_84=1)~;~YDop_%6x1}zmL()ZJDtL
za0PO#qJ8H7JT_E7LJ{uq*9)U7s|D^qdcl%3ttIn%uR(xvVL8{`k~Z3{o{X9w-7f&R
z;1M at YE7E6NrK;i>h|rzgsn#iQ*z(hMU=UwZXdsg^XYedcv*+`9r<r^14kf!<KK`ge
zE^IF)!%B`W^QA$Cym-DCm^Q)yzDmql=ll>hJ2{%?j(&@<&ov}zgXy0BdoLcbKsKsm
z|E%EvH(!A?_uatk3&V|eTi+WY4||2eXVw~z{;Gd8vZ!uqDHo?`VfSC|o^J|G?FxQ{
z>?0xTjIoz5cP#bmZAYA$2ti>ED$@;1H|U0=e6a6tqpP%1rKLJbuLCZ_e28)q%;mo?
zYmcYCPDY^0#K&ydtER?zp(Ya2^x5|}LgE_?(#x>fcK^U-5DQBFE06hr3=AC7Q_c_g
zUXlQZG$s4Mo$z8!Cj3R- at WE8D>^S*e$iTI(C4SCG<C{dA(~1}`EuXWgy}&lOo;(nb
ziHc at Ls}uX}L^^pK=KS|hOC9{=98App>TywIV*?rWAt;OXmqGx*VyhXnuVBX+pW;!!
zFZ=zw-KZi;V)Lt64h!;y{%s=qCKG;|{M7o#>njCgk?7{*g8m($)Nkl9oTIo&#`Pt&
zXx1zY+9EycEB|>(cLgVT<L8p}?CzC%{+X|O5b8wFsk~1p5<U^~hA{HK`tbvPR}mWN
zHuMIu%P^e2w0n6kzYn1{<JhRCVEwo%J)TirH`Qt|0H-QbJ`&GQ^4MDFp%JifY8cbS
zq_e%T at VL2B=Q`6;zX3MrWlrPr#(AaWTNEnpv#NGv0Viog#)#bwbXv`~y~0WOt(gup
zoNxI}@_cwaZhW^5b8kvA at ZxY?BT7-Q`G#nIz5k;DMM%l(b(~#WntC4gmxYq$nHqY%
z;Z@{kT>8T2+vfN7Yt;hdq`qN{5g2H&<mV&s5RC8e=)IFLIy57XC^$DT?k;xvukP1J
zc>)K$!7NiB<Ya1&;<<xk7Re?39UNScE7q~|*8&92fgP77O6#xQ$Okt^3`-t_7b$Ni
z51%qbN5lUOfV!wduX}uwv(adN){|m}3B|d6H>BkA5SIGwJ&Ju%`wqZ&i^+3l?BMuT
zyn<jan~Iir#6kAG4H-C%?|x*b!Ee?nLB$-|O!*xl-D$-180<aHPWxr>Vpk9vfS`;+
zK%<~P+(Vr=xlP3 at zVKI<D%s&N3bDly|0+*fikvQdMW_EM5CI*Q$GiiO(}ZKEfEQD_
z31)6GyG`)N*zm7%n<SL>(f;6c=3S?}9}GZw#iXcran!pvdr5+9VfQO37az8a+7JNs
z3yl?rtd6wGl0&79MAP%6`_~$7%7fWHYjSWe1u4NFWT at n3Z;C;732pLyOSHEbeT3P!
z!|@hEbjzxEU2O|^cZ at d5F)iK8kI9A4MDHkBQFMt4?E1NGtx)6Ez-CxAC$FfY#|Piq
zqZK%Two_fuaVhH63Yv*z26#~36V at q;%meeotV56-LM>P>b>Bwl{ALLb)>jtEnS8pG
zoQ*zuL$G-yXIPko;v7Ic+a`y{HMg;7o=A?1H1y&hR&7E~T-aFpDGn0hPRYedcx|$i
zTnp<>pDXryq#2%hcYa7+a`n9H*%70v<^N)$P`<>d;Yo1nz_z`jc($J}XxSCls+MLh
zr(_SF-F*&)ns^qdpCH*2uX57WV#5y6BHk&-5-SMtmQ6Pfj0?zNi?>^^#&m%q=@Tgd
zXaPTS+7`I;n?2x!1pLee@|1wFVlIbSCyrUKjiY`(NpR;j|4bt^#gmgHGRs^xp3)Mw
zuUHnt*J3wF_?enXVfxGJ{_#OvYF#$-%Ik94PW(rQMqkri%amH^r>3-rmROrc$U}VR
zIcw09Q`!B(zEN(9;B^AR_|aQT&2l#)nlF3ly&^WjN}D#VTGy8|seYm9uJ?O?_g8f6
z#SE~O@%?bsfsN%c)f||MZ8;JxGL>n$ndW+^4CI`$FDk>~Ljn)3YswCtwt>!pgXOWl
z;Ej_^5USjHs|{Pi-+s3q6 at HngWr7+#EC7Hr1El3qKlqy6D0 at Vg14shn)1p1|i?BSF
z7+HDKWyPA?6HuV$FAXo82)XY<+A-3)eH)FCPXw-?NzH4q9Vu+;F&+o2dU#H%Atdqd
ze2(z0rRGhPGM<nxt18)j$_4j?<T)LzQB4}EMCDa~1l?2SHTB9tW|JPVmTFO3vsb)6
zz<m2+)A5X4TsFpCbO*cmb&@@H)jglgX)@mCnS6=717AOO at RfMGZT!;(2eX at g0n(eg
zL1 at EfCz%gS9bjmx2|<QT=67+KoJ~iYH~yV=DL})8`|X+@;H3;WJ;fowIMIM*1!Wjp
z6#!f-!G-<~a24|Ny=4>CmX<}pi0@#btCOu>dxImDhu=d(_%Vw<r6BFVeWpoIJ!WU<
z1skCslWtOGSd<+9jTP#_m=p;TtVW{S0~H<Ct9`$jqE-;HiE3fEn3%VMRhsC8fyQ$g
z%f*vGA5e8XD6hR6G<JfiFxUDXrkkieDe}Xx<y|n>LYvWX#%ZklSz)};JVZQ9w|_vK
z+v7($^VJA2>z2-b%PQaBhtnmzHJnzh at E!{}4MwBpHNA at +QC<NOxfTGN%x^#d-%Gl6
zjwSJ_Rhg!)yS*jesBUXU5p9-C|5_{_O`S`diudtQdM(4!F*l!hj^z-2(F<(^CF{=g
zF8WE>^cI4P3dY6zgcOS%dYM;PpW9ZQJ4I4 at DtPdd++tM|Q=g0>a^1L#Q!y2-oZjMB
z%1RC<&4+hCSn4E?MP$TYG39d8?qef17+xiQ3jTIqFQS_r{-sk&n5~rGo+HtArDbh7
zJ}RNTusb>I75O3W#O1*5c?Ww6oMT=ihZEuKA(p8Nd>b73^WYD6;2uKpSs=id!XSND
z^3~VRlR#d$8b>34z5qdL*WvHeKP65jqMSEzW4`qlMiB!CFEH(w4~Q9XbD5dz`qWPZ
z#R%hIbQ=MApZOo4FC_zO{CYLcJtCjzp|cj_H6xJqaXHSU+Rw4(%TxB6w4eXZ{I}>?
z71;kSWiV!PC#OQUQk4$(eO~J;haR^bT$>ExAlI3|7wxasv3eICc*7X@^f>EjOgRQr
z*-L{<2U`~t)hVOci!U{7mf0^{-yni7CN}Y@!<_r%6}A0y3O45d*i7RjUpXR1emV)Y
zCW}%=W5dJjR;o>&T=+<S|F4Z};%_^N1|Fp~?hUA%`mOIu-y_#u5*-w?5=@>KCqU!m
z)Ggp0fCb-|w?z*XKht8 at mp*=kPd^DUn*65B&xVx#M_K*zm*p2ff=$N66p#tH*nO1<
z_?4mdqsg7kpu{TR2DCcf|0bcT$%v`*TiaVGj~MXnkLrhLCYH<_CBu2ok*wl$YNr0V
z2%p&f|0HYHY=3o)A<uU`wp(e5mDNNq5o!ucN6L|LifiH#kua0yO}~rCWi*<`E1|ZR
z=*Co at BQDeFRB!EJQ1FK%9VI}RT3FX^dqBHFr;B%e2kmZqf0#}{SH91WPnpx9b|YI^
z^)5NN)+X_&TX-wXyniUWHsL at hr5-(c{Pys|DBP-5N(c6ZIlIB9vPT4K6%W*@GqZvl
zjW8(;iiun{ly?xtrQ{Vo?Gy;r>HX-<`5R#sLPvqAprC~`6zL)V>>@i_;K3MPoriy+
z>UE8F#T7|4k&cR0vNV+Ng5;Z4-x+hHSieo>_dXn*3m6KKqYRfYpwB`hSfj-m4>Ekv
zxPL;}q6eaX+yp3|+G?9SIH=6+T1eL=;QOJr;e&*Y8ONsct>5G2pg`%=KoOgfcnD+C
zK<d(~b5!~~ul9;G_Fn|P2tQ<E0M&n*?tcQSiomMUNs|VQt)MBH@)?}k2I(kVr~M2)
zHMc~7!~K{RKO_v~pVE5lld&E{&kH4U^0cQ|ZyYz_nmUaLQv7r(XU*oq_)WLj$xey!
z-=gjm7+75LbP%YG*~V*EXcpp0-^abZUKSo{vatvt7xk#ZkA0`Z3$7OR;Kqw%F at wM=
zBjKRm7jEp{0O6JT`wwZi6_g}CIDqHfIYt2qBHtLBt28o`Yp7$CP1+GBv`R9&qyqt!
zP&Cu>-#@i58I*5vp=%TNM3jNE>-vN=$gutbwyGAf{hN3kK+~O@|Jo5BN=AH-_WdiJ
zyU8<`nc0l<$GAMgo3zbfu0*<5s3|vEtPTYzuV6gq<FTSwUL33W@@U}d+6lslE6R80
zj}tlTGrxFvb9cWO)8`;x#KCp#$oAtu{dCu&ny<E|Q`1Z at g6e0vgdZ1_HS4m*9r!f6
z_FA+p+Z*(dw~dI3zg&}UgJ_Y){N4h6oIy_MB6{TT0z8`^jY}TBt+cU}!?((cwxfDG
zt=>bv%QQeLSL at 9K%~QwzM+SgquuBL8;E3LTbent60l;+L%gQ(BcjLVg)Qe&-b<-jK
zlM6BXF{>{Rru at K8j4>e)bg!Tw^HQC0I=Sd9@)GdNI;!LO$T5%yy94XnC)OyQ!lT%z
zqJl3uz5qh)<_DAG@*grh{U%ncyFH8aSiW)lS8+X!n>k;<VC%@Nn4_aDSJiJj?h`3~
zr|U*xdYj^R{a>glKo5kw8PRd_D at tWlQ6l2|nOsg)%t%vgp+J3qyUj)P78TbseV7<V
z85zs6Uamm0!U+n-0Vt3F3IOKG1_xx;n&w<C(@&$cnGeg$do9QoiVPL6%$(KlW^6$=
zXww24JC=-Jgn-U;_X^fG&bMn=%n4od8^ayOq8eSXC9LBpd+rgGP7JekJ;s`wg%Uk^
zf+#1R!CA2z%&M%Pe3cfZQUt_ at a3F6O@~V4pzwTuMF#n=;`l;M+dT!w^S|(0Vl+PEY
zZD2Rgw&<#O(c at d2!&|hy3+?=^dv~|&-}Uw9!%euIo57M$o>JDkBj+UqAXH(uFL)_J
z(ZI5M(Oh=0q8Z9k=B5(lH3$1w6oy<RpKig@;wem4HCX at iJuT#)g7aHEv;FeY at zl1M
z2jOR=p(>K^f@}Qg3Ia7|MMd}<g1!9Oqv8rD?q%J-N|RqNC>hpu3}u?SB&N+(;I5k}
zOrfPP$;~K8dGBO<7Mfo!+9bx|yVCbx43V$~hq at WFaUjJxgwb)14m<}ct+n~e_)60-
zo$%;b{XHG3C2ZFU>fx|>-u``NsK0Lud`v)IEkTILg5{%7l!f&uoc}d`=GJF8;e2rn
zb&_LivFGxLiZ&8Ul*@upD^L6Y|Go*`_LidX?z76uXMbA`ISKJsLKyjFX<e5$-mA%Q
zxhQ|v!+W!dN3#T&IxLl+%tlfPNpg9^sT34-mg9cq-((9{({57<n-(N>ibG77Vi1|M
z$b~xa`WpL3bUtHXi*FF7mHA{!rc at 8M;JjX|)GAix>73lHk9oAPbW33gbv;M*>(bm8
zx9POTy#%cy4k17V&~fQf1 at -+XSwb^pqtZh>(ye3W6hiJ2lA5mu=o82Z#q{=a=(mL5
zrqDIv|5cUlG}TKZ8ziobp4@@g{QAumVS*nS&-#Ow?&tY9yzL7;=VV at ov_|xLYh1h3
zRFg!Z0F;lniHgu<ZA*>-;^8Y};2v7nMxSQ=QtT(g&+^`{l^2w|hrF+UL}@rE`k!oi
zsf}suD?UZ<qn!cJ at S0B_+LU$&#c{Wbwi5yJDShWz^Ni0C<p<kub|OF%A}}Fp7&Vd;
z at of8}6UVlmb*?#Uvy~kkg at n2ks^VEMg%aa>6f*~h<)f9+Y>w8 at e>H8o<|B5>qzH6X
zLBww5ic%flAD^q=1_l+q<>5yNAF}E6rJz$Mbqs%Gk~UmU!Le at A)Hyg#B4|Ss_kHp;
zp!?kvX-)l;+0Qm58eN4OhcLWG<twncZSW<n_V&o;zwSU0IlPN{1VpLcS%M-%O3&^n
zCc5)ij*IC&yaCp7`Ri|76L%?E6t&OvFB?63w*~k{lToL|%;YGdpR^dfV(Vrg6vX-A
z`vfHjO2#^3>;$7l?G`_-vBYmx!U&mHD<;KeNcJyR)@-^Q=9GJPL6z#A`gc2cg?8E$
zfzLr-Qkj7>`)xw&QzaZ8vG3>kk!8TMT{<=)vpn)oT=`btjmz=fU$*5E_}agER|kXS
zYE^<fJWggRkMuzkd;2v4n`uGY8TZg4NREe{z^Mkio{O?nhSb!Zbrtg8aB6zy<t|0~
zWg79{|3kfr4E*J=+bQU6`0C#1RIMCxSppiHA!Xep$6S`rS at +U3VW6#;y_+w^lmdL9
z=y%9I)yXKN4`1CTeo-u})O`4J-c1IkrTqTv_*D=?v at Csc_?~y at Q-9RP`>J=gepWx8
z0%4 at 1v9wp_qz17Sq2C7kssC<tD6?)ya+!zphmSaJ3Rn47PU_c{#8}$Zx#Y5+T7Xb$
zu`|;(okg~4Z?erv2blNiYR%!m3oHyp_GUm%LYK<<g}a1grXqQEy=o8F2g}CDYM*RW
z^u(_)NW(>W?pW~t#pZnxi}|`p;)rlH>g3<!silsH91cPxh$@sHuQVDNMjtuLL1Y!z
zI>5UXB7QYF!8Fowxv3TWN0!!V1dJjcs~H+TMa*S&ojQ&|x@<X{ugQXw935MdYv_9_
zkdWfPU<@4};ev&eA!O7}f!Bn&+vJVIb~9hI+}+ru+IS-j*pMOm)Nl^Z%($kVew281
z6)|X)VEMNr)NJO}w~quRQ at omxZh3p&VVqkg;|B4nn2t_-&(14Lw2 at Io-)6b#L)#73
zrRQB3G0)_&{Q;PbT!f{(WGeN1EyhW!omD~fQTGN8s at mV}-)w(d=Ak9)emw{r1aHnG
z!3*dm=$d|O5-1<OI%Ua$5%6VI at h>*A&Q9<Gx*#=o`*unF9Rr9?jBzcqXJ(enA`DN0
z$AD#GTdC&q%YF4rbd|=JJ1@(x at BgOC?708w75L<SDSr1VOjq?XY?U+~h<R{$<*uEZ
zFRDh+UG280@~ykwc at 3TH`Dudz7rfG^Kt20-G7U=3n*+ at 9ARygmQ+zeDxVk$<P0W&V
zknkEnoTMW}3%8<IjgwX at 7gCTiNkNL+2XOH%Xn~IyK<o4IH_VI7%BI<DIpF6vViDeL
z8%b*IzDX6A?MsrHO{$#$ab?YDbb;paELe}4N$1HhzT+DKtjYK0#g&cjOEPaKxF1)B
z&3tF-FnHwtAzfX+-i(X+6C(E+ThzGr#BP*Ax_rMYLOSqqgIeWkUi&?P1ij66vrKYe
z!98oYa_Oj2yv8!Zng6KicCh2~Cu|;8aXrsELADAs)DiC>f|L!GdD_<gEXa-930c(+
zV|8c-#y+ibQ31s-+P{99!;3tlsqZEv%k79Ge9Ah at kWVv!)gwgU9T6}z1cG&Cd}07c
z5umWel*ish#GH|^9bTj=vZ6&%m9!q<nI-<ZSX`lCJQZ43oxIgFIgMm6TJ>T6X84gf
zMqBe2$^Y{_>>Xu;d_8DHE{jBWIEOqtZEQ?^c;(>?9#22uuD{l&!B-C6{X5)VR_}gY
zi;>SsAdphlYM*luP2i8XMR8N;p!t^mks#%~2;w$@Cr5(ZLEiYavHv}-XxyC9k5eb6
zTJL at hNa3+QvFE;xPthVHAkZ=i9!x%qoe^A at Ob>lC%iGgAoTardZcn4Hjf|KE<jI5K
zoEHB2L#>LhB^BvZnOG57+kCH*l at CMkR5b?+-XK<esY2z^GZ|@Ptu6DZ_xxEKxDvB9
zI`sEZzs}CO17E?dVlB+0qQ&)Z>Z+dZauyuu5P4<aP{kj^Mj)5wkz@|lixEFx2&Ein
zGk*Z0WX&c%Zd<1TCF}NC+Y4X%Z=}J!^9%J}q}7ycc}r_8I}e&m<;DL4a6pg0o;r#T
z6wdpmQqRd6-Cv%4y#8eHkz;^!8IuFMAID&$0Ar6YV<!81wJ1+^O`18U>hlyG=Q{z7
z27nXrjS4;hZ1{&1x4(;4)hgM{XSl9t9~HV>dDYd1`R`DZOKeEaM`f*ZumzlM#m<h#
z2|N^vse;y7HLu3}W2D94g(t*BTpUli-^Q!T^<8ZuPZBItTX0May3eB8l1E=EH7X`U
zkwQ$t6%Ji;7D&h5U-zKZT37=rj!Tn;c+E9&YjfJcp$Pzr`Q4?9b1v+Aj#Y;q9G@`u
z*99!l-~xpe$ttvoJouyTP=7^oOJ=LY8hXpKpEERABs?1UtxyOxaGeZadAwn@*k+>-
zemU?%>IZN+{Q$D%z*m|)fQ-$oMWkSZ3@$vwqfqGr2o18KI+7dk;)^etP~j{U3Yi2I
zB(I+g)4>0mA^KL&$zx(Rs35D1?!D`^2`L?L%52z10KpzhyKuA&LU2 at B5>hMACafhj
z6}5FgP{2a3eV7WVd671?n5%U!DjjxBfUG&tr4;0SjRP4|h%7-i?kH*kQX0BVK<tPk
zk5cOH9VVlaj7R7XO~CqOV1|iG__^_>n at yj4vP;pL>YQLXOxTRJ+0Jvy%(al?HK at fV
zyi`Q<^@%`FC=p04!QPRh#<m3yg#o*i21>>mRbTT(lpzTXa}$<Ag`}+VXw?WzkT*P5
zcUtpa219do_H1MKXyln7C<apH40YF`g*PpuNiLb9CZ1(#roSjfU=T+vh8b!9h{|j+
zpD4K{8?PA<8KU`TSilCnVRpiMB=*p2 at ***@jk%zmJv)LF)4xYHmt<GbDDM
z?VTeq^6rEBPPHMsRsm4N_UF=FNb0^Dp at Bipmj?Fq)6W<%9wp$Z;%{*ouPQ?~lB<y(
zn~~yZz}ZnnwNK~B5t!vPRi7B=0s#F0NCh?>f!r`4J^;dic2Y*MqmR-|-+c3}=xDsG
z%GY-%j6LKQNSfTJ+-|DTX#ahn+FIibt2(j%alUVX-}C$p&EBKRdG3Of=tCHVbW)N_
z$bnd(1Q(ZpL!rr{@MI_h5oTp$762E*2XIVzY63zQjQr1BKqE4u0plDlX-Wu}F2ql&
zN$6RUrc}Tgfb}F~RR<&a4i{a#$`saItHKiU`<r5v<o;w+?yq^hTH#c*iH8M(lp2p!
zxpT;T++U^u^K=u1Nh%?akMWtzb$HspYv1|D=l#D5vsOJO1AGBZxSYX5PU?Dd%M}`-
zmSDyN2t@(*96VIaJ}z1!M-E#zt<>&2W3{+^ZwHRPlTSN6dhYobjE#D+nkr0_dN#0Y
zc;-0woR<F<q3r35c0?5F(K;p|yO_h|AzvsDIbp5;{lEXW>3l@>BQ*`am)!mzjVNp;
z#oB~bQ(eZzp2hs4KnivC<Wo-*;ZHIQ6$DAG#a<Q06glQrTy(KnCz^L$sJ|D;W*#<r
zZ0`Aa>*U^#XSz at l|0#jV)w2C(%0XGQ9%Z0APVc%@{r8 at dG^aHD615mxpd5=45;`Hq
z>XNSl{|K5ADcJ0K96GL4n`yulP0iT`yz`~^FSwSWp`37NqZ(m-Q_v@*0muY!0l<v{
z%-DCXaS-A8pQO-J|DnUo0>j`_XU;Z6g(^XK>O>{?00>pQ{EaYe*|E7qB_``1P`?V(
zJv~BT;wfSw{{F-hPa5V&B|Spk=8-Cm&6C0*71Vvsy at m`C<JHEV`g at R=pYSV=R>1T`
z+596VwfT*)M-!t<41VYlN1EMVs2N}%z9UqG)um?#L>s?md=AeuKs0c=`Zf}oAXzA8
z{;n+WSJd3d3z?x5UNi}=_qwtMar$9G`e9YeOn~KSDzu6ldR}0fk?>oqexK0!Wei+R
z>IY2JL_0J2D at CKC30?M_eiVSFpqF1K4d4x_S~d^Bng9bu{EJk^ik*0fLU`D}5Hay$
z3N5aa>cC=Q?;oWYHH+Aa>R0vL;6xQnP>o4T3SmOkdioBZ2j1~N{NWGA>34$cadH^|
zmvkf&+Jcp<p`?E&n$sTo^cioELaO^o?Zu3GTLgW)LUO}&kH#6a1{9Ozn>br`^FwkV
zqMol^zaiR3c?+#v(>{BD`6!N6P6v!inlRdgc~3_>G=EnB08A?Ym3)eqUw$QeVB<s4
zF~^^fs_{X|ulb^|hca?Dw<Jy35`S+5fZXU;v(bShE3 at 7ts+m5OY5{0}Mi}rd&k4A%
z)X*_<<Y0dS3^r~_mfPuSY=M^_=0`<qv>`+pN|pT{sy3_?U2s%-cXE7t&q`{(pQ#82
z1oo?6{mP`3o~3qPR(fWbJSF^cNxi$Ir#tr0V$PEtOStsaS6_>cS7(~RBSvM8 at y`kV
ze~_-LffSx9GweD!DBo1s?S1kk9HWxhk>e(q-_7uzq3HiUU<{T3I8=E8agD&e2Dk<Y
z5ZvRe){<*RB)~9I4!d);LouzuiAJmuNKF?r*J*X0Cbze=QCf*%lHqR}s%NSug{wEv
z^y#qt`hgk}&$m)$0yX=4q40F(E;kkUEvF|SQ2+p7-u??@*Ii at OMka%9FnFWM?gDww
zRAC2<mzfy;?+u?h{ol?1bC|R0_aUcEMnWU4bEHw7v=%du-+Q0vup^H)Ov#pAbUZ at R
zA>qp;Xl3RSBMulgBATuCRM$$IBE-5>IqWHuT4t^IiF6)1YD~27kVU4U>W3eGGrH}L
zJEOUhl>8RFZUaETdkqnz9VqROOgjX_9MQ;LTD!72i8Y6K08m3mjyC5Kjd=h4uNo5)
z;A4LCw1(6vEwkuUss4mvDYvE)G6WbQ^UtM|s<hSGaorc0a(zc-Leu^p><LImAU6 at n
zngC0VJ<h22G`B$QKUQiPz5oE>V78VP<5o%PsdS8^3ROYDGQWT&q_C9Es;XJZHPkT7
zB?7_M-+0qVeg;x>oN~&2La)s10Y>9m`zOgO&r1R>Q*)In025+1-gCTS;glc~i9tHA
zkUc#?9{yMg$98)wV<6j@(-BC~k9TD<5|YDj!8KifM*Mf|ob)vS-VgKXNc982k^0rI
zeoe(w*O}}_vu1&F_|9H$@bHn*;W9VTJ_$(=mr!cf=@<^vWu>^EcvF?p>W<5C;#JaI
z8+A|?9G at Enc+1NKq}-R7K1Ct(w9w>Nqi&IbMde#K- at U3NFRrl50|0-a%c2S8QmLk{
zBgL?}7aV-3RMA(X?<p6aa#D8gc~a%eGo=v~U9V29FLBuME;v>1QOYdEEJ!pMte%<j
zz5I5bs1SsK)@!dpq~bebP71b$DtDu*U#09g{6D1D(#Vq{8`_OioK$q4zmB}$I3-LS
zuaF)fMFu6gB1rHmfR1x{mco43%Ov}fOjaTWNc6IEiv)_TaI6WbZ1g9SaFfHtxdl89
zBj#xl^_r{WS8{z!4gBrDi at gWWP^SUN3Ah0#;M-n9kdqaPxl-L*u=OFVA4v at +)Izt}
zR#D5Ju=ILKD8!$vi~}Vv9A?$~KuD|x6j=#q85)PycvZkHlfQ!<X-Q-v(~o8+5bCi4
zziMETFTsoyb4-w_3d`a2!ZUxS{0f5=zN+~iTq%^F_RKuO1WS~gL1{LHF-S#1L+x~g
zk;+Sh7&O0ceB%S-d3Qsdd2P<zbp(va-dn925)<2(W70I@)O-7Bxp at prKFUQT8_DrV
zwrMG2*E!1SncL0hcQaLUX*3{RtqEJ_OR`Ms&}<%9l?k(Eeh=l+9HLEjFlDLweO0FX
z{i+366)Fc_x8aiLWibG~>?!A@!38z$ID5(vx2(*!Jl8p7H`R)G{6!0+YoLpdmsbq|
zaV}-G8w7Glds<eJghC7+<~&I at Inj+OW(mg>sg>Ld&56VrdeCD>A1_ZjS(c%skfPWx
zDZZp1({h|{%Jf*E at Fv^auzF|Ua6CCqDW-ouz`{LFQ_e?O??nH(c|TH`>BLLJ6y|um
zl6o3drx8lz8{8)U2K@>eJ>MQ5qL&);hMU0 at C8~v at A9(_!6_c^*xkbY2AXV^M0C?rK
z*Q0wLel%Ks<uy^im(&a-EeF2*ifE-0dH?_tfEFkQzMC9Tjf`d-PI(WW at hImw@>1!U
z6CQCF-A${UD7&5(*KE<fN{LP+lH8(D+)veTW4Y2xA>MXLQ<`{A5i_A-P(euIN?Bn~
zh%xE1Gfs{${4rby#+s%w<VI=)swR+(P>Ak9ZSPKJ9rpceRJ-8)2%}PENV5*wq%)r;
zNy^rTcu6oJ24&v>%+F^9$|RbF068R>vLV>~e2OyWs!IF2icflKRDCA*I2^cl-5qNH
z0Ki=WfU_>UD(d&*+cf~VL;x^d2`MASPmK0fRo`w>U%UIIs=iE77^?;#SyepLTL86l
zoTLzvAKwOf?5LQul)~vp-Z}Z~u6kRXnrRDg;yiwzQDA<|C-y&}XW#+K^KS-R$m2iZ
z#FGp#)0%s^Hnp6bZpD??c08`Q3nsV(avv-M()F2QA at V>jP}wcoOVDNwm}Qnhc~-Wb
zf9|>Gl}3J?>0yw`mGGQ?wP-=?pMfz^e=ikH(#rc3nID8rtI$hhG&@){&aezTINC-3
zZ|fM?p6kWW>5po_vrqtVX9 at tXMRz>(NObxoS4RC_ at Bm<%oJzZC@^{l at hbLi(zGv`K
z_V4)rtvsN+Xhn-$<aG1xZC^Wpz$qBHT{bO_KBUq}F&56wfBUz8Gh1oXNP?RCGBvX(
zMC97G2dGv8_4O0w670{G>9j*@uqcGBt*%g4C8R#R0TxlSPpy5jpPs9l2W at mG)SCKL
zJm$5`iNg&a5R!kzDuJWPNURTm=1ER+1=#fChbou8TdBJH>-`CN=B;TFv#yY4Myc{z
z6)g?ab$xo<1;%P{?5yMa%Bb{i1z_d!qYD5pOYq&k at sa414FZ7Y9RS!Mw4JIH;LMG=
zft}<gkg+Nn=MhLIamIMqYf?TXT8KF*1j(rUo|J>xDI9_MaY{|rUWQ~cqNWmypCYXX
z$4(WyzsMhg`iX;amTJ>)P^v7Uv-#>|GZ3Fbj`ung&mJcA_prl{Fr~26+2cIKp+*K>
z-e#IsbE!{ws?`*vlGvF`q%Mh0XDG+xpX5|re&Gsv?g at VuOI_BNwIh;pw8F(C^#C4}
zgHO at 3?j`LZL<2<<mg6VSm=(P%AJmnqGnh1Oh7m574*LoN_vCYyfyDui1^@uuw(;R;
z>G~@w0Dz0I711WEQq@$HAd@?B@>rFxC61u-xyd1Mf={5NGAHcfN;{-7)o|pGL!4y#
z(dQlq7dGZ})wJX2teSscW;-raoA3u at L*q|5PU*db8#$-m-x0rW#@n03_E#ubhLl_C
z1Bg^iQp94Aq`q6MWWrTmsc0bx1QMf|;}Oy*XxIw#uT|60iSpF%sl*+l4Kf10AQ*Lb
zJv#|V_df8T!i3*2E#r<;V$W!4QhTU=#McT7RqKS-cGrEMRv7v|0pI at kq4fWrWTwsW
zUI!dnGXVgATOWKlI&qx<AY=kmk=iL?Bm@#-hzv7(M4ncbInKSB6hsPZh`8OXE&~98
z#G$?Py%`B$SO*XQvWJRqhDwrRGvn=FE}M3?V*8iKi;g{guZV1likr;yH|X%p(^{y&
zyXU_9O+<kLoWaV{bB`^`_~V%=j=5WT0v~+vp;4pvV*^fUF9w|SK7PiWoB3$Xk8mG_
zEO^HA+a)t-T(nf(bw5yi{?^-Wk9dA!_nG<3)HB4Og*mfo&013?jlTfxVITQB2Fr(F
z?DYU}l+jk#*zpm)DKR0Al^<cCQlo>Q(V*&&gxnk%yXreF5CGhf_y7QaTLb_nth+qw
z_p0d%9Jd9xO+l-~9?L?4K9Txqx3z3BCq{3GJ0|cN6KADn2xwd>6%$y^A2D1G&9mg#
zqn*^{YE^c$y2g-D@{)>Au2DJU^m+56T}2#rl&MmMzw5qp7AzE~JP<vhJc^S~UuNuI
z_Z;_L>EFro!c at mA<=WO;Y!FCMCCEG1fsK{Setkhe%ZTT+9ynOT;bMM5o)ir|@Zd%h
z8in~&FwP{R!~jAT9@(K}Nm3DtgOhGN0Es=XO7fO3AchDi4_BrjA?TITe#T6kT+=|D
z_hl~1fFx{oxIQb_msR4VD*>CTOxVnEU(~(ZF+u=vtOWqKEAR~2t!~<ABUx}Ra~7$N
zE-{B4hcyN^=-=c5bjiEFRPpOC%aL at 6_Jvy_BHgHxTf%6|<*1q<+p?KO37xa6n0JzV
z2#-qY6Fxg$>NMa}<@&tiFg@!PS6^d#DZ+>+>AA;B<#%o0vUw<)%iVMjA4FJNIyZB_
zjSoE>?K^)#YNDhx;Fw|LMbPFAlZn!3-jl{6G?AfuamF<9>p}v_UcNJQzVa}hf8j+_
z&%oY({O$`5qt!WPA|{A06nyQp83$zLs6YX2R$2Qh$8-k(+$;^?7yy7U;9E&saKeC7
z6$Nk!sf_5Vyg<=0?RdG+H3msaVT(SeesUWhek3|dsi%aKUQoZnGtNCf8X at Uo&KnSq
zofu7`?e4O5_m&xPzZe3C;xSTPQTwaB+g{3XpDV(@RYXs>+uPK7eScNC4IDW};4vh<
zMwNN4bKchZY_k3sQ-&<3=smLA50aC}XC at 2&I4}2+W^mRy=b9)4dHmPkc#~}ZL)17%
zTcF8z;-;PANVR^5S_o1tx;>|Cn%JfDr^|Gp-8bpR)3u|}ATlI#3c36`4_}k8&z<L|
zDT*>RqFH345}rm;!9=ODrtLZ=qyZcU06hEFJ1GDV1(>2JK#*_~MzIWIkAZ2 at VHqj+
zbC4LVk&!TF>2<Tm4N^0V<0OG${D+nDh$@b{N)gJ*r=JlGpD;OQ_%@6^)Er}`s`}V7
z;T4*rsFTl7mETrj{xMUgMkncc?iK^$j9h=|Wzj at wCA&%Tx#w3Uf-(Sbi5t)Q4Pt&A
zl}nWJ?3M~!XDp01R*`^XRZ at J5G6M1N(@X9wmGP3>Kfn})1?tcnC}IID*outgEBXqO
zd1|j|eH7NmQJC;!%|_RWoc>+QEyy(?OZ-2L07JR?(Vo13;#`HSxl<nncqEPjY;FJm
zDlbvd34}_6iIc?qx2a|Hi;~QA$Qht=)OIjF*Vtu{cIuVJME(7jR8+O(gp<tm%b0&x
zIXGwUe?WAZd=f7xEf{bjgof6@^ZVzw8vyo{#9gP at I-9nfr*Pj;0VYz>G6w)a*B>+l
z5^<>6r*LW2x^>1UF(7de#;M<~!?wQhrLP(ICE?Tr&<czcX+XwocIriXtYfos7GPav
zVTDXUuk^ZAErIj*)Ewf(q%w1nOs#!YZ5k)nc_wad4ozNeP4V}>xyQPa3FsyQ-6i38
z_T^Ux0ARK>07u%li&<jH?@C?&|Nd`9zvoMDRB;l0C^|VsVZQTa>woyoZyB4sKg^HD
zk|+6#e)G;j^3T|B|7e{u3h^nNdG2`;ra&3<50$OINRa^+1Bqwq_76DF_zH^7Z662>
zj*if_U$3YE38l|y9Dt6MS`hBuiou_F%4udZ$=6?hL)*d0UKFU-Y-{Z9 at TgbEoiL{t
z)+IDLPwB$=5+0X!R+s8alp>7=*{DzqGFCfq!NTv-R2eYb=uuKaUD@{)=-B|%)9V5M
z(`t1qW*-U4n6FXqhq3B6Q6-zv9+Mj}stcdjoaM3qCL2Qci-8`X7>JHQl{J9GUTz;C
zIE<KMMwBsA==W9Y)~lJv-O*|4S;xTJzy8w8BcyIK*9)BkGtN8kV72kO)p+brR;MHw
zsOb8;XhBAx>Z+0EOH!qume>7UN#6-mr?>oERl$LHI;q~|CfuxW-z+)(c9!(ve9VUd
z@<$x3#G{*4V}QDk!}JUR+r;TJb=;852;09QFMIr5NG)c!C~`9%m9}<*A`w-R!D_h_
z;rt2fA1Lk>Py-N?m{ri?tt{H*hn`2u at w?>s6OH+azXbmp5uvYY2dPK3LGFR7%8SF(
z)kd(zT%az-fSpr?SSxpq0kdvvFwOZ|%7LHvd;t5%2T+xu>~XC!mX&^u-q$~VhzRN_
zG1dkZubhzh09XhRx!G&`?*@?UtqixDq^`0n at ELN96-j;=Y)^#(_fc%0`U47Mo_gk4
zqY|PbwmNrJ&j)};$+J#V56VIJSE7<hun}|Oh at 7a{|4GUPAR<JS;d*Vu#WU|Vq+F}1
z@(lj`lkBrp{*vcZ<g-$_1SAbrS|b3<j2MvefT$?7-1<A*8WLA?NyFfdW)K2`TBuZ^
zQPJMM>YG3YCFass6eT%D^GO5UQ3C#})cgd&v_OtiG#`J|{2f_viUBGfp<{B}nrnUs
zFcNd>5NC5xQx5#dW6?^=f!$&toPg8<q?0EvbTDr1#LfA=EK*SRyS+yFy?7pP80jMP
z6O-ZWBl+f1#m{fP^)_SU&R6H1?E3_+;a at W^FF=GhZO**tR_#_pbm2 at ***@3*T|
zF~WO`k3L#^=G|+y+`dWAHCY~YL%2C}SBVh<i7k1I2&0doYY=I^YIt&#{0#$1PSW?I
z<m5ZznBxR!x0{3>GVrXgBoifZ%%e1F;+jPz=94ii6ElbRn<Leq1}4|b5sBGW1w_h@
zX=L8A4$~}<gtV2sELJ4>c-i;}984v`qqj<fBGZ&iN at FVNn5)%(i^i{0wDuwCpC{=}
z2j^ynb$}-49^~``pc?RQRRf-Vg?s at 1z5p|%B34NR>NUsc1qX`x7i;4Sy2WgiJ;_#5
z?5abD*`jt+dGC<ddTXSRoFpIA<1^IEgY3LKTX8Qr+DNCpV8u$aStePCN2)4r2w8G&
z@=m~pY{W(^%c+3)CaIWc_1bl2Bhz!Vb=OdZNFmI9l>SWe7iG#w{xj5?Y@`~E;HWAC
z?Ph<6xyTfxycd<26xC3cUe)V2!t_;-O><95Qs2?wrb<h?Ni`a1O;5^?ainTX1}Q at _
zqk(9>@00+zSz06Q+KZC9>T(#|1gJ*-wo#4boNP7V>(QM8fHNoue$#6TI$IrJOn4{I
z<TKdRa}ytj7kR2$UjJCxV=x)5v1nvMZ+ZWDbJZo(Brl}p9y>_POfwHUA(K9AdL^nL
z$6nvgm%RolvNJ^(cPe3qrlM2>QkGkI|2ofi_;|M#qDXDzH~RKb at Pz5{gO5KparS{!
zI?9VbRY^<i`+!M8&iyn=rXnd6YM`3u at GEiz(!7+;LTs^ii2MzvX=xytr>xeZFe9`P
zMyYtL8zBMQM at X|fQ2jAU+ at g6bTa%4e<z(o&XsAk$&Fhpqk$vBqBel`FtWSo at cg&h7
zfY%Vj^aHqD0PvR663lc3769}lqlbXTWvDtPPQb~YH$gS=SE+U##;2_pDb3hkRLnK<
z9;VB2U{HLsx0vX9RrOKjcAT^dstWU-Yp6C8p|?NILAofje?84Hvfk>jJy*uijr>k>
z4&}!Wits*Ejz1cJ>E)+)T&P4NywWrzJy~ED?{!fBOzi+H_ZoopZ1wh|C!pETgHBTx
zeC at hc1j5j>H8MZV9Lt;zmG;68PPZ$x{HehGF`1l)in$O7dDmQoV^!)uS(DA&*E%ZG
znwO;Rr7qpttA%kv`(V!m004{$;PwQ({E91607#k8TadCBs5v*10v%hZlk?DZ&K39g
z9LI<I3^U}j`0`iYkN)#N|I<h_wlf<dCTvxUvFA at yh8ktKfBy5Iqa$U at 4`YACg6FzS
zeiRyiu%XC2l>kHZnMN1|i<B*5YR>kv*Pw?0iBA;i&_~afBD2rlw<LW at JfcG{-xqD-
zk*<%kE at d>}{_Zj=Tb-RHKLjSxK5{x*=5GY3%Z|-xV+C4QBkvG9;D#D)YK5XW-;p5r
z{qKJtouMex*hy+oO0yHEAkC*~_B`02R(tc+491TdRMoob`~XgpQx$E=?FjU;d;quG
zh9Is9V73Mmy2VUfUtL${kf_Va_SKN0jVKz3BPWiG&}2=Qs{JK(p24{VLF0|h#E2`H
zD8Bk{&z~sg&KmU%K=RY!hAzDP=068a1W=&neM{-Q8<f$<1|9SSXjE0JvY2@>c>6t`
zXFR>^`h1$&g%47DvmwfXKn?t^b~qxoPwKB_{<=af8)j+{jEgh|QhN{9{b7FgJsc6x
zqH?vpibBZJY!Q=X7^#GQ at exgxpM)Ku*bo*vKzpI1Gf7f|%qA}7U9%p4@~LR8qADYm
zeqNY9?E4%NCvjEZMbUBLYCvTI`cA;<DhA3F^>`_gc`1>Nw@|7N;rQ1!&XP>IaSR$M
zQ&G((Ta4WM0~OYyDFtX;1OTptaHT-1xg^9-Ni3!XefG~)De+(xyX+}KwD-2m)+NB9
z$cR1zIMPV|7%PuE*>-+GRIBNvW#{uuqx3v%1j_C?L?4D~lh=WI_C-e?Y3$Xf<&QXk
z9h?OS_8r{$v^^MdLBY&VV__`jnc^PQejJgbwB0$TmCNuU$?Z$&Ji+8Mbrv9NG*nbY
z=rU%10s4XJaX_*b at q2nCVA7qZbmap?XTvARQL1;U5(XcybZ?x-XJ4>F=L{=OL~BE8
zdS0FmVc$FClfp!PNh#|$sTgR<TGax)^iFMWK+_Q at 2?M%Scp+pd3&~XZJ&0Idt1;i3
z3RBepO2mj=#%7&bv`}od&c>wUkEg=B%n#uMBI}hZiw(bAUi{%~t(D1qQ`QyXA1&@m
zwaxmrRO)Ayf3UB1ydj;J7`J`yTKlwG{&yV5PDY#R)CuX0+h>~TAwX#_2|fLX%Pt)@
z(iBC({M0JMU3x}DR4-PEl~>>QAZconW8y4Q8a5$XTFu8G9XEIJM`*n)IMe~QcP|$R
zYU@=D0G9DhE`;_}JXP7FuSr89Wc&Red at S4jR+BkNGSpy!>FznX8+nYkT8U|70?u1_
zunBcGRtwWe-Hd;1HsduH0Q@`vHxa0aiQAD8=oc2babg!7+?Hh7l2>0th#Aw4G%L)r
zUyBke_-)DY#~TkmO+#plMLd_`UKg8+0w5ZT(p`9#oTq3AWl}#E5E_W<`|H9rVeBWg
zkqNf_!AZ>n2~a05JJaMWPzgC-o1buO2zcwlZUqe}b2IjwdV&}@VvUXPDch2hemp at X
z&aQS5+s at fUmpl-#0KoBk>b#K8#NN{lr}>(by9Q`$)NouY4?TN9AR!-Bn(U=lUKK5t
zNlB(AiCq4iS1EuaXN9(A%g#A38ZvrZ+iFnic&|bg>jJMO*ez-ab|S?<Zbu+A01E(_
zYQG%SWJi6!qjLP)G4heIR<i3RlZ3#cW`;QFr(T$cxVRm at W5p5_RdUo5(9qImV%blK
z6K^hRok;_hJv&(~zhVB2k0dcwY6MA#oVZI42}173%VzV_Zz&J1V_q at cTzUJSe)c)z
zf56V~Z at TCViOyMmVf4D{4M<R-5M_5|^~Kj92`N8|&OT3uahzw)#;W7 at N+oVGzwX?U
zSj1k7ln}?v>zWXrvp6xq41+sN?#?au$}qTnHYYRC)w1dVQ=lYsaf5n9P>l8M?|fH4
z{<_JDSfU6HH69}r_C-sIYe(uOaT(2{DV!wQU at y%B4?ogmEtZ|r$nW*FHMOeTP$g+y
zHK3e;r_dGn`L}BQ08BY>QVe8KrV%FJK at -)=Xk-HHv9-lXfWkq;d at Ul-r_i+98ftda
zWy8wL6*I at DP}3rm0<75iTE%-|e#&UsCVRM|0;s6{li`~ob--W&C}Ely6lw&W0z)8w
z-UkZKqv+(un{P2bh-2lfqDX15Od{$G=uJS&Gm>pga*uz_I;QrR+4HxA{R6RfWEtDM
zufyOp8eO9vgJ>Xg^sE_1W-c6)&N6k at e5wb%jBqk_Bw|oTfiT)bQheM#)1$+d92;Gs
zMx*#bm@{fJF1zZQXtA;(N2yR}m%&|P)WOjX{YA?yjDeE)B&J=gH0KeMr?hmf&~xml
zXEP)4&OTrvI2SlR0MirDY5>o?S?dR|UMlb2v**+<+Ta9iujBpE$|Ra|6HqAwhm2a3
z6c^PYVUB;n_!UIN=V(tvn43O)2Pt>jGB2&JiJjBu?^&hF(l-0RLl2GU+M6<eV$Y_G
z;Mk{O+ccJ%q0Fx`XCJ?#hR>7ar;!L!Y^l<qW2fm*v$+eNe#&dvgtX?6^dc`g+K at 4M
z>LhhyuU7y&S2f4s$c{eODv!eU39K=AwohNWUY^9wtbIcGd35E|A2kMez%O36K at D3T
zGMi!mMz<(0pF*eo<m?+fc7kF0?R0H3_F at cddhD$EqtNOXzxYKo_n<?fFKSH+uV?S;
ze1>?b?7O@<0Vw9PbF|*sI00pf-T1&m(UEH|i~2qF#@lH_ko8iDCe4~t$HZkfZpZJ1
zK;dW>ML>{(KrR5(=X}HXq`zK7b4!J&P*q8rgy~`C(faKKZADGd3Ms~Cs~H9{?7<4H
zS*dT$11tUW>{A#ZH9;J;x$*SRp%EcUm<kDYx;h3U^}D38oO;HY#^FaT#9ZRea=7K1
zJXXy%pIOg-$Wa=9S5w)uy&DtXi<8y2m$VUR>aKh4jSd!|+WH5#^x3tgL)vCWqx1w)
zp1|2j=FLE*+#Y`H at usc#i>e5HSN$3&IbNf1+(A;wN6TTltH6P4w8HG6b4Tty)tHcE
zSPq{wrR~>G at 7Z4<Wd^`yKNAp3z{JiGKxYBqMFGHd_iv02y=X(!@5#*=0Q?qTzD<p^
z9It%+ixum~erE5qY04|u!`Sm(rVZ8w>QDodJtN7Fa}cv2qvlH@)~o$B2UW1AombqE
z0R^KL7mt19 at S{-&i9Up;NPL>6cs1`qG=gFjA`&JKAt#5z#L5!@a2;`>N;Ox#&uBBw
zv(`)*MHdp&g3{yr)Nhc+CzKj9|E^Z%cav%r0Ctx8K1%BL5h}-BrxI{{G;gcv?PH3=
zqXEp3#>72amGDJ?v4a?KU-ftRiME)Vt8UJi6zv9>b^yS&0)RtS3ILvXy`}-I>#Z7q
zMgD+~p|WY<^c;W)A;zhy?4wGH*z}bu*Tf at iw?mt+dVidO)b8UU#)(GpN5<g=qo&ME
zlpqEUt3LamWz3bHYp>&d8jVCA_3LiDQOz at 7FgxZ>nK2`pCrM9UKUsfk)U^jsdz_tC
z4^E-)+~?dwpkSHYb(q?}U7v+v^u(`F at 5mf%0Er%lhpPxG>{KpxAlLbm0wyUE4jLFa
zd7tQ*rKhOlbG&BvNb9&np8Vs~*ktmoeHFeN(UfKzOIFVuNF{ImZ^M)$aK8L6R0Zy(
zzK&?NZ3h7VnF1z6YR)8P`8;U=w<jh58o;&pZHx|H;Q>H*m;f#N0Q^NSa5R>If&HC?
zjA?WCi>^|K7V_k2j)B(}P at tvPfl^ngn<okA5~WAmR$Y1C at mPg-9B8?=b*ySv1qPQ{
zk>+gPagIz7h>MieS<0(ltOOr638n4%#j^czx^ZkN*f<%Del)}|yQhWZh1G)Fb;;K<
zTN(&$*;cGtqedu`vK^1yMyw6>h|D_rP~k^P;vaC>;Snv=X;J>3=7xqQqtuv#HN_mL
zN*AHy8g*(Pa?}#DjX9;)JF85+o%G*|sqLBo_yAH9z|{cC0HC3l$zjy8#b`KD!g_$+
zu0nyotpuWZ$9{5*;XETTW`(3E&NG-FX?C=t0Q3=H&`*%8uv*9t^)~U^i%Hl&kx>*{
z%&q-S)Njm<(1;z7*26w58l at cm)0KNpauWUg*zWmEg(Imn#M at 8GZ*fg|tf6E^=H8P0
zj`R<LLLD$TNj5fPQ}>`gp3oziXZtJnz|P+;I>rTzx-e(54rSkSJ^C0dQl=vSP39xc
zTQs9X6msPEvTHQ*`xh}?a)+W%0z3x7<7~1W1;zvQcTt<SjQNw&YZA>!A{ss~l<`g)
z83;H^_j5A=1pwE}1UPI}1q~pV=^IeTLrFt<Nk&Ea%#CzGH6gD|m`i;Fv?%lCm3{cp
zM@@YEybCTgwc9W-4lCMR8$!DN`e?SgyYyG}T$T~))%+j>JB$`mqg at H>+Rj-!x&}5h
z6`|n-x#;wjo40VG=|#wXhIgncjd}=Ux&(3zeDE?EfZoV^2KW0qzk~;T))X2hE#)dX
z-rkYzy+mPBJHNT}5V%h0Smt?vz<7jqZk{W1>~d|EN|@~{a(H6K5$zbNH0W0EQ)O+k
z^JPJBsA>0gyPCz^q{=@d8~{ZddUbLY+$c|-2IbWQ<ncq0f4t7!F5k`f0DvgK5kvtp
zPC%(qlNAOGsXg`R<2BdJ$wrD_poYl4t(cc=0^z!<wVCuBqN~~AUIiTzEg_uos^mIO
zadIRkrLd=+A&HqtK!|jniaSXEq>VU#6CH?0O~PA=A1`h^YRn|*hJ^E^oPFP{#K{SN
zd2@)ApphwB$(sT!oRPF3r)(QD;L2;RlM{1#tu1?r78I5`PFwdt^u#ALe?8szVh7*F
zYIyo1)yJQ8{&JHupPEgD;8dR+Wr2$jCee+_ioDR(hV9BxvH$7&KZqVtYViW?9k?fZ
z5C(v)>^n<SnRRtEyO4%gqX$bL at h2UrE|brJA}mVLcNcA$VSPk~7V9fK^8hP-rZi8a
z0N?{TBk)zqYvMmL0sXDPj$N-rpr<l<06F^tczxLN`mu#1PzEh?7&w)(3B!h^YS=mD
zFP^*TEDYf>+JfCDo1PtZk(hI2pW4J2+t>dCwZp<|JVVux^v|nT5zDt|DoPKHJ={g3
z-XXTDGWSSaA<GZVWU;!<JRy%Zn`c}o(}l#9QnfHm6sf;=UOIO(+8M<$^A0 at FG)%cg
zK9y0E_HIxOuYsa*(rVDQY?c6Tg?t;BWLz6x$JN(f8<E*Y#-quv4-IFtm%4SS2$V&s
z at Tp`@cmuNs2jnB_L`C07mwr;gU<E`9hK>LU0FO)CK2TI?6Xu?Sc0!bkJOFYbOh=$A
zuZj9Sr(z(xGmtF?;(=ocT$6M at qXi$xvuE?X;a2h*M)yF$m9DN at n`b+I(b+x6C4`;z
z>}=3M$6mVf{QB3wHXC(PAY++^1)i?7Pc(u*{pnB9M3vEUjYb_m?Ks|NWS(Qbq}yX^
zn?=Uj;>C-NhC=rl%ovEwecuqVW{Qpy`#Ph6B?RdMcb-X*C#_h=8FEOHctl|o-E#P@
z5p_J)?&R~3DTd#L{Q+pA!9IcXdLUAR4`hHU8v*%{eeDB5J>b?rws6ft32+6 at XYRXP
zwGMYG;&I5~hu6_hc5MSdT;Q`xQ{FxQh`WyUf;Y>ztV0F>q@~;?P511pXbSr7dn#j%
zHwUFp{4~XG>zLhP>=09DBzB_mq+z3sx?EHBeAPHFK3rSGc=7y&3wcI42UVFJcYgNC
zC(%aj5inX3X(xGQZPEk?Jw>+jwc6B!ooETK?MRHcB&3q}dm|p&j9;ZL$tflf8fCI)
zAJYC|wdW>J;iXqzH6gxTHK!Q~lc;-^5K;#AoRmfd4MZV|06DXcIcrHF(zUX~zxuVW
zn>-56u|lK at amGHFxQ8NLmLHXm<_~}PgJ~N^D)SL4%Apev=71|OES=VwVIH%@LZX&~
zV1Xj6k(H#g2f$&R%rMN6o3+P-5g=7FXgzuknc4OkeQ?WUxjJ2vGo6whfL|!5 at tv*)
z at W`XlnP>nnDMKm`03b9o$RjtSX6Nqg*t;$<h8Q_J(H<iQ(uXZGr5R2IX_?#VH+OK(
zv2vIZCnrUge)EIIj5jf0jw2>JT_Hdi9|FUcrZ=7a-M?NV|1XaBhBLH6z%fE#^?<zS
zbU1?XasJ(`u0*u;W*zbpoD8VC+M5pmfO7)o8K!ptzRu^7u|czTDEGoPr`hFuYRYn~
z%8n^ZHWi1i4eI~x&=FD}>4a&9_VBO&`md(Ka+#X0(wt_5`s|?*7?rn at Ac{@JI^asc
zD-)4${57GdfD0OV)qrSOw~Mg==|yTxTh-4JIxc8(l$qZd-%5Ry%FctY0o*MO;2bsv
zdCu7!bbYcnAP<K$+(F?8GlW#zCu2K(rb7t{+a?1-2Knj<I*>@=F>N7}?Kv>orsCLD
zweRPue*ayyo4!}lbB6M<cNscdj6W#aM)w?TQZ(<5K9Vosd+H#B%1TP at 7nQA5^&aLp
zT`M%22a6gw>@i|=bho75_toPNvjq at XLk+!(OU#-$^$~uZgulUQ&4XNX2&GQf5aHy6
zHuF?@oO2{ey)LI58Hs}=rCr9$H5nwyNxCA3ft`k7e9RmA81UUVX*olb$_wM?0aao6
z)YEc8$EHp?>#TD=@n at JJa4K^U&YC~pM3m_GgA+8>O04i~^0Vx|?(^r(h5J3VEv^sX
z4*39<p#eOuRNyz0-GSFC6L5mErnV7NTLRx&#BPQNf9pL5WX2cte>3(-KF#kQ!&+u3
zVB+}N&5v!w;A~)ViBeAAc=N63YK6+C?YBVSHPl>pyZ(bs?)QU2>6aBVzwV}6qQ%FZ
z5OryjP|`xn?%fbL*!OG at B+wqvl&+R$^2yJC9{ur;e~exeV^Pmfu}ZymVT)F>pj#BS
z&8V1Z{sgh-#E~Xxvr`h&wy|ydS at S0(ITHeqb!vU~ylN!aGjN3R6f)I at p4T6<1i&Cl
zK-i9VqkHp1S`#WPkJbjId#k(iK&3VN1YK%&CYpgCwFzngju{j7b>v4Rd~>G1(wk`t
zO8to0f1*;Pqdp94a!X2_fVscBe!9%x+4peUg4=4q6E-Lc at W^X#MQ^_Sj`0DkRsQri
z*`6t5i=np?bLWlE>o<S+$GRX<&uCdd at d2jF|F_XI?$$NZsLbDzw7lTrRnh1v)1n<^
z at 7weD8aXz4QeNa|o_jtz@`R<)aHWmzEX{y(tK6ghm}0PM1~7J2sw!d1e^Czk-~RSD
zd6S=r7A`)*q?5w at W!gn8KRjz{_$i^ThF0v0z*MU_tgLon!Gc=%FR7(GJKl^orb(PE
zQ at 4c}Njn0EWpd!b^t31cXG!}j6vsbGwG}gzZ!ua)Jp&1yrK)=pLQAA_4G?Ofv|xBP
z4b3{fCdb^cCTwvMP%W{?2SNA$m|`@2rGV_zGtZ9pA|g==p0yo~>Yjn*rDTMn2D#q_
zOs(3rYmpT<3`k3`o7EERXtoD`M702^24DbSUje{CZwLecgB(Bz0YMdTr~yKAjJT6j
z_sMcPQQ!S#rR`q0TD8{-jlnD_^GkJJcHa5X_tn?!2uc0j6$NOH>6?4T+P$)%;ey1T
zBgSa+&67=IQ%XqhR37`>0}qLImR6G<muM8#fS?`(GK^p6OpQ%Gcf^ctooDeUgoTtn
zR6Y~353d&U6E;OU#nR95KI`w9^X41vfDj&$3^FgTR(q^t)pUa*EF>suw(G>R*NJ^j
z{&0Ly4%pOZ>D8FH)Fuyv3&V5aG~Cd=2ag>e-LFkz*c4={d`cPnJq3bV24SVl!>Rz_
zF at 4ds?cDePKu^G<*Qq1WlTIE0#Xu8O4!o^#m|-_dJvJjY1HQnh1BZbE28II?0iY-Y
zg!sCSNg?f`NMnFFsfT|+DkRMvj#tsgVC8?K?pvnYMIohwm7D#pB-KjA&5@=?>T_*(
zB$_~K&S26M4f~vVpN>i7YEvQL88~J_v{Xq+?|=1c(a(PNv*=>Ake(<r48KIkGzn at K
zCEyTi2QerZAn<!ExP?+l$}4&7FrZ~ln0%mYe3EfsX6h%XINU?_ymb`AyjD`N<1wkg
z?3_$N(D^GbR%e_eOtoHI6&MfJu{LT<=4u~1(4Zq7tu>u#BxD<#O!dG>{sDag$w at d=
z^c740VrI{m>h(b9=CWi#&`CD)G#jHm1T?Tx0C?8P1HcJ5S(}6IU}E8eMJNi3C5;jc
zC}?cs3>O>>Km@?SGIkL_01hED!(~F38Bp&JJ?a=!-~ECl(W0Y|G0r~x7M96))*1UB
z5Z$E~&Pbpk$_ao0T*fbC at -h%;!|$m5#|pSeXT>Rbx<X)s$4=Bd5BB^jW!guqU1Y$)
z at j+ywB!Gc at Jl1Jzor(}UYQB+V){CD=bqErN++1ZyvZXoMl=Ic-V*p!VB_IKT8_&P~
z&nB(+KJcK~A$OUYZV+xAIBKkEjFB>6uG2UMsakW6<{NX=`AstQ^9~^9M50m?$<dgY
z8>$P*9l2aSr{NR#HkwnOrjcp}Ip#sgY|2E{GBpVK<_W%=&@)(V#!m&lL8-utNd<mJ
zIRG{h$OVAZ>z^z}9RMT*<~j-U0iZbz!POdEfS7a8qUaXoT$6Qm<cUi&D!&DQQF8jN
z)@BTB4}PF*X#);zVA^(p2HME+r=D)I{OI3*rs@)Qlr(JS8B<WJ^JxTtK|o;v!DSF@
zBEX<XJrin7;>)P%*y>1hN{%T+!sB1_luL~_v43?`mNdLrYCoNImnsQsh*ae??w$x1
z3j&759OkRbv5?kMX7Y5`?|C6zLdvI}rA=04Qch-5(<HZ~Y92 at kRH~LeSG`AQPDACu
z2bq2V857`&)C4e*fFv4_GP#WiIG at HWNTh#k3gnH(O at xryz=U5a<lU%5hB>O)-+sW5
zjP`)ajW%$)cJ76_&RcPjh%7M+dI<n*t7k;*$BBjm_HgYhfK#$raA_0(0K-uJgf$Ve
zATUJX)cvK#-(_|WKKz(tl!7bU-3y;#A`Fq2pQ0sp&bd&|Sn?L!J^)4<8CBj1EpK7~
z$P4L)zQ>H3E1IJwW3 at oe_-***@wzmCN-vYcJA$W-3xX;09>tp01GZ$AN70qRX+-_
zZ`h{yZTx`EU)34d>~Xsc8zllf)?|lWux6bYe_-^v-3KJ2zdrjLpT&Yjhnr3`cS!y3
zFV&O#x&8&KO*G4Jt(>=;-r)%CFZjk=Z%1EMmfy1TFEFZmE7#;)0|Gf3K%IGz<T8|j
z0Frx*@+2-*gH-I at wF>)Ln-qy}L7+>izjIXwaQ at 1RqGx1o5pEqPC!aM7jLom%Y6310
zq<JQO7G?zvppXG8<d2kvfZg8*kDF*xe&5q>%6q9&G&VUK8_h(B8a^igN^@0~?KT9t
z>fQ&V{V!Y>_1pN$n`szujiLZ!XUwh(?KR7=pA%8GWr)dlQcVB&)0Rb#D(<>YzKYS)
zW_rvY1HoveWwO`(y$@`R<{r8 at JtprR%A9?csVX}NbF>T?bXyV2Ns|2EmV~5n1%K~6
zbVNDxC(g!d(TlL!Zy6<|{#&1b at e5c7p_qT9!gCj`i3 at Q^bcr)UV{g9!0FB9No3>1S
z2`ILDQJalYlMnOb9Hbt at hPJFT%G#<Xsmaj>@<1R@#czf28)aJN9e>y&bq)sHE|T=G
zz81y69F7v%bJ_<kApn?vfdJsaSKdegV6^~X%=Fm~V_E6ij?Y*^H#%V49i;Z3DAkg!
zw{Dj0zmJl9_};%3&cQXZ`yYGa$>^lB&WW~>dC=JX-1qFSd-N}7PM6_xq5=@>Zpu<T
z<fx;Kv+uj#{U|z3n?>xdtiMKyu}~W1IR0!3v~3*e+WVPoLZ=*ffHLuxtLqT$wXRXN
z-!Rom*wk=*0{!IxoT5I2mq|OIF8^8OSRAkBsW<?4p;jTu3vj*THp4W|GR+oUx&8p(
z7tn~EUtJ~7W^<O^W4O|@X)$IT%JKu09UuShs`m~4ojBdC at 2%BO-vqcu4M7&JlnL;l
zqX8HIkOp9+cB)$E{p~Vy=$P8?pB3XbJGK*3)6$qY{#}Z at ***@n04Wz#p(e2
za&++}mqq=RJ=g3#L+2F(N&NnKp-vcm$;qci|MqYHW|~DFr<nh43Q^WYM#{{r6kq}o
zm&6z2`fG^TSi&((m85aU4&H<b6J|7?>_k<kM4G$=YTIvAMIQP7F!ioUifoti^AA$z
zof~et$>akN3!kHiiz%Z{V%ar`FV)|u|1}f91p at 1(wkhYXf51&aw@&G@&rGVio3>u^
zchPkT$)2EX)amlOT)qt(Mvb2}JCAAlyh)?4&#&-v466L!fMsB8ukWgk{nQ%W_5&ah
z=mzZzu$Y~JaseP01hP`RolF+G)(~awnIs?Cmje_thtWQ>TmQ^}@rEj`mpbPg$nT%C
zpJ9IgIQ#$4>io=T0iep>f0yB-qhnN%#FpVyxSgwbcz^RAzBUv9(Hs-1%p@~D4g(f7
zpa?p035zCSU4Q~mfFKF?y(Q<QO>(hu`ke&=L)GzzW*_ALKcp&4HX{KLVs*cM5c<mw
z`2)}nG<Hgc{lBX%><DP|&?s#ArDq(kJp+k=P@`cSn at -jq?;LzT1E%_|!k|hO?KL~p
z%TU*-jnFafci!=Ot{t7RKLuAwHQ-C)lN(hFaMa~jl>k7gCeZz0Fh-e)q{a>yKe<k#
z6LHvK$na>`-qWJ{A9%p@!{1L1z>tPe#;EQ79W81{J=@7=pJych at 5TIANL}7d+CaPR
zl?x&P;3xwPen(>%BygfA=LOmG^W;OZAhMmzsV=F(=bwLm^vhrU%CsIIFKyAy3o#mp
zq at o=rhr}HriKS5E_9Aq~4lN7=7!Ifu{_OxumdSjkQ*MLIoio*l^&V{&bBgv~s3M8C
z(|d;UX8gG_|4$O`YDsrC`7ZnE9%ugca&p}Nn|r70pl8t<%##LiyLLM!<^M%#0M{xL
z at E~>v-uP<wIRP!v!3 at S`cZN%lzN66nZLBgA0f0dh_Rgr-TPw6TLR&puxOSZ>>!kv4
z?m>qN^@f!?F&lSG3g~2Fq@%=_0fWQ*gd#Cre*gR5M|a<IpB8O!+nB!yM1sIj;*kA<
zh^kB47Ci{)r9V}TQt(f(7Te1KJ5B#*%W(>oR%*xF0Wz at w2RH0nmj_})!~ydp)kqR8
z#A+f%guN+#8>JnfpL*um=t>os4N?>!FC?CZ!@YNI=zBkru7PWXpDP9t=54Om7W}IF
zABy&0b%|FCpj6;-%5rMxp^FyR<O?K7<}7sKVmlH96q}^p{eS!0e at 9&^<ps$Y*gcCB
z4tz&U|8o)KCF+t(4Zu!PdFrH2a*jPW{;VOSPgFdc8KGQ<(tHO29iccKcl>Fmo6s5E
zY+h4^A~EAUDO?6fRit<37(K)13vx12Ms)}b>3*4dLQ;Y}YvDlxFvYkv57b*Ml|%KP
zfB2*5pH!keML at 8lq+&dW at p|~fm-<M=yiwJLjgOP2U`FllR<wrDxmFvopKCT;8f{de
z*^wun<lNsrN9fbq<@PzN+v$zXg?pdubL^lwGQ-iR_H%jyVgg*h at zLn84Ke|qe7n{X
zj7-2ubLOThnLinM|1Vnvqh?7xb8V8)-!O1y$mZNf_16FA|NNimNEMLGlaudMwZDEu
z9b>5Jrw;o#HKEv39_cU2LA8^PZ)#-hrFvD=CA^f76V=uS78vI^dBeXdbL4lD{0}M}
zc91;kO-U~?*)|>^+WQ$M^BAi}K(R_)RkiL?I_rh%-~TT^`AKxL=64Te`Ef3_6&I{p
zZF2vy_p$X^w<3l%zxk?v;Qx8xkq6W+Xy^W2pcXee|ESSjihO)YjZV&2G^D@!6Bb at 0
zvsPhXtoF_&fEqBXLhF$QlOZyVvrfS4Ha-#^N;&XjZa)A?fC=gfoW5xCQuRcbwe_+K
z;=cgiXNbaSB$E4gz0Ejq{G{kgHCz1T7oSGIl`T!l at 5YB7iq6tTo>NtAwu{1Rb^?kK
zG(kz<&NRSO4o-RCwFCL>$>5l?F1WzN`EmF?qHyGN70h6dRsmChG<2K~u<0?5M6`3@
z5}94ctUW5NOc|bb>?v?M^MV!9rrwLzNR#>^8HxIRsFHhVa{1y*FPqIqhsnu`=75IN
zmXVl+McPfq>~c-8lD~-vg@${*ykqS1d_m?K8^@4wI{V;7#?&d)#GH9)B)U_SK5u_B
zq2fRmZtc5zEjt5N;<veK3x2yCnbrqzjeGzL at c}%bFyI?WKY-QB^h(2k?MmXQaGi8w
z4S{6`w*H>7Hz&<o5KWoCFdC;Y;E+k`izn~;wxj`TV*C*@VN%uJw>eXgbASscPBKcR
zUE<jKqFPfQ0ZJLQ<}6R^cRu<k`j7wk57TXEg1pCHR6-2EROLFxdBpIfJ^-8!&y?c5
zU|9Rk>0EdfnkmydjK{GjDjA7z->pjZ-CbFe_zwmPbf1+IkbZ<`uedncO?3;bk at Y)#
zh6qb&c+r`>D9k4PKJeVWKV_>u2MGWtMjtD3bF^wr0L6Nrixah}60OMqgyTDL%&^p4
z#%#`|Q)pqZ8Fi+Y1j2USFxsmGOPvYukW7HfWCGm#;_E2 at tWx}Z<g{7QKkl|yZS3m(
z&Hvr+++!R5yT9&}AFeAS6cfq|gz$nf`&4Rp@%n&7%OH3FU|hg~@pe^@fy32n;M?E+
zj_Ks{kha9ajs}HcPFLcZzdbZB^SKn)Skwxw>Ljx#WnEtb*F5x?<4tBI;jM8qW(j<T
zM$_jX5Iw0H3gY`@D(*Ep4!ttk6}{-~*V%p4xadahuKbv)O~)!R&Uawjd8`SpnpTvq
zRmOn_9mK;jHV$EziDLl~GjO at -Casfg$5QPxYqt7YB-frN6TpoET%$aIh4cdm0)S=m
zg3o`@Z|xoiSVE&BuzW_x#iIaJD#ZLV0FqHR>r<O|Cc{s?`#;bggG4K64>fbafzghV
z8iqh}lY5E^r>bc+K5*1&Lj{h&vD0Tn_ifx5-KVnMISUVtc2jeX{pDjJ0`TP1Pn!az
zJ){w2!KZ at yUrDuZQ;K+=c3GOlmVf{4#aMIHcAd>l4pBGaos_C=qgZx5Ezr8mZs$H;
z6OY*wiJdaMW%ktMi<vn!Gv&*|(Yhm_0Va1Dd^=qu)f^KIavObGErHLi6BFRJWOL9L
zv^CfjDhAq at YQTG63TOa1jM#35Z{~WrAmKi9Az;K>N5h(jqdHm%wyn^5j_kwdq%QyY
z&wq}d)gE<(&$g2!{VXbTk!qOHJhCbw#FSy~M0&UqBxKU~-(^e(Lxiy at F+i!T*WY|g
zbdNGC(OiZp0&t8{t?Af9CglOj^4ncI5?M3I{WQc?G#p}&iO?}$lD{FybOcPA*sMuR
z8^^pU)s(EZR#=r<47{UMV{(J$=24ZJ50n!WX3l_Ma*veJJ!Us+;4*w_N+#;L>ztKu
z$S}TPc+2!Kz8y6wzrEu}ikZH~_%5?shPSj}HIF$81G)fknTmmCPzz8M0GeUe-f&JK
zV6*@fsKnD2ER61#m!H@;d(flyZ#SqbM^(<3IyKcjAx_Wiuo5K&0K-UGl+QBj5HYU^
z1VV8Jk^_h5#cIO&jKJy?)wS=VmR at ISL(8Y1doH?v<3rH_>K?m`v;o(->HfXF2)3aS
zaBOCtD`2<s?D44iVygU|0#h9bW#`JDJNti<w2sym<6lzdDf6(CQlf*$2A-?t<8kb8
zckW?eGvfJUPTjvl^POe-nja~h3+FvUplX?)&maI$4HyIf%NPMop!=D6&$gQu?lV_6
zF>0DZNMjhe&y46AdCA#S1Px%SY-c2eb&iGY+*m8f)eMsOy>*0!Rm`k<8B3fjAk>&8
z3k180v5(X~gI`uT>x#8&qxp*#MXLk`FRI|@7Hw)VUHSY-q8;)^kognBP8i(>9sB=n
zmGM`{#GWH7D9K!H!Tz12HB`}xijJ8sKqvkAcA0UQc1D`odj+1Orrm at ACJb81nxr77
z|7-3TzN5Gy(DT&(SQDrXHwu6WaJfu?S(pI#g-n1B0HkJuWq#LWz)7 at n-G=CWZC8c2
ze1SR+`Cjqv0)VX&mD5G{tZ5J+MiIvs)qZS-cGV?!;%=$_M=7yo-DQ_W&%N+sbfe0r
zr$`gn&XZErBz+73d5j+dfY?S&%m9a(Gw+1zo#%iJM2jqFeonvD4f;lu3~Dx(sm6h=
z#%HS*!d}CVN}2x`XlU*`WWXi`5N~}#S`J_t7~APPchntIpfULXaFxP<^XUrwpi+U|
zFyLtAcYoIL_|}DcQb$|taI1?Lcv?gEYYfHC$U2FitM=zO4n5l+5B^DN1O0|tV?870
zIZ#a at QQ<!;XJK~aOZvjhKhHN1BEVe6FoX%?WCuh!QfbpSsg(K^h5Qab_IOFU+oI<M
zUhD;7TES<$)JVQqdgQCXR!t9lT8ZYUz(&F)!$>@jSY7qqm0U)(O+X?Gdi9P{<^|@g
z8wG%2=Xb7h<ta74R`&l+IB=8e1m_yRgc*r8<~(Dpiq|Bsoj?1XeNWzh8)*TI`0q9h
zyIz57%`tfZaV@|L$^--e_9GAAQMCkfHwGD}+<RWkzPOnP7gasSmQ`uZrvVN-;t*Ya
z%-DMDJrJqr at y`HH!8vtNfq*kFX51VbJ$ZNLfWo5#6zhNWjW-SR93}@Ep))HLLd2IP
zpnB#EF>L;KVWQ8hRkB{L89_4D8R|UrjSoMJ4nO`x_3T@(VxO0y<;wEwQci_k<Dj%F
zV4mC at 42L<sAckPnF-98+J_{JJ*E?^R=Wzgq<91cUQ*vM)dhD at imbw}H*UNg;>zUj2
zx^J!bs(T)qygH6t`*&@f^FT{9DS=QoD&*GqLS~lgWULeL`Bz?xHr)L{H2Iv>>ItaL
zLElO?2c^@_M5O|Q&@np2s1(0YypVY)oDzRZFv){E4;zC;A}O74TrNly0Z7H)vZ{E^
z2G20OndBq^sZQ;T-<j~xA(EW*@O%BOx1yuvH76F!f at jg&&RzD?IJFYV7)!v~u#%ws
zQ|k~Sutef~L7!$g1h>1Acuq_<<+$pG8=|?2TD+?U9%raq?*KLIOr at s3Zp=v&gjV?+
zcg|gq2_<%=61OIGLkv|HCGmj3f{}af&N7V-(Vl*6o3%j=KUmZHYX=golIN^}XB;9m
z%$m$wDjXfb_!-LC%_tC#PAR)<f>srJ_PBqLV6+<ejD?4oWG^&;=U#p_T7BES(a2LS
z)Yf38EqJ^;@H*`dJVC`bH2{c-cxz?c0Rkz3IYhP<+JYU9-Bu3>);7zTq{KOv(I|4X
ziW*b<T1WE#yleRcoe-hR{PA<glG+fI-W9L-d?iwR<HK)8U;D-f(XnbxM%LWci3+z3
zfN7bVT=~$DV{QA2V>|CS{vW(%dLMy_>~I%gc%JQ5$aBb&<D!QZ(z;)*tS0Zfujyz5
zv6J%cO373ziP`Ew!CAXHK+l3|jp)$;>ovkUK+YVKbFG5)bm^rs_$2Q at bmhP!jxrIP
z>!kXRo3XE9-Z~oezbi74ea7~3QnCzf9nAqPI5DLgGof*y*T&!L at 4w$A9 at 7svIJzYT
zfLEebx84(VExkZZLEmsp0M!DF6JfXv4Ku{UQ&SSuj-4fW(%zZOs>tU~U=ptnPg=c~
zK6sq2_m5?0YqgQY6o3G*fp=DhA0@|h^I at O*AFEjA2&IPNFiO?81pF*G8VL<BB%n|S
z42HS8az+dihT%(@-U9{qyaYf-D;4>MTW*b>S3W<c%i<+VqF;RaX|zCb{#{f+l>v-I
z<Fgt at tVuZFZp=c54t!@@h;cHKuSDWiSff&@S at 9aIFQ(hxY8*pz)@QZ9;esQMHh|Tx
zdzkAa%wJBwtpI?- at Cmb9rguMm0JvBHFyy4=asoPg1Dcj#atOH$U518b>I}?hMj<md
z=Law<PQ_8KKGmLayFtUE@$!YRr5KGdDD3%`dJY^UX|ba+!-D36bsD9BkeE!?A!MCC
zsiu%fZ7ao72JRB``=cTtI3Unp#XQ$3r1hG-{%kmU={47wo(Y(F{Z-}W0?f902BY;Q
z0|3hafzkf5VBl+bspmaMf|k)qTN$qe2w;Aaoj#CHgv~woRmWVwttX$M92B6(8ecT3
z3HTt83jhx|4MFMvAd&24AdvU_XG9EUR77U~xN_hq1C|QEd(XCwh+~-=dC*<x-~avJ
zqrd+3ud0Lp*r?3d)}M9E24gy;no*5GVq3FjG6l5)m at XMcy*JF8!}yLyV9zP~M8jBj
z#g)<5RLldBlcxLw)$(7sa%HruGW at nz;Zmw)B$|f3o~yZ}Kwz|*+WTzffWhYlcxKpn
z$Y=)T>U51pD%!?P(NcVEBs`kkcnLW)A;5j_x$_P4H%sH~I<Mv%2=hxL0 at StrbA14}
z-y4lMMJB*TXLHas3JKAHCu7&UY9I?Q!ft$Uo*nM_o{H(KoZkOaVzWf&ex|01HCf!x
zobZr$4&f#|<ka%BPv0+p`Aa$d-qzMubJOQf85 at R3M$9N0juhQSOwGtJs+eutgqisa
zj^rGBe&$mSs%^~3ni$#t4^=zwDaz at 8H~Q0`{$$>PjV$JA`)U9teV&~A0}ST5yk|Gh
zVKoGOT5zy)VCTiqhO=%pfT)4Q=L8mJgkttq=nz^p;nnsHqBx5bxnXVJQ=R{CnRhUM
z at Hvua42Bgg-6Zsv%P%2%PWhmwA=daQ;gP_3LE6tV&jX>*+1ko2jRGhU=n|y@?@cQ3
zqiP6}h5 at A>PEZtJ8#$Ef28-{0?-8LTem>hZ>ImK3-!cIVW}hi$wrV5)J=V$xg4Co5
zDO*^-qHrIrl#r-J_cF{<$53K67%n&h$5(m&iU4r0ihO>hzI|U)qLSGzU0r>*S6Oo2
z{M3U&{M-gGG9!NOEGWfbl&-me&<6#;Aw%Q|foF)?A?9L$$ODdn0*rWs7 at APtVr|I6
z`aYwy=fM*u84$Dg$})N)JVFfa2*EO8kO~A#x852v at 0Dma0QiMGW(AU2i+DZeD9_=x
zG!H<<K*|G{xklB1k17h_0>F3yK<47<MQRsI7ub=4t$i0?+e*>Am#Z{cC6gMuHYzwf
z-~Kacy&{h9soT&4YC1Aa`{C`NeDHV at Ya^BTiPWzKcoi4BDp3?1_YJB1fBDN_qSXSl
zJ;#hQD!)5-A;8+E35_K5-j?7jJ=AH7A?7zGM64mC%pcGYEQ1@(Aa9^C1b*w9I4N3x
z$tBV2(&z>#FM|7JfWo`CjRskeN~OFH04Wb7G at OEAZM|dRP%jLab9Y^~Cai3RCqx}a
z&hS|du=1=~&1+CJ+bISj55Q;uYz_8E8343RqUXF^$@RaW-_6LI1P6pdrpf0uNx7y&
zB6YC)C&@0P+Yl=A#z!AB?Z<EyWeCzI(DeTzCI~7pYEcx&Bng=?b>H#awXv1{E;GH5
zNV|yHX=K4WOjYV{**T at ***@8<;%BNSF#DeI9C(cEFmoZ}Dhl%%cX;-G>QJ_h<pw?p
zWz*<n{PdZ|tS~mW^-+1B#_TX4;%F4!TBmd1nZ+ at K#xxr<vgqCgYX=Nm0N at xO0DQXN
zO4l~SVf at eQ{yu%zt%2TSmK>dKBGCGK9*icQzeXB>5`o at K@&MM72QYV at K_&A*{&3JK
zWz0GTjhQul*uX>A**uP26nY{1f}a!N6)|LpxIUwW%v)&dblhIH;Yp{S7JVw_ze!;;
z3VXIwcVT{Sh3Kk;AL|^XFaU&ai8KwLdPM7gum5i|uq!(E!WGf4fAgDY>DlMXbm1MW
zbFH19Rp&)s?A?=*c(kiVZQ6HSe?^MoffJA_PUBF^Sz8|%d at wL3h6Mu)guZXg2LXqV
z4AWy$CelCUG0R7eunRJ~$MBZfk@~v|{3of;!;vy|E?U1Kx<WfTZB1#qcwnXg;MSxc
z02;u$yB>(fo~=y4M_d4q4`93!fk3W22G1~df<#8j+L20&7?}*y8paKcdP(tFO>Rxq
z<L{bESIEpcXdYyKhbi#v at 2z)c%dQ92|82 at VwZoRQ$YuPTaHb`)^3Up_%SM>s^J-%?
za_Y?JgAYDbsqgdAWW5LPkY2-Y;Npf)`K at 9&wYB4F%ov_0o}=uTYLT5X;4abtpfi^S
zvqC4PXCsuXB(_4%VSJ+jSjIO at ACIjW_It7pQvsStcSph_4Dnr1$kl(`glM?-y_}#v
zm@~9P at j?}#opky#RdZe%-FDBt(G%L5jl!<yUwFZEb9zlRA5SaFv8~F};enY-1-1b2
z+$*m}Ywx;08hzHPEC8$#0F1 at s?MUz%V|xtkNMpmab|h+3Jb{urb~M7EJ$Njcj*}JQ
zW80^x`!AIDdzctUQX(ByrJZwJ%OKGh6VOYJceq#e{BJ2u`M{%&iFOpxWSGEzre?Go
zX(#_!v^MT~dw*v^-3R$@{=Z9~Ie*urx`dLlAydKSNO_~3CW6jrvDPfj2uz2;CF!>|
zqxRhw#Qc`&x6*l**YGRRSF&s3Wc8IeFgilruFuqNSVZQ?<6x)j$DV#BdRdO?SJh_z
zvB#f??z`{4=oW3=cAd)7uTduBx~r~^&beq+bi%STqr;T8K1ZA6V48&i;DHzb9)720
z0$2d}yimx#s5=oEM%P4shWd9i>eXxr#SFtpO)yapox{TKBxV^sZH6XmaP$vGYE~J|
zO3f<QE}O3!K%v3VmFO8s078F<Xb0OJRm*PH#WHKkj5&-(96TBBde{9e2Kbz-?QO!p
zgT4zRiEB)i9^*)8L)(E-XR at Z(Nv;R8CL?BGF*3|tHmuZ7KI at K8u8HQoV(t3q at u!}O
zURGx&c8~t1dQ4Kl^|B=Pg97*KuD?E7CDr~+Z7+AU($Nn*`k06w24l6CN0&mH{nfd7
z7qu_nL8c#BoG$3rnE-b`7>zx5t?~fgdN+*%tQOjgktDGT9}`6)-7TX#$euDelEGtG
z!$_5xsTxxhGiI|4xmWb}Qh_)1FbNxlYIriA={&~(3wRwPY4L*8z9ZGmW-FO5Fn<=T
z9a9Vw&1YOo?3Tb4wlV~+v6Tqi49fsIHjjzi>jD&2N8R)Ad^wD2zc-BTFlEY|Wel0~
zd-|T{U7hz0+#__~?04}sa=}4h at C9iGU*I!&o+$?`j5b_*UG%tiA-eOv`%O#oRjN=t
zQxg3Mt?Ml1aST^}2U-Ha_BpL%MmWRpb~u1;fqkZ;0I3f^c>wG0-55<E3UI%Z2m}C(
z(q4R4s at E7iUy}DMlNSL+<4sC8HPe^fKa>7xz`=Wefx)&Sw9)EgN4^3Q->z9~deyWv
z0|-)WAreD44ui%_Wf>}FcuSat08q!|TsOXcN{ki$&eJsNw2cfXGynjG*^&`@Hw$tp
z^Y<VCBp|SxQn$y-0l&ApGGXiQE=kVX0(2=DCcvGpU9y&Dt}{#@3jlZhXG%+S0bre?
z0AtUW25|4oZ=?-DZkIFRG}VnCdfbUQ;{<)59f#=uhaB5W#xZ&hwYuIchitmwJe&16
zQ5kM|Yo_nj1Awu}jFX~8CnQ5%ffi{TX2w!87HeDZ=7+AK9h~g7n*Cg?YgB#)X+Mh_
z87;kE6LaG|+u{1Z8QML{4EOiov(?WhYi5RBM?P8Cbi`|I*PYMvSFep8k>9|S1IwgX
zbLaihh%;73{qAvEg7IT#bmpK#1DiJu0066Qzb_g>Ex?_Q2GCjf&3oZH>)TmhXyBQb
zUWr!Ra!)jfa^TBfdNX?Yt#_igJJP?S{d8zxv!{W#lnTA^ndhSuue>P+fF;ko8Qm@|
z;L%rJj~-X6pvQ#{kG=46^ymvOMUOuJV)W>9j29Xo&+43HJfhDnV?3|-^oRTIq2Jx_
zHtjsw^{T$!mOheC=*1b2>F>uxNB($R{Rkg_@#T1^SxIfY5<T&9{&-x!Wsgs;VXvjn
z$8_z`J#)W%UdMaS?Y={w`P=Ym`FP;z=c1Lj-WyFmdrdUx<P}lBeK)=o&AIEzXx0t)
zMbj?7HQIa4wb7&%mqp{xTNjNxYjres*+tQq(^o`ePFoR;K9zA{Jk(Dt9v8&p<O`xv
z?ohj-QA?MbG13_$ggUw7#Pg#OfiYa)WyT5me>%?7-*(vV{r~g5dt3{DAMc&Z|NX(e
zLf at Bt*RE&eIwvx+^Onx7w+427MwvCMt>fsEopm<r9 at D^>(^iTm7#A7(uw&dA7e(XF
zTxIBHywXf3oU<mHc-~s&oUe-}U9diyeBp*@@0FKCQ!c(VnzH(`XrDEgM^o2c5lvfv
zRW$vQtD+f~UK7o{?AmDN71u?xuex62hG^E6*GDrizfRv at XMUe?$<^lgsq3!P`By~y
ztiC*&vg)#UTy&|fud(8iX!42;y5D+p-*hZrXP#xEyx$Y_TxKX1KH=Oo(Re%b%;U|_
zJA{Vbi+5v;YunJAoz1*u$5{P;?3oukLvwv*&d}VCDH`yx#%PTZTDu`y!y(I*2sHK1
zr=!W&KNO9>^p0rss_UcS=U*0eoxLs^eEKSb5CcUl14T>&MN|WiKeslH)8EM$aO}BJ
zc$}l}v!lQMZ^kj9akjocJKC$Ep$#mLvBRG0{eOwRU!w2YHI8<!#otxOQ4Jhh<(j4M
z!+R&gnNxr6YipFOqqDZ at nxCNch6bPo0gD-;jX?r;#^94RPFXI;(uL6w35+4jRzySP
zWgd3cMbR)3_i!=T2r=6zG2mzc!5A^=STXE40l|2+r=GC>%4niMVA7>mN0TqRCYpS?
zhCccKMD1fgQNNEDSd0^Bj1{wUF4y2%qr~K+mTTzRBP6)E5BD2>?&@fmn0S~NH63EA
zVH#ZwF;hHNMnmn;GxOX<qf5V=p>t}(UMu<3dw22fX2kb2LvvAiq|X{(D;?=`d-t^8
q+vjsWhw3*wx&+X}&S8$$MgKqj$!hTsu;d^B0000<MNUMnLSTZhNefm0

literal 0
HcmV?d00001

diff --git a/data/icon_ivi_flower.png b/data/icon_ivi_flower.png
new file mode 100644
index 0000000000000000000000000000000000000000..0a71479c6fec61bc29e755ba6236aa1681452cae
GIT binary patch
literal 24475
zcmYIvbyyT%)c@?Vlt?2X($WnI(p`dpDBaQ_jr6i~OP93L4I;4QBGO2Q!V=Qmu)q>O
zzVG`!&+m_UX70?KJ9q9m=X35opL?S;)s^rcJ$(cK0KST{ycPg}9xg!u4%WlT$gR}+
zzmmI_k}Oa?@@)H|0I`vIBLe_+ at pw1pm=9%K7iE2S03hi8?*R2Vms$dVDW8hG%zJN>
z{dQ~%L*a?r{lohwi}&AK|31&kebwWN^gFCKn*OM&V^N~4(in!i!3u?#1d&+1d>x)-
zk%U?iLS}|gnen|k?w(p<HUB7eZ1G|K)7Earz?slz{67tJ9-m`S_mm^kB9e|x0mLi&
zw`P<4;}XuEBYB}qi)k}=**rBlxn-3(ex}B)^hUWARmM-Me}`Ppy at c+fnFF*o&OEI4
z3qPabE*)euHFOK_h>?8*Ud(}ng4(SFvxc1=l5o04_dpx%@Oq>$YV^45w3z6?W>Uhl
zWBvlCXKDT;FQZY#(g~=*f7aD-%KTB8!(8KvkFU628!zS{Ydo<~W4ZzB<?&=zl34U*
zUC2}ine5-3XWwU)jnOv$(wnTjPK^KFvfoI&bG5OlI2bfqSTM0|Q7U2<HgbZePd8Fm
z{aCQH`1 at vB7n#)?9dP0&KcA;NcVJ$&E&u3X7#)q4+r0kaQUyiaD*G(ZO<H;BY{HAt
z%Wb?KcZt_0#k(4|)Ts0Nxq5WrUR79lYvrmpL2iVfNSVz|kxSKRmrPq{cM9<le0FKT
zm1ABKBzO8#kO0u)2<iBS)47Fq){2%|)JA4zmbZ3jrq`>E7b<_#Dv$b-Qqi*4tNQc9
zeB5Z$0%Zm%@$l<yQOeoFI-kKZwXoH+1y1%g8uovgsFzG>Z%`8$NQ(8*oo2rnd?xY{
zVUwA5uASsvvg*;>+Bo!g^cvKYZdKH&f#<`-DJB2!Sx+f#V%45pw628Itm=YNZ;&+P
zND(qdJjfIJ(Z6?TRiNji>tDv79gNXdzNzs;PZBu{#jRP<s{+TU_kU}vntAJJ!tT#=
zQcNCQq^B(3IR0KpNc#G0=BKWKQz4gC8e=@Sa at 11OLh?Xy>uLGFYKe;07!CV_z3yl<
zy83e`#_J284Vh_UZzE6P+*xFIUASM>YHv|x_O5H$dbRSg?Qi(qwZuhpr<A9uuJ&Ej
z!R8MGf3h!V?^lZ+vw72dqDH(OcS~NX2gvU7g(c60&4pQflx2C at s=>uG3(>yF+^9`z
za at w?X<eS7HOnr_LOBzi&V at t$sm|tvXAI`jAf$r5xUC$E#%4$p`iXuLSn2t0(z7rL4
zc}aPjhKFP2e-#O|csa&Fhk~Gk2W$RjyfvMZ4kcrKB1A`0HdFN<=2W{5ltH=u4S~$e
z-%|6~s+3&~i;vjGUb4?$DLwIeJ$Sc!u7K)J#YFA*_ at Jh*d{BWl)(iJ&o0;3dlH1MB
zkr8+e?{I5gHBYmYbNT`^`%1`oF?E3_4{vKpDs$%QOH at R)^K&9ZfY-r7iYfZ-osE{3
z!IAFwk6zC5(bvsiPt*2jn+axPYDRBeOp$a}(Dt_iNh`0ELpG^M7}{p8Sn8ga`|7|2
zH9T|t7&|NK{Y%q3<+VDa=w}aWBHO)n#T1Ue<hc|6%V=-8-ycbCF}cnFgZ%COy#8|m
zbZ*^bOa_*viZOxuAkfMg=l8|O&o|mr{{2wf+;pDi_^d)4?lAKe%FBE`Dw4v5;GDZp
z{#oGBzC83BexIG=)w#q4H{{(pn2yC!9DIyxM234q%N2AfiP<PeGHO}<?yg5|$T-kM
z*y?UJGtN)hSQv&j?9^T8yT>)n$#a*A&Y%z7_3cpdRnPU3AC+Km`=TYWd?5a|eHknR
zAtF9kyzN0{)@}a508^%<{|fkp(z;pTU0Kyy>OSN?stBbB6Xgy}pScS%@Vzlp+ab>E
zu9+5)@++CqsM;-Js5z4|Haz2QBa>n?dOdI*#2O at mis6c===OZK!LLt+nx4BmrA=-{
zL$Bgi%)i7}Al(<JQ9Tm3V)pw|*w12mj!cQWnkXocqoS-jzt;=OTcze|9b|%=arES-
zNKroe=bwBVKb$KER4+Nxop<uSs@!$LKH#MP5$NE7lke@~Kf$=-=K6Q#!rSyw*$JrU
z){utcaF?Q0LK0-~_6D5{uDXruY4I!7NzXlfE4m at da`z3_;JO8kHt8Wd3ryb-s|qj(
z`h<~!D&z{9=cPXBX(v?YjNv4j?J~WN)A+0}DLU&WJayvkO!RiAtu;s=(|7Uk4B5G;
z=TUN)`g at _k#AI~vIzgMST=d%_ZP{J*Hgx+{XyGs;PUL|Ul+ZYGh-_RVld^p<{PfJd
z8anhb?9x|EX2(boa2A8mYjzo at w#n^XT;9qy*FX=rd8nDR$!iIFl%hs{k0+bD6Hc#u
zQ_GlG#k1eHI$2Do^H-=^EE8i!-L8ijH&x!Qbe{aSbB$Ok^-R~2;1X8Qe9~%jkT?4M
zI?mzeErAO0G3xEa)YS!vxK!GsTP%;~CIJTSD61#tPsXBDOhIxngp at Lx?YY{wE3~10
zOYDul@%eeT{90Dg%BlOPKQNQ^Zn#C^AX$@wZQi9mL{nU)_o8;jWMi8>b83 at 0LwI^+
zweR!m<G$A(`9F|jQ%UE`c>(z|9TqE0NB3SpG#%mxeYP0yu9HW{er~FvK#dqpurHS6
z+v?4F0>y^B#Lz<??q`1_CY%vJI<(qvG<beG*FPGODsO2mZz^G|nyptZ)z~?&;|iv(
z$Dud4)`kkA=x?C{*Rtqeyo>+`|F^*W%L1kQG_rd;g^da_+xK_3r8j at g*(I%CSl<!q
zQY_5chk5PJ9%5ZCZPMx>Yq=8Bi_+qxZ at 5=h^woDyp=JL}?9d5h2YKjq47=NR`Ow<f
zjyhs|I5vuNCh<xQrO^I4631kSF~7rk!o1Y){@r0P>aD*LRR9AiLLEjo=q<{9_mTbg
zWVr!b=5+F9)%TAm`Hj={g1PGistuGmd%)xV&GcPnufX^6%t=4Bg4(=Ua;=m*O?ev@
zXyEJ~6Suo+*W%c?JNuoCU_~OAEEmFX771d_r71Ca7emWW>Z2=Sc$0_R-&h4eXBcF3
zbob&pe)c}O{qfKu^1!cZ at f~WDu2-cbWAD5;t(_uVPh>Qqh*HF?K#g<hOB#K>Poq}q
zrU@(eLdI_CYXo|cHDtTdxuBwN{yXB>_&bCspaSMA!5y<R=kn&9`=?gBVP$acdg5XP
z9LraVA&vf=R#2!QU`3Z$+Q|H$SRVh%ZCOBjV^3e$;Xg0p_KTjrbJ^nzGT+q0^DLe9
z6ta7yV~_8sorn_Oxm9$>b6X{DNl8Is*Zbt9*nHZ;z)sSeyh<Q^QL*rqho;H)8OGR<
z<kuzn{eLW)Jf1h^A-+ZT5XM)YC3{Zgi+O{Le2fVS2tgvn-=||`xaN6eT|I|wm$?>a
zbLpaumtu<ce#d_<{iOepA96ZzuDHiz<hW5o62|evPmkj5^uw)o;%Dcbq9Y}K<ZF}|
z%oqs7o-g6G(ltr3W&6E%<+X7!ym48U^6fCZ_BVEd+c>8?D)V?E>4SWWJED}ueZH+Z
ziC4fkTTm)+p|(8!c2*<7+;|n`GOt!$X+^F1c%nI0C at JWO9<&!3h?0G!V!tF~-ntt&
za{F)f+okTb?8I(tlpU$#bF;^r#JlQvXL2 at dyv&6mkI4Kl-%Pe2ctA{2s9gfzLNpEP
ziPog71`0n at zrR6eH{smPxG$vmbszncw~<Zp!hdSLeI)5q)3%h;|9DACDZH_JGuvJ2
zK<<wkV9F7^A}If<X{y$|&J~v!^dh!kDGkP-t#sIcdGH+KHs-qHG(dKn+8;~lpAy3V
z2`cr>xmn7Ih8qmDVK4TL&XNy at nKzR<grkIXi0xv2F|?|>FUTjD_d||aVVZn_xeV<T
zKbVE5^*%XIMaK%@IW=sLAZz|mLSF;%B$PScYQGjfsB#B(8<T?gNQuGTd^5GBT~n?~
zxW7oGr-nt$EH~bSWn+5y^ZXqvSXUWCZ?u=J{ln`{e**;Kl-LYzYzpF9SF*gz+ipG`
znwcDSY|ERf_YZ)&h at n0OO9M6X0HNi&H`w-asV@}p)@b7m7tCxCf5G4&eVB|Id|qj;
z4>=<|TJ*VRhhGMdNxIg{0emaw^hh;(x<B!Lt38t>`2ZW3|0J|apf@(yh^o3p%8A!N
z9w`&HM+>0`V&Hvix<eX&1mtXQpnQuStnvAH3E;yR)WyO&=I(6sb)|hZVPZm?&7$z(
z?V!K5ymaH&hHS^Moc?tkfeyNp1zwMj8bA+C-aCe8qzQ9$W6p3!t-fEIJ7LW?c|Vsv
z+~IxKz6u-mGj$_9Ic0q<X>y--qtyE)Gr#*8D#eAys*+TCU=$Z|V!k!p3NXSf%s^ya
zwHsdPn+sBIt2jeYbDFTBna*ys4H?Ae6>}4C6}isLtU=H7jw@?!mhf7{i}*H;lQBgY
zd}$0x;P607!y?z4-c`g?y;3jdWE@=ET;)x&i`bI*FcBXD&-)pUIhM2{Jj at Dx4B~27
zxV2aTlLfs*px4^(N>M}NA$_ZsZ|vbJaLoR$gtdP=M!(lEL{tVwFD{X*1cZ!1`#8&6
z67Puv-=rg@?9Y9=tPfUpcYET8n~)ZnVd>%J2Tjz>yK7?V8_-A8Ij}`c1o#L-bPbRv
z_t9WOnqVlk8$jmmA~!wy?R<NZktVAyC3iyG4Le+A;N8=$0Vj`jmoqL#*cO)e5$tIG
zV*i2#Z+2_0Dg93~fg{wsapizVXc)=#w<pEm*5>fWlBRfIh4rAX4J8BNKbIr%H3E{H
z5(;n%B8X_qv~O-_j+tSUZHKR*%RL at LZ?w}EGLYa(Ii%cIsisD(Kf3beNSLhX7VfgK
zU7UI19U`b~f8Lz6FW}&%kTfORTc=p}$sLQ0H#$1V$V{|kA5F5_9k<M@=+&#d7$O|`
zdd&|skv=dSdWb=HrzJz-XR*(<mmqzJlqvy_#Dx>ce4>9KV-52|AvA%>`dRT>W#FDk
zu at ***@9DGIfHqK<1;3$i%<8R_zEnzda>WH)p3&Qc4y=<<6bE6_dkrx%Lkm!Nq1xuBL4
zeBOS&f6z}in1F$3Pd;CBr+M{}JKl5bX3RCs=Yz at 5AVLQ84lpym;K;4#mJMboc|JWp
z at Z~!QY^4x^5itrg>Fnn3xur(?WA<7_uXj6lR<-)0I)2Y*G`L^1=jFvyDH*W;l*Pq@
zUrl78GXhKvD(F^kx})D*Q at vdXy*jI;F=KCD{NZ>P at bF=RNP0__pRZeP%X#3(<~`3D
zeGC?H7-dI-ANRWH-Ow=Y&D#gs`|<i8_(Y at 6{T#rr9+_Qk(AAw<{kSHdDc8wUVOYic
zm?Z_>R+&DTr_o7 at k@=|rmt=D17B+BzQ{#Dj(nfy773w&w$V?MET^@Q41D;~Jz2Y0#
ztzX;Nem}_)I4%V<T1cMvD6_z)_hR=Ef4xN{tq)li6Bm;73%UihUz9XHiH~aPLI1R=
z5uo2InXYMe&*^zdIVh9B+B3&%xgoHD9+jZ`>4)?~HDQdZ3#f<A={!k_A9C4ZpWgiK
z^W#&w at XZold^rbt-9Q<E4E`QUHcHJ<U)(ihCuM1CH}G0ADM4L!t%fa`_W0sRLfeV+
z%x_qIgnIDWeQ1yzq!t5sC!9xYo3$>npK*|m&?Rt?T4cH5 at NoId3<i3Q^A=ep`kyRp
ztrt(<pSNf@`WW?{d4W@|E8I`h)Iy4S`mqsU`l)r#0D<&eN5mAh!=uNqWfQtXdk9KL
zC>c9W8tijQrf6cC+e*hGCTdf2)JNYlG5&c((}Pz}L)7S*x*xRSYRDkz6>rhV3Nwiu
z`lu at uw(yKI!FegIW+EoPFD=&)?0dA3F^=UI$S&u13z+wkeCT)ZcnjtVV?C7g94Hr8
z%b`gvQ*CkE_-iwPgoTlrerckNZmm&BOZr|`Psc8O=XeVqSaq^$VQmz1ZtK*|WE8a$
zCPlzP<kQZKlH*5v&!=~4(ARPu5mHUpSu%aBZ(W)dxYPu=Vxr!gO|j#p>nWN|GeKmO
zwma)F$1vBnJCiDwoIc=BA&*kH)X860RsV at ***@jfaf|XNxB8TDycvrlT|DrVWw at Zr
zSEmUp(^$_D!`#ZBJb9W#uEQCQW_n{-Nz%2huwQgP2>%=+rN-GyV)_dmuj~>r$Ozza
zc at F6b<9(8S?4`7Gu(=C;nLp(tNr7z~fp(P`QIUESWu}KSUDM7cLWXN56E+=tm-upw
zxl^X&YL9u>aDQGY64HVTVC{nEKainH1|1`|UbR}A8xmh$zu)ofJ$K+n6?g0{4nq81
zF4X_nfVMSmx$k?KOl;;~er=L9YRo%9M^zm#EGqqcoJRM3Y<8la8|)?%t&wAat5 at Bv
zHLnBQ85i at M>x(bR&?DW6%jzRQ2bdxjCLnnglb^GKNh)pxFLZ|Mzb1Zo{|Jun)?U4w
zvt-D?68x3N at y94pP6@@&W10qy>@Vy!J(&GpNbV0X2YamcTh*U7dhQ=0joN-oip{qY
zef&l;@GE8@{zRi*z1 at F0Vs)*iCd2uHF0-j%eN-8vDUzN(I6xUY{7D#Rj~If)dx`<j
zIkF<wfQWnMJ|<lI&B~V3#3ir6k~Yjte~jZ6-B$0d!gbg_HhOm{evvtmm6Pw at hEo)<
z(tra?z9TKTY>k|PHlELQOdn2t>PT+NZSx<VC$K<!oc-&&3uyX46QF;L#<=5@^XDxI
z(6Lxyj!Y}8zIxI0+6gr9a#W&}(!6jac^rQ&KAZTl at KQ3Tr~oTTLiTkAD9;UFgutzx
zMyo|@DyHh9BtcZtKN=zq3I&INCqzw+O9$S6G;rqJhMWB63o5bh_KUFkN~@i~u(>l?
z&fPKKixsM3q5pO^6uvm={1pQii;*WcHB at VJKpErbSxoH=vfmF5VFcBaCcFPT at t<bo
zi4l;*AtHWE3)0kYxRHAz6&10D|EtC{4M2xxH{9q;dx6vDTCUm-dN&mcwayIjpf725
zs2O2I^sqXSrJA2w)@7%bh5vNLbDLgR{xaZeC4v_ne<c=FrB6DR=|T`o>-j{Cq$DJ!
zU+q43y_C62L!rK(9FqM4kjcAe#cO_*WvlcFdWOS!^sj7R%c@>j;4pdS#x6?p)Tw1!
z`Hs605BjFwOhihgPAi<5)wW<^VkiKWZzJdhI;0eAmfA+&tG+6}Lcez_m=J8lhVG!!
zHx|B)hx at VWMz1%z)@1yVZ9k22=}5}&n7+fVp*|3s_S!L`GVHdTy2kY1T>f at k>`5@;
z^BeM#g^Xcy3Qccjh67kPq##K~ge^Bx%dX7|&2g!1<J at ePHbWwngJHSl3ck9=uA|z0
z8HKL5t8VQ?pxXO!+sWRR??vZV`3JQvdUjU at PwQ~?!3jWSiN2y_vuQ+}94lZz#}U$O
z4 at vHq4CdV0zTf?%pStyJLMt_UoGub<DfC=5t+VQ?ZYN=j5s>v(j19wC9=J^6u0K9h
zYiR}lidi3gapqTZd-efou$J9R04LP>WBzXpce(9GgYsCxbKp(6TjZXFgtzbe?a0BZ
zv4bGf*8!4#A)f1Ux>V at +***@77SI^wZ;qEcSMj`&2q-<Y>~mq7gTNJYz=p4^n8b0f=L
zG^FMHU%olyC>{r35w#5^kcv4-_Ibe=-gZl}ZaN&q=7$qrN`#=`%4f%9-5~@=E at 6^`
zegPmp>|7*Fgxu^<`k7*e+OJC0>t+}1gupX;C<QidB4P$2t>J2qb_%+(XunNO^PAVJ
z!xYhkTA%P^<%pp#2%b07KhAiDTL}N4XHN>+622m<{h8aYFJP`<`)+gSk4S<ImjO9D
zLnlCkeCO#LcZCE;D1!G%ZR7zq-$$Dy^A}(b(YjDU*V}h7i<_ppcYA&Z>>Y{A<C(9?
z=(lTBFw`#!F9VFm4;hFt$bX(Tai1Ex^NlTn;nwBnrsebKZ}`-1IVm?%WsbjapS_3$
zMxp`Dvk-8iO<Gx#`UUOGa`MR%kC*?Q$GVljWJl^4KOu~*(+re<bSxHy3q!()u*O5m
zP9L7#F<;$ntOSSECl`{FP^ODX|DyLL?o1AWDKDGh!Xln;ii&J!j0~-%OrmZz=~9!+
z8)6qgc+0V5*Dvj=3YR5trMchM0vSXp+^}2FH;h=PI+7<t<B85ko^N<+&sOqP%mQ)E
z8qp}9plKhIY0GQXG26sy$*OhNy8x^JfbER)$6g015xCT|oq7>3(|H?GNC-OzxzQo+
zKt489r at N!}&?tdvwCc;~Hj1<7P+>GK6U?0v;IU7bn8Wu- at d_}s at zWqfMOb{b;Eh?(
zOTII9?`comcHgvGxOMU2Z at NK0{xEglru}KO=noMuvEA&(jxX!<Im**ml5KbMdmfRF
z+gh?5y=O;kdspY^@EkJ8uLgJA<dbt&g%IoN#2yxIDC)bQW83UvLJ>o|xR?V(lNjWZ
zVD^Yw5^pJ)btk{M(?z^Et|x2O(CJIv7W>9&`u7AHfKMb4J{JXfPS!l(CcJTbM0&Ur
z?BWg@;*tjoAvJVy5U=xiEe at qSXa6d>Vaks<4{*JAHcYc#R7sZ%@}ya9zw(-`YC7)l
zmdeBQ7-3Gb%Nt97N%jKhiVW<VZ<BRiG)3xik&<s@>uc?HHt$sroUw|(%(_Dp2A6eo
zHY^`h6ctR`sa1(z0er$f!v0AQ+W%38dG&SFK|tfwc31{Ty1m- at +In1B-D3J_vi|cx
zU{|f<*f++X7x{*+ at Jlb(z#TOF?~XP2kAo4JZ1z3+y4>&l)4(kQ-KnWSkXC9^9V%Zb
zkIH_n$y7s+!JTxHt|@jYxt?GP5Wmmg=@?1-8x(XCQ*w~9u<JDu-&?L=`Jtddm_1-l
zHS+OA9>DWE(Y5#=#lGgQ#>QW|8m<lU4M0YjgVf(iqC#IywBzpm10C_mUjQ2>Pre4m
z(GPmJIq=61!U?lvTx)qA0q7tQ#E8vBqK#pfqV4X0CEj_;t-#Us?P6@){<O4kK8Jb^
ziR34WZVBwf0(p=7Oh`p)pOdc(h|oPN-F2oaZ#Q)%b>}3f8cN{8w|Sj+9pc5%7($G|
zBnAfe-|o`i+!;A$uYSP+NRvl8DVz=9oA*Rr5IWyns*sL?ncOwHhU+z>%c%8<(`T`A
zGL*!WnNF=##6a?D<nOJSGO|zQ6$|SMU?S<4j4(~Mu;$@UM}2&St`;5t6n8ozuC{+^
zjR?6%=KttwvpEZMh583bGGH}srro<7 at dlN3kFpp#DdIEZvp5J}%v7x$R%vpz9*Z%;
zR%HAzaF#b at yBTx(g-*Ra2Erw^QWFx7i-HGa<*^Ckc;R+0Q)(V!%-_hn!ZZ6C7kY>^
zc#xPFk#$n<_hO=<zu`TzrKNuv49H-Dg~e9HcJQel=@B8`z=0Zvs?T_14Fl{xEzXL)
zSX-p%gOgwdhmomua3oOuSJTX(=HiheaDq9LLDxaBzjd7>TO-i3e;vmzmwhTmyJtK!
z at owEwkcx`-MR;R1qAH0x)2`KS8#m?$N&b)Oceh(>Hp?s7ILk>mu!5E<>3>rf`v_OA
z)i*aHLo9Kl+^z2MC*_h<RG=+T1)j05)(^|(tpUx<x3C8F^O${)nL`aCL?cD+;Wsr1
z-b-%bkB^R82c!L7%rs=X|0*rvc+Rw{3ZCH`aOv-{rGW|DAErMw=__<7R{Hmy(8cKf
znjPHC1;)Wn$b2pt6wo_=Njvtpv4i&*Hv`+nFX-jg`qB#>OUwpjQ9(5N?sX$rpu=$)
zO&aLx*<3u+xxXl^i=4C{T1e{1AW#{d at l@}`_#hkU`LSKC#J`O at yQH-eNBX`p at oP+u
zKUV0{@x_Ns%AOPd at WWr(QY00`zM{tZjbziCv`IM6<0WkTGo=q)!+86dtqHJl)<`Gf
zvFp>KKx{jjv9%I=^W{dzer&seN|4$m*tD`DznmoOL30A*4LA)*hKyt8V4%{SaL~!N
z-cGf#-O#`_-ikSyOSni19fI*3(8JeVwpy?O=jzeZnN8+&^nvM5eLk7>Qh<I!@4f66
za~@1yLsT`Qy{x90Vgm2!z}Pk2V}b+#AXHLEBog2v{54q9k^1`JVIA~NrEr|qlk`N_
zlprHPq!Mkcdwhjkh+$gZzbdX3-5+V&JzX49ugt(W&E3yD5)pe7<ynb`-S4Lyy1DM#
z6O^z8J~Qimjbone$9Q$!@sa;t at V8agrCdjBO75Q2MFz07XMs7@>PsIkkTE;V3Lp7!
zx^XT0dtvfZnsP8`NjsAR*@!7KI>>vSTZFK}FXRwlT4e)?+#L_LiQSiezzh34(zwt%
zSD%%1l6<pTeFg+b^NtaoK>}pFgw9Hwe8ZqU*NuLAAdt&s;R~pqQ*+65G5?%{x%?o0
z#ved0?F%*w_shZffo|3q?a#ATkD`e6pIdsD+p%}+{ocUNRP~ACpyMV_m?I=$Y`dnf
zc6~;ah32Z4t+?NNGnsXB7Wh&qMQW>S_4Q<90qd4(rIh6al%Y0*z&E_(s<%OEsG!M#
z0o=?1&X<;2&c75Mcn-g^X{p1_Jd3p$5z<*`F!1obUP_resG@!99^s+%{kJwsk?{UY
zL>U)V_gfH`>dV0tb8UidhBc*c&dVp7(@A<`DwlcgP~;1p at Q~p4DTwdKCA_^&IK~X7
zP*8gtbjJw$*xxV8WR%F+M!|~gzE$<~z-wTCx<ni0Xg_db){#ummby22A6CDL#dI$}
z at O5ho^O~QN2Enc9r54Cx68HyY!gJ~^7gzXM=1`fYH#<m=)sHD9ZYTz*jsp0&g(#x&
zK82h#odH}9FRY_EttaD>jKka9D=*~coJrIZVo#!=-(Rh7RYrc0AuO(c7DDw)97GZh
zCRh9QG((5E?MaXsPh#=)oXhVM91;N)AqHQqRf at z!*9>XeMAf94`m<U5AD1u8`VZ%$
zpS~P8%~<<Fo?EJi1N$sBQOB<o9*an}KkKzIoFLtfHwr^<jk?1zuI2MgRBCX at e;PNQ
zzwo?SJxPK;mI=H%TN3ujfWP8zIiJJHX8~`KEnD*cyuhg?*n6Vpbuv)*hha5S{sn&}
zHu~20<9L1cjc>p>^gf_uZA9uURZxC?*k{7K;*nV<pAK#>iMK&wYyRN|xh-89<QC&G
zRZ{y#1IJ}wMG(%0<E6`_Y7{qS2L*S8x1p;kZ{f&0By9)9P*Eez^Tt-_ABw^M=wf7}
z@!zV?oK6}HDGSy9b!z at be`o{44-E at 6u~f<E1N#|rX8YR*E+F;$hEBZm9%q<;)1r9w
zQ9Qil^-o0xE=Xy*>;9uc*tc<YczsEC2`j|L-+qo6CK6 at 8pigB;d~~gR1KYN}(VzPF
zM$~whNSe(^Ue~;Hzmca`A!;WCZZcZiY_q at t<mEUDW^rUZO8%OZla_s2`QH89Zb9NH
z3ck&U)@Muc84Hz_tQJ~GK!$4S*FLwRe+rJQ#c5vTEvFZFe9Ra<J0H4*d4cR)Kvgw9
zk;#OuTuj|vdOhk{U0rIwpco4Os6aMUNR&Rm^QY>f2mNjy{g<3+vD5hPzNWZttSnXV
ztc&VE!Dal~(e?Kh1Aq47A7l38Z~eEiPhzU+M;q?Gt at TLfPDg*cBvhh4h(;RKgC|W9
zZjQT7PR-VvUR&?XB;wFa9xSqqccL2dTzYF+XTtg4TC*CdK*P>504ASN(A7_cV>><P
zgN at TK=>71+O1Xh5h0o5CV6>)=+vwY%&Lt9u9q-{HO`l8I_ecwEO7leVXQ$udTwL&f
zRVKSJ>HSJ#?inqWH5<4eIDCXkX!)er>jX1mFzu&G{%c!xSpM%j^XwF(#m=|O<dg9_
z>!=;UtJG)T=?S9mb)uzMb^(X0xpzyQ3a`YkYn^_xROA1lIQSQDXi4mpVWqaJd{0%4
zd7U{izeog%#GK)y8xGx~_vdx`HW{ol$5W0CXU1G(kW at PU*_{x6J++Y3dj8dkf1E)e
zIxSBUbd6Q2%y9;X)6|wmf=QJNyIN3$u_|J>5K%g{N2(>&S&4O|^h$+wa_Wh^29DvU
zTf0wn<>WbI#V07j{jq%3Cx<w>&+9YyD}m6m`;uXQ(MM9c&I!&3VOHmL(Mvl|UnHSa
zf9JMP6E$A#Gs37DfnG`swv_9UgdRcm0`@$Airzgqt`m#rH!;vAB3|?~fA3(st+ucU
z%hIa!1D$@2-2(adqnt3+G+Q!<AgXXZ%v$rKA{Rnv+YV`bVRd at qIAKCw-kNo;k7jBS
z=dA9@%idQVmhQ!M_Br1DHd{!G8(N7j`}31+W8L9^O3Y-{%wsm_j;|P~5Ry1%t{icd
za+Y-WU91H<_IE##9!9oh_v_4N{2 at VRSN4#FsO&o`adIg^psoxyh&FzEUR at ell&}5f
zP|Gf9k(41mlaa=He|h at lh9lFcK-jaTIGs_)y76D!rstLF6V%Xon7WkAbqf_0|6M>D
zBuC)%fh^F+A3FO>J+Q)fvhH`5C~WDbccSDl+ARK%>5|3LD{Hu}Y(><0e9lWTn#8u2
zyrTu$yJ_H;r7I?b_yvN{g(qxV&dz5l03S8<H<@*lflW#bIl4l^$vniz;&?({Jx*u=
zM~?j at r})f8$dZk58JeL7Ar`L%o?q$DDM^8NBL at +@ej?l(0mj0CanMH`vFd~EzPMC<
z82vO=^{7J%F8la at 4r#SEFFAFz>H%88AKT-oIO3CtXN>WX=DJb;fR{-%o_n{6Es2qs
z4FxxTNF3ME7cR{!&0tH?pQ6_9>5KZZ#zTM)SpU#WSLA1A>H|~xp0{ZAzi8g5tU0_f
zgGu{j_VwcaaDGk2XO1`T<fU&wgahq9jJA4a^0kk8EuRpnnpr>Xj`XD>JQv9DyZxR)
z!_wO}B!6Uu5%z-4G>sL`p)Ym(&vs#>czJ_S3i`OyVnda%@;GsY$q)Ez;T<oaSCO&$
ztIbHaV)ST1IO)f2y=0<k at e_;fBu$TUWMe+#f#A%)2S-7YfkGoxy6Ugqn+s`&8U*^@
zJ}|z*4e7NJ$$8y+Y|%0InA8?K-M{!~0>H;Z^qBB4?P#3JJn7URxS|K+F@#SvfP#Wn
zd%sPO+VA%ul at dnRoFyd6-=DDW%Zxn}tK~)!b6;m)i~swJM6bGR^Ao1P*kg at yF1M&@
zl|eD2#rK4w>@tT#X2&bk10lRwbST#S2v#{ZABWx#%Y`7ieFd{33a731l4=!uB~V{i
zYv`oGYQ^;61cDSlfz9o`?*-BlY^MZUWM?zd(tJZVrD2DBza$X6q;lyx$e|`~uTzEY
zm4 at xO-?td1<dmP#CWkbcA71UJ8Yz%($V<8~C3>y(MwI(WM4qpFHqiTe<f5`2*{h(y
zv%SUC8>S|8##~t4J}a%H{3AYVXsj83bocI%N62$&!MBczAEc)`7XT1yI7HWv7r1Ib
zi6#4FvPNoOw&!*ZG3UPvXP{IzYZ+(*8-ZDL_z0d#Rod9O6P`Wpo-X#n|HA3i^4g~0
zk8hiuD`bgg8E@#7(O5oTVZ=|O_lhO_WzCtXq8wJmJ)OD-m#F at C>0tx5dXxCt2KMj$
z14-R3Kg`8T@;`@C>M-*|ezA<%Toe!c2R-?2K+iE5#nVpY&4K}`)igEaC8L<x3}7F@
ztHbTU-w;f8x8;8)T(^WX1JH0#a25Pa@{52MQwR at Cy{_YzqtD7M!ia>qYRL+)-*>Rz
zSJ!{&AjMVL0tOEd$5?5!u8jSJI?D}<QUMBTwFSg7lEYv2Kx?~HPDPdn?VtU0KTH@*
zk{dD)aGzwh9LNA#OtNX}?#S~^d&*hrp4`$VjY#4dvlcSiXayEqek&cKc6kH=jcpnA
zE4DGa?(UW7v3ElT7?-A(*ERAwgukCEOU3JBl#`hVS(D^MCm`O53R$%TaKGb7MjS)%
zao&2_SRL1iUyJ=f#!fN`LNW`u*fT->q;3io at kKC6B0`r#tN(mM{aGXCz;|MnVI$Br
zU+;APID4*dE`B7iwp7{Wi1qRDazT^@i#`L3;KqH8z&&B|I#_dp at 3o6zhq&Z35Jjy>
zVl)yJLXgE;V6$38S{bAYyQdHpc0U?BhPbIJ=8Ew;6yFG{RyfIXOLh43QvD+p`N?fY
z=2&d;Qs7`@Yic0tMP$gh?U8 at y044*+Ofe}hzY-$ez|mL8Y!n;B^{@oa$5yg^30W`F
z{|=9nd>EFQ-EwITN+w8$9jTcNid{*$tI`e2uPz=Ar5o13E~&&|Y|0~m#R}n_1VFCd
zdq>}p5V~rBSBAPPELQ~U>*+?~j{%HQXD1penHz=JllE*bRJ;<^8Jyy_GmM!HPLdUd
zN~ngXPKp?{-m`g}P#ttGBaDF0XUi<hsq%~4xSec8R?Crj*EQzIZ++RfqNiIBbDtt2
zMYR&TWd2wjlF`e4BhXc_z&=r|APW1CO7H?p9!0z?hb at rCD8kO47$ZPTMhB;I_Pr{Z
zwwdAhex$x+(Sdt+x7?G+ckOcgb~;>eJKqv2y+b8T4<^E^JRVb6X4NobRL$JtzITsb
zxkF)`1)m%RE?BF7T1etZfJRZgiJ*h#5(nkR93ufyNM<GfJJTOjQ8R?}$vmEMvET3`
zb4E;Lhquq^o`B34nXvoC@*blTXFlICR4Rjm`ZrG1`t-D(!n2o at N3ee6MZ#DtUvUX4
zx+K9tIW`csyWT@?9N;vFf5hvuk9U{+mEhJLzq~XhKbJCj>M^`AixhWx)8d49BvuL=
zZhqHC6BPPbFvX3ii<%0XaFMgS|FS<#yYFdu+5qST*2Y9fD)hc>XQSvQbXMRrUb~X7
z2D?2Z!$v+l(dzm~@fnx6?(0s8MtUHL=<6%K<@JIu_<4`7_26_50}rfPy{$jp0Sv(|
zExic^l*YWYol6_|TUW9s7{hX(hh${>NQEG5ojIjavH>4I#9M;!h<#v0351mxSxR4Z
z?nVE#&Fr8>&}F9tBx4%azm#QP^Qcc85I at bEaE_;iz{(zr3G_<xH#rth=AV7Kz&Mz!
zCp5Nb9%FT)cZP9y8ksaw#fAE-^EB=&B!^|tuE?D23S3|nbViPu27k&h4bF<>QX2rv
z^CS>{-9BhLA`XasL{sGAdO)fhA%dUmOKxQL^~w0=*Ux at u^uSLC+=%QnXEnUn(Fg6h
zS6)Q)>Q7e~JxOW&b&Ix8CNH@<mzgp at HJMH!uOg^j=atqKZ2W1xJKHw-Iz!)o`gIV}
znuNC&k_guN?b9RWE8v_QGPM=Q_rl4%tK<9k(p6eUSSur}+2Zjs1u=~R=apWnT;%Fo
zz98Qq3Jrr}XDcwt5X?_{5o8cRDVTL at O76YX=0%qCS%PH#hEX4Z*>HBMq(@upb~kbQ
zSc50iQ&3S#sYk<l?lCb!f*4?tMatc&K`|r+SOhi%Q{A7X{AvQA<dkYENAgbRoobhg
zT|=M~L`zDa47rPi#^8$8%x<Akwu=6Vn&TtU#j0IQFpe3fY411{+VV0a_q>vgiYkOq
z6kO-%Jkb8*=F5bIqHwh6!Na6=i2>-9?q+4EPrGz){3vJd^Hoi;cO38?G|H at y)27C1
z3N5f7YlkKe^xFvTFaj$%>_9(@EQID?lI6tJrqkd0FKdg(v9Vp)zOSKxXp at Sf{i(%N
z{<m3^QHvLIthAB9AF7bLxAj|X{;g}!PKATcvmOBf0W3Ts;P&aTgZVh^%-VCD>e5vr
zgq#Kt#{;Inr|S|RLY$VRc>={eDT#^v8Ts9J at mb6<u9?iWDiD}SpYOrL(2#YV8D$;y
z<aPSOnD?Y8 at Qz}jzn{{mR%r9ca;O+9nKQ(0v at X|=3<pRv8y-8!PVIU6?F}BcnlU{S
zlZDIi>9hjM(s7`kw(gOzZ~NazL?Cf85YZL3zmRb;3D5l8nkBM8iQh9Q_TkSk$EyhY
ziP<Drx{tp<8j3<ILNSP>%d!AULCf%Gq>Ot0r?qZ?^+T3T(q&;_rN=*_$$m^_-x)%b
zEDe_ihH0!1+TP^lm^L;jWdZ^MpJ`nd>=3wEA7(g{gU1f at cWH6Kwc<YY0Hs{pb%TAB
zkQPP%e}9tD3A5|6c>X(8^1Fvg5^y&96fY1wlpsfxK)E`tHedW?gG`@_N{LYZu-;O#
z4j`ZAY**}b#Sqe at 2kO_=5-1Dm?CpN|(;~7NSeaH!gEHeP1Em)+PM#($CFpm^%u0|z
zq{--cfWI1<a&+};1X^q^1gZydM#9)3-Q}CmnwWLyo%wW9{zSgU86%Jha=65DtQCi;
zO1=@&chmRB055-42*rES)YIAB$fz}s=B69$i5wyyD(dL7iq7k~Z6`|K))q=(KZuW4
z-H#tCY<z+$8X-=PBR-57>P5e^TG{WZH}|^{>(xQ~7I?=UN&Mgro04q&_(NhbkE4m^
zVYSZu&#Ugn4_7M}ChI>NVN;TZko6!_ULtS?8R*hKLjnho2Amau!`%ufmCI0477Oe@
zU4 at xq2XXbQPS|v6D$~PY&p~YtK4AJEe3|ZC+Bz#>ss}HKsSzU$*5io9m2obbRRMc5
zf+;5mr8g4nm|#y(mTh*VkNPn)TBH>fdzXW$f&v%V|E?5m3F3?4`;U1Z6)FRx+GfQ+
zK9B=&Adpo9`rl`nu+J_==VR*Es3$h9UhZ+uAe<Rt48(|cw*V0WeG#2iRrN=}u+x~g
zs$_7azyFme4A7fg9`NoihD_FeTiOyCJe0zN9LZvC$ODHCLyf_Y;J}?bOThnHAHHw}
zB=HWa4&kFFmWDmlN{n!k2Tp15U|~do9XsDaB|HfaUebIyN=1zDB!)db(T4*MT*(==
zG2sI}cQk=x_L5Xuv6mP-O-x0G9^iuEga6P6l at K9nah5Zo;*+0sIcjUUz+)gHz&%<J
zWNG<KBEN~tp9IIO<A*(d+pK5&KPRxQBBa)SKpNV%qWfFrf1T(bu34AF3$WhHp*yQL
z5Y6-MTSY({C!Y~q8^;Jd(F+C2>j9IONW%30sZ$}psrl%EH_D>{+eQO_=qd7NP9U0w
zt|*h41;TWBAS&6$((<v;*nD2~!?0*@w1!l=;@b^v_w<Gk#6<-4U$e9m$oIN-Te6ZR
z4-){L1>^6)gBa=mhy`Q1(1G(wHGO}7$>X|lxUSY<0<ORgqvsg4Y2J2L+OZ(e3nYpW
zHZ>sl06uhjfXBupw)Cc?0|d($d*apvQoC}{R@!>VGs3Eo{m`42h_KH4K||m_kL}<)
zQvgQA9u!1507*!6btEDM0{mVaZTY}FmPn=l)XD&GQoe_LWyrXgAx-HdZU!Taf(Uk}
zZ{ZEZDw0dnVh#7dYGLaINdqsAAQ+gGptc9B0paw%&u>!);-2B8B)ZDi(c(6%19Ve}
zrZ=M)g=iu~5>CDqKVZS3X>hf?QC at LE^W`u2!FImtvBJjxfMGyeHO6)aPJW{dz$dSQ
zNhREN-(t5K`M(G=HqS at Rrvfx%>_YPC%qoL0mvNV6atX2%T`k9x0nrxqh<uOEfR!IO
zun`cV1;!6r3#EU+64ErH!enAw5IDhP67lU)W~m7MKlL%msw4U=^Z+O&5g4asF$)k4
z06b{d3iJPyAwmpD1Nc%DX4nsXNE^4_u>5fMNg?L_s?Gp at oG{X;I|7VS05TpCAuNc2
z$4L}e1O2ajFKZrL#?VUm1>6#X at L2A^F)QE(msT~ilD at G>XcIDf2tgPQ7`Z!K_~Cfc
zE%z@#Qwjk7N21=Wj~0)vf!t`3yB6d6m%aaomD0e&N^j(Mc4yEqcMMRtBr_Z2(U}FX
z at v-6oy~~J6FV#<9r!fBuI}}UVdG0m`=?f3sDlwuws|UOl0a!D at Hn34QZ-#E&YxX*3
zqW-T|e|PhdoB&N%-o+ at ***@3dgJgg9%1VEd2+Dw~TA1JzTdo5-lU}KOW=H34V27
zyJGUDNiDAq7;`@Juf*7fqJNd*&^u=Ef%RNZRVxmPGFICtA at 3OfH?H(FQEV*q^l1wV
zOuFGs*pOo at ***@A^+6~D$IM6yVfo#v7#zzlF!?E+b{2W>!B`Bj at d$aX{&BRQ65{`m
z-Zy?&EN*c)Ka)S&koKmty}Aj1;#L}POu(eqB<iKiGXA6+VV_3M^?y<9-IcR=Me8x#
ziV3z|WHos>_Qwxw>jTc%;sfVR3Ope<phK?RM7NfaCOj4Y|012X&1IOx(hk$@g5V?k
z018m-tf50P&H5&3F#_!U4dZYJ!oX|x0G8uH+>cJm|1EM)<okhfd}-+yobwX&%^*PW
zmyaj{ihS<mg0>afHWN3gq$g~y{{wA3yt)*~Z{x*&ruv>S`-BHoIA-PFHh1+{0d^>W
zNudCIPklgS$AOIJ|JPwPv*ZhtQOv4`5tv8C+uSfuV__0yB19Im6jK5hV|TKuB&+oQ
zfqe2T1$PFago$lUGyAq@<z_e;Xc>!-sdnmS*<=f1`GkR0dWZ49a1c>bSQCikg6kd{
z6!)oNe)jaIVFv at xYMUGESuam#zM`-9ve6nVvj4q{c{arYUSNlhQ|X^htkRGI at 31Md
zDnw--45w+YLn05C{s9F5iQBxhRJO(Azg92T=#bfG at Y2<AX&~d4{}q5|_TjTFq8xqq
zRRce*<-cxQ1|*nqw&o_kWMw}PoNw|%oSYef+wW08B=rWODTec)*X8%Ezm*KM$LJ*Z
zzcz%_j3g0c)91JN879#--H5}!ex?=&H7Ec>bHL4Klp;XKMGi9yUaCe<nU&$uG9x~}
zC)!Q|3e&i=cuDWaTa}81ExU%4%J<%aM^Dhdll)#yytuW(ak0(;f^)q*+Q*&p#-to#
ziR+K!gun#!&n^Qzr}5vsSjcO7{b^+iGal?+hrDm1*!-w>ilUA=SUXQbZx4P&Z``!C
z-%Pnu^^p?YH*Hev-7;abI at 9Cf355`dhz!b0W7WKCQWXl7GEAjy!T{wj at q=)P5Y)to
z`4M%=AXb=m)7TLc=z%$oe-1ig+$Qb`V~|;aM`&j)xg2_SFC<%q<ei}wqQk`Ktb&KO
z=-M{vczIg_544fzB}teAT?@Kz+&v!>ga#I<WPjVW4Yp7I?n^djj<G;~=P-sDRAbCp
za+a7>`tb(FaE!=cJ$P}L*RUsng5I+$q-&&_hAeL+;awBQ!NqBdpU`x@$=mCf#Y2oD
znM%$Z^W?iOS9OP*{m)(6y3qf_pI;Yln6!QT>rb%;yrY6kOC}^|b$dGSRhlO}D;jxO
zdZ|Oc-=n1MCv at gzG8ivO;fW-|SvGD+Je&kWH0=Ui1dFu2tV*rFgX4qkEH`r0;7e9B
z{5e;dY7Ex$i96ZQxFim%x2dx0Dd&DBP9vPS-Ej1ip at 4)4v3S;mg+m^mX1sc^l5(>4
zDSmc3_C1Y{8F~s?Po1mhmY(<i<HyHOJHIiYzYBS7ws6g7PDF3>%3aHJUd5V2@&jW5
zAq0ri>GSJxT<aowHO`y$r?<cw7EWxxO*BpS1!dXoabvB-kE%#-KQF43`v}#TgT3~0
zPm`p_1<wWhO&W0U1923yNiQvv<Q34?oD~NLs-j{l!B0=<e$7TE&XHTJLMP^<Bjews
zYJ7}u>Y4BExb*s?!$s{JQ#UO+HhMgt^No&dbbPnX+^@~qU7t(#X&81*7R%)Nh0*|o
zd#yYjdjP954#$9Q;lpi6=6F9QoWGSCartFocAKzgwOb^5Y1P7);hCUKy=op-{pd5`
zj6#Ay^wtU2aqF_R*G(QcCU}w^2Bc}roNJ at J9S77HYo1Y4>?xvtdoX!+A2)jY{h_#D
zd}^ALsk{4T)8wylq7Ta7exTjZ=u^xa_E&G?eBt7w4Y_#kk(=wuHxa{rdSohy%aTK#
zN_X4Sm)G#VoCSB`Mo}RnG0*m?3lrtkn0VfU_@=(~m0N{hXt~T4RI`7Z6wl;n<J2+x
zrJG)ujn%sOH4{a`{a%vgSEkecUNxnID)WTBcL)1Fql@}kX~W0)MB}JrwgRe-{^Ipm
zT+19^p23@&IuGBgrRfuq?S^mSiY{RKIpO5P+Zydkjuts&Srhf;m6qYyS_JI+$6q6&
z?s4>(rTQDhs<1mz<=ef}JEMcKtN(rnj|=iu4&bRveX9%^X^Z%ds!)7h=3w>gW5yNl
zlDB2c$Kt!-MX|$9Hqw6F6WNDtW5j0sW^Wb~nf-S@{jIkg-=YsJbD$yjR=f$M0}l%_
zqO<Z`X%xVbsiBE5A8l#v;t9j6v9k>Kps6rIyo{Smaq+Vw`Jp$fsI9J{A-Y*Q$)Zcx
z{vsH*eJhG{_INTXsYR!E9P3uBZ~)4V2dpo*8}8~Q!~hzQ4&q-V)p}+RCj8X2p3jhu
zCaYt{9Aw;lUg>oENqZZ3-isr>bA@;Tp(oc{HIG3&TY*eJxg!1`9j*$6lY at f^DBj-)
z3rrt-Z5`#4#{a^;bn2RAy=Ff*0v&1>7rrk4z&wUc|Ecd6+P6KAY4uf*B+!edYwMLV
zsY7+J^(Yc(oe;yGjVJ2ph+M}krt4aA^XOv>x*v2V8j9n{AEmCPZ88D29T#2GI#N%&
zigN8}42gkd$diXTx&RdOuE)G7A>(Gr)S%%{s2DG`lVjt at Te2CSZxpXf`q00=Lm;Q0
z(@hgS<!X4Vz<2-du at a^qa#b0-83z=!I%`;b8jGkTChWSbjNq5yNfq at T1z#1ze+c$j
z8_dkzc~&^iAk2kh&s_QL?)?WfK*j$KV*Z;55>kfb_`88mLo5aU>5g?N^7`#yT~N14
ztKA*)@)#I_iz!*8P&(79XE~zOC|W5cz;Ps|vfAI{CA(A*$z^Cd?Xi)0hg`2~PvAK;
zu%q7gfGa?u?f%PJF{6(e*?*fEig4EO0uXJA2mMVb%SyXyrh{Yi!O?i%YHE#Lrw?fi
zPEtRE at REH$d!8}E0FKZ|>5P*As~!nTyNtidEkU<f+)~{h!r{9I>(pvc=ic#g8(t0T
zr(BD>B1h|6f2+JqXhHO~%&R{kkMV;YlI!k|x}@<APFBk^PYOG}EtT?+Am+{kl<Y*n
z#iZ5}(Ks{4!D+25>C3f7Yxmj5uDpduSrxuRY5#s#<zlowjNa1HX4x`=e`J&s8T`@e
zMx{*7e_l#%NxTJEL?liF7t#jqzaCJCCj9*@)k{RT{W<uA!hG_JcCV-_eauEV&5+2}
z<SWjNyMOg2UpV+Y_hVOaQ&JlK#yXCdz8U`U5lMF?t?p>6Ck<^(;=~C#X-=#}xbKP(
zhcde-6Aq at Xi5d}7T%5P2<$~IeHUf7RTWcHeL4Y#7I9tJY;k>Kbzf-^WnE9 at v#PV%O
zmo|=VC)Idpi5h$9Lb97XS8gZlFp?)H at qDzcNQjS>LT4wVtV=LT);c5+6si1r%k6zM
z1KsabS?KVztdZScxD?i~MP&cIa|^#=h+v6NQvHCnWm%Zmz_)^7t7m&#C+^f)nh7<K
zvw at 5SbgG=m0f^yE^$4nhAF*KvC1u at 1GFSXpHA8EG=hYttN$t*$msUS#0e%cQehS;W
zzWk5Pc_RNt#cXu&Pr8_!4ab%C#_~Str*b=z8VG@>pA_V2aKXKj(y!*C6Jc<yB-XV@
zRP*wXxzFN^=^G>|Yb5<Y8WcBnzUBl<QB#csUOW8_UfRn3#Z2Hd+_;qv#BQG at T#mdu
z9V$-o5WO4_^uwn6BWPouZgY?t_lAEq%3dJQ6a~BQdDz)2vmM~T8;n5eiZG(B*XG|0
z3pmYtq~}dlHVGk5^D$j4pYaUOr7-eKTspsWQX}`}fXmF_f at O0PINigTE&2`Bu=<(Y
zwvFHDXW6rH$Lcw;460!NgZ9%5j;^t!0jJ4<ZPV0e7KUf40KFclp;XfT^Fwol9TnG!
z29-rESj-=5ko@@;-DCpI)br)zpz1AJ;Xn1!Q{yus$j=K-1o<<Nzmz$q;tADsV>MNj
zl78zdcAtji!#()dpA<(nZr8?k^{74^$q?9IkSG%Yp?sTP_koQd-BXzyGsu4T{{@pC
zY~e8jiEDli&^w5Qpd?oEwnkFdr*9&qzezv<`e!Y$*;b&Z9VNu9eqUa755#T+9&9~7
zpg+K5D5;I at zo@(M*|t?SLo~*^x;B${4EpYS^yRB*pAF~f;or#rVswD}VyxHq$YwJ?
z<MV-B5*)@nfQKUu_v&rirVV at 9^!)_r1oDVn2Kij?dopX_gBz1I5IP8n8Q{FB>+J+z
zpIdN$+$_6CBTerfLpr*qjfi!0c3bR(0D`Gqp>ss+HX+lT<QgZXXrJQ>nExg6Ao%7F
zRSXFk2*<^gp at My9hBvpUSTpnO`o3Zb--VT#!_5jPm_c;DFwXnkg?S^U{q(&ujz5qe
z<cI*GUu0_kbGPDdN|DL7gL}ykq6OVZR!sqs)lLUAq!3&JTnO at N5KKo50y+B$O@;_Q
z$0FdK{!rsf-oL3iKeqwPgY at 6%X-a>S*a-oEz-}<#qFUXNcWrk=4+Kk^kJE?3 at xTO3
z5V>@+GkcFU%qEEFlkeoG?&@Jwp<Iu^9fBIXfA9S<<~ozIoFN?8nIS at ap>ND3$*q3I
z-h-iHCc`0Tbb?=b?B$l$omc?mvLgAU<>wOupufPZW+1ty6P*C0N28Kkxdn7Q(jkpL
z^g{$jNYXRL{IMvwHq+hF#~ru+00PiIYp_N?@N?+(kn(>pzfoAiDsMfflTGH$7QQw&
zj}Jt;r9V}H7a!H!{nyOiTei6dEMNdz246q0s3|}5v-P0wr1+Tmcg1{|`6NI5A2YME
zsh at FxFqc)9>z^{gQRMqCaSvK%kun?@Tvuzf1cuRT9i3rP5pxkxUOEX0M8h?p-(jnH
z1zeM%Me_aKdFkU}=#Rq{;X3Aq6!djlKmht@&3u>bAk)U6?~D56qCDihEP=_nWebTU
zwHCeY41ZvX2k;w{<qRg&aNSIH6rTw^m{4Z!cNE at CeXBf?fmoCC;}+2INOA@;_h63s
zp}hXAj*N`G26Bf|Vio*$t>n&2kx9hCyb at cITMZViKCQDS15XGwfV|7ig)mTLMyiNK
zKtE{I=)YRmAIUl$h-P&>sahNh8LsU7I;VG&BmL~?Xi9H4!3dxw0*DXp6OaHGx0{d;
zf*FK)!+7LFwd{1}k&BO6b`0kY>&8jNL}wig7<%_ at vJuL!bA_lq8^6~BQkDb`oQD;P
zs0>CPKBvziBV)e+5zr%#qMlI$Mc#lw1oUUsCC at eD2_)-~fF}ZNNB+$<@cAjRrfD4S
zOJ6vL>5m#cTn)mOag#&nGRG&Ce<x_|f&c&)Hxmb7_UK_O+*T$%emYrs_%st=+pBit
zKCr at iPk8{rX6CJGpDGAqVC)r>icZGAQG79>`AS*wGX at yQCl-P4Ff5w_zn*TJKA`9X
zrvYp9(3utBmANkcsi8k=_|O;hW?K3~!)l at L9i@+5i(M%{fB^K*8YkKfum&tP+HOwJ
z!&t8<4<y*{&OXLZQF=Noe5azfA}B*A2__MF+s;3znkf`gFzwa&X~xk6 at Bc_ZvP!3(
zk1kwv7v&mQC-+<@piTNfLx=Js`$h!l07M}82v!e^eAOo|1N*9KB<;9@{uL1vJhiV2
zdqDtPhz^C&v&i?*ffvAU%Edj9Y{Lq$9!#+wanua25JE|OHlqZ&#n0Fck_vi2_)5T4
zWk{M~zw5(3SLL+a0y+W-F|JCPY00et?Vz;0VO8 at PfYOIDDLwow>=gmTiVcV|DsGE`
z^228MKq&vD{GYoo>+Vlg6ed)jm!ENvNGb4M!ieCa at 4;slDxKODxx@`?^}Q94(ye_5
z1fYM600OfFmg&Vd#qB8q*b12am@$|_EL}vxQDOn;N&V)Wudvih%E%Zb6qS5CgxD9x
z at UK0sTX^xj<loGDHHLu%f^Nk+R at AvokktT+<$4{nUJe3S6aipf1QTP^Cnpv{nd0`~
z0>nVknL=sPD8qhza+9?Dru^j<Gl__kW(+j<>}MQzKm-KxkdTBSJ%+aF)o-*vx`y<k
zjGlFLtxM;k?d!igpH?nL at t6X-%C{kac837gH%8x!DC|R_gQ9N-h=Pv7=Bl49^<4fw
zK at fxkrz$HW<2VCr;L_uo1-6lcp!wmGbjtUYrSu1EQuf_qod8lh`#`V&`T-Bukn$5L
z#cVxh>fsmVK%R^*5y(A}eRO({&$L}->7%Q6T!EDSYzH&#J384ni~yDs1h5i)hVO-a
z=0ij`uoWoB5MZtK(Rx8|4%cj~G%J6`mkdU^==-|!yy0dlbPD>g-hTCJ*RVc-UIY-M
zxKE!uxk-jG80RGK8i_brW{l{mRHbBOd`VztA4}8|@k$UJ5rdy=1?(8>1W;7?ZGiaz
z0Tf9fYzy1@#8N={320z0HAxnJyrkA&55E<toYZ!()xLi5Ip+w+6hF5 at T!!xf#eLhM
zpRzkS-*$-aGyIPCr?!Xhy~+aiZFR2VzT&p6j*UNyNS$M=V|s0ik4cq@(W^|njnRRh
zWDQ?`TDN327VWpvdswijXIr6H+4b!ZKuH8pmQwEoF#&7`Iu04 at B$RP%x@|!bAu~!w
z#+MEPh6r<KvJW{12nnVyAh_83iXs72I*64$-X4Gpzzz0;vOstv>AFbFN$VdLR?NuA
z at RNy{??Oxr^JN$kq~ToGBlInxxIO;e3%$xg0A&$CQNg#u`dDRvPSo`~hW1tTNyHyR
z9ZVVi?!rQ{5;8KrRA2?L;ufLsOphl*kcKm<Qz=lkSbn?X?U=nFfNj7r_%)3EKOS51
z>+cmRAS2^T2K at lvUlsvOhyY|M8v!JAY0m)xR73z(Dd|>NSAHSYDYz9l&P*CT7;~M;
zuV%CR_6t;M at q4^&kdV69eFTDrxk=A6{V)OiW;^>+$Mt=md-V+4oo6 at K>Gdpob?=`6
zqF_l`|Kg302WYIWZs;0{8h;kQ?*_{vfSL%Pt{<S*`HaCf5Qre|8|Vid*VF^i2}qIz
za<4P~nW~74{RN6nQWX}ny!g0k!B~8rzFV>P!v5588T$*CE+;?W==8G94QPB|+I&J`
z_Zl$)G&+dC#|R|QFCYs(Ij*S(;=$<UMA!&}OjSh2{s6*7xk=+r>Z#|GJ_#!eU+_+z
zk*#*fC#htCj7-o62kIKDm~}SZ%uD~4WdU>uAOK~JfA1L}fVv1ErSKbI?(&8u&@Y1W
z11x}s2!LgiNUKaMl!ffzfO-GZl?BVNWXodLR$Z;7cS3Zg-V6ORWLYL<^^cc)-ul#e
zGWH&r|D+PT^P=YFEE<quKxWK#yWa8dJ;U|{zzuyK0mQ(kSt1yyDL3HFQYR8HT_G8J
z4|337cvQ7H81%(7^)7fP2pXRd!J<fji796vR5!9PW$Zgxp!U?Ailx9~5nJ9zO-L&2
zUc(c>iU`0fx<@ww)P<B%?*tIYlFXW>%p3BYU8SW_i<GT^{Rb)2f4sbC8EeTeN1zE7
zSs-<D`4Bp7XP(CG7Y&=FlHbk#gGP|FcPwf{6yVYd6M_hvPblktAWZ<>KtKY5!1RM+
zS%j|r;iId_3Lqeej;L>PU%<YD>DIr=_kT9&*N$(kZV*8HZrF}>@MLVsOww$j?LQb2
zKliX|o#W^QjU=sq=tm1g5dYp&Y)1gGkQ5PH3aR}?P;N;Nw;~dlDJ|QwMht!AmS%rJ
ziZvFxBqe*jB?6F;nfV{T8~t7q0pOxBS&NmHGCA)rLhFC;RnvU`_G-uc*ZV*@!)FY(
zrMAZiWm07~9SZ?8L;y`GdkV3V?*(XSmOp;9aL2J3zlJ&jnyR3Ty#cKZx$2p7ZUle@
zP<$@}+j%ea6R at N;{RXM?W$X>eg~2lWjKVNY9_twMzo@|bi7g4h3rDv_u(7RMfHs%u
z4O$>N1WUD5_xz1qfx8tG(w;#m8M^{YSh0lk<omX3hybv{dJ#Zf1TZ??_DjF-cfi&c
z3M^ih&^xDhLhOI3P6zo%Gyh|&Y&Y-<zCD?2LjXm at ***@yy9${PVbO at 3c5TBEo
zP`Sm~A0TX`UYnf70>IP{1hDaLc;C1HSO~0HcUHo=?-83{AW(i<eqv#Wik+)SAC^Bz
zA7uWo>qxi0Y+&PkZAL$3Hbd_J1_3NZNEP<j`9(GmZj!zLd{I4g+pmwtQb>?M4iMUV
zU;)tDjK6QWnp$|QuOh+oJ6izz3oKmZoBkME)4!~GS0jiXpbzo;*uZY|ZF?92G(`Zh
z@*@mEK*IMTK6hV?wjP>}kETd~ML}2t?T=ffJO;hT2z>yw>>GUm-S2|;&UTijqO<Vy
zy=;-~C4%z*)mazd-NLfTeS7tjYjp_uFrdc2Hv#N7Fh%JPU{s*q`e-W*-+tb3CvQZ{
zfo1F(2p*k!BgC1jo&y1dRv-{I+vx-(80gd;zcN$md>K0j2|ri at oJQ`={IU at -W<PcA
zU9!W$CIUzm+E4KC^nOwqn5Pr(+ZL|MxHSTphX{8MMp;hXuDI9l+NR)10)UJmfX*-=
zk(!x=cMs$jIVKAht7T8kwav;}mgS4wABN7w=pumbo!w?h>P7=;Z0zG0e9TmNzps0n
z2ma5p&>|yhV^t(Tj6lPLkPeef0=omDrhnWlTd>JG0Z8FP%Wp6O at IhM4NoUefo*B41
zgx-F_d@=i{WZ^=v)IY9oAY#*j4tnWH*dOav{Jn^cvT2<QFalUwUR}cvp>xO|7`_(~
z_H9*Wr|{>pO8J04geCCNy_s8a_g*(_X>dy*lBnQ}{y-$)uh&cNnOgR0Q!S5#57ONb
zHob?AP*xfr+|byPrEJfUfS(V1{_mvx|J*CP2O|ylRz5!+tS$NcwEW0>w>|{~z1RxH
zvhnfp_89TLjk0R|u>e+O0Td57ctAo3p#?;U1m4cCsPdZb^gV{8e4Idz71%jwiI at pE
zG}d(Gy02&IJ0<`G5(|LXj7Jh!mTF6#D`RVzjCNXnI$l{8oVhP7{e|*V$8o*y21Wh(
z97y*!EPxa!wB7f;1|)!w1Y^=$`eb~`oqJF<A;v6aa!ac6GkW6(DfB~GR138g)v<(;
zz!TMV0QF8V%6xUz%vA(9b)JmgKrVg46(4u;bfW2Ir2KUFnRP3fj_Z6YCEiZK`yqj#
zPx1F6r2AVFz+nLbSQcXvxke6w7jKr_m7%Ik*+uKr$|SHepwRR{GaGP;vFCy?nm<ZR
zhU)s(^SW7Fsq<u{fjlCYBvc`%0#kbl@@d$pi_HE)eGdxE0%)y>0L%mg-aiS7*arF?
zgZ;&AhEQHDiAQl;^jp{I2HV1QX`uoMsNy8BgiA7a;I at R5;gmc?wKEXa$COjzEf7lT
zJhlRO at 3d5OR53pz2LbI2^i%zPr(z^KKHGNXhU!&vYxRr_TU~p(HX!RU!gebY5N|J_
zczg%+<$#T{{`#r1U}>d802_)ND`fZ{e#hvwZEwNwppBR6VJgj4H#NKL9>_#xDlx5E
zwgmbEK|QR<G|9vhxmE<AP`?O4cz5(rkBekku00cMe?b0zxV-4j-ml8vUowLA_3P!<
z>Nu%{@wV{211lew?Nxre{aeA86Zt~`AJ#%^3+(2%_#JQWXJ7cfRoPzK>{AuF^6`^?
zfAakTi!0VIzyuc-Q((M04;5|=6dJ#D^j%v-O1)B_aXo*s5rEe+UC-UGSl~+PJQ*IO
zO#9~if~B at 2(-OHBa8;YKu9oHRoAT3eb?O*|??DN}_99aI!ZGXn0=dN7A{4iUa+|h8
z05ZwD2w)w$h+(UJy^tzj+!j#W*W>q!Di&Z`EmT)6Wc8NJ+LPBhON}L7RE7t0`<Zq5
za;jyDZUmruMUd=s<&!JbK3H;4V%2jH(AJ=Se!o$2cV5;l#JW^hovIFzPh>S#vONdy
zE43YLwJ)Ia-a&r^0D5iT3dQpAIpXc{{^B-+7uFT+H|RHJQdNS?P$5Gt=VgMCVl4Ht
zGQ7ajck)!0lL>2)0Q8$gp^rx!CfEcIrOuP#7xKI)Yl=l~-pS<0bwaV0u~MxrHx$fJ
z{GHlf{2ox;mMRl(-)dj6oFG at AePVg_!y57Udjrpc>FvdBJH^JiS5?`3(sRv};^&h~
z?#kn;`|a9by99?7$AE?O+x12FXsqcL>#HJLUzbL#0tCPiAhR+F0wOhd>O5a6kSE+C
z>*XJ+*?bA=3v1Nsu%rAN;CFFb*k0VWJMjKe+ey5W+#cP7NC5))C<53}uH7S?OVCYp
z{Z5tXIySYx2w!GZ=l(#&%k-)=K3ebV-4}Ih!RYk*S}!dG5A_3k(FcfwydF_~KV4oh
z1xIip0P4 at zBOQXD++2Cp-Ffa4f>J(pp3lKS*Xv#bIr?7mL_9wo(BxI9HdbYgev<sH
ztv5y}R$5*`QKo~Or%){4Yugs+yxYy_K3<K#2tZG<u_H!&KtJ0O`>b-dgTI;dxg&6{
zfKJ)f4j5)6dT?fOMSg6{U6M8M>s24mo_eWY8tAlQY at cCNEGFEom;fNr_o}-aPirDi
zzb-)PJYN$2E7*!X*Glfnld5|$wWK;)w%C-F)itmDK{j`cSmtA-$`-IL|Gf~(q{?-+
zcg`U>=nw!K1{vX|6F`7 at 87m*wIxzzu+{kp>-FextjxQ2oKm@$d)QkQSK#NWtuqqHF
ziNagU)v3Rhe&f$x7ID(zebIF#d?UsGL2`5EUfJDMt3Nigygs&%EPnXZY59*hr29vN
z0Q$h{C;ws~0)kq|v(E4g!!*opV_EXl3;&XERV^9e)h!8fOaM#EpKJmaom;8nz7(MR
z-(l|GShRQurbfRnty=JuDL$>f<g6%rM-`h1;21pIDkPv!TD5ZHqnnyvvG{iKurbMn
z4z4e?g`<UMJwQ at Xt=E^(Y=5$8*ykU7nFN4^L`UgQmlxIQS8Uz{i96_9V#F!P)c)h3
zuH)ee;Nz#Y6&}!(zw_AzwgnXT1#Gu}J0y<fCcCzUYixflSelnc=T<|)O@!9)Bnx2H
z+{x=$1HO~+OCth;fmj=m*=fFxJZh~^wlXcb08_^uS9sTmxe~PcC3j=EZmm9ZA|OTI
zS?cR3C1*)Q3bt8>V<hCbuj69$(u4layZmvT0J?W<AaRpj+qXj~+w1t${&-(;TMA)+
zTs{alzS^2u0|dH|ap=CR0g_}|6ro;zN-&Nqi1H)pCn?wv1`}+3R+m1yS8v<ypS$Jc
zamN+kp7)D$TzFWqM4ilqV09#ddXSqyklk`t{2qP>#M@(peQ}xixENdQ3kc_kk=h=%
z#m9O`_uD5V0BfcwTOueFNbMh7&@Z5OX?+8<d<=t;9fuz8ziyQ}tKp^v<hbGNy|O8K
zb;%33 at 61{=SBaL7D8STl#|>D2Kk2=biJBC2EQYeE2BInXKu(aClq?+%_D}bu`|T4S
zK7Cpf2e=PwJosjGZQr6?*tgYr;(g(J*dFgoZrAw@;rA9uoy$ITJZ=F!x at 2h~G7i6(
zPC`Zt at B@!C8PLKroW*<q1mKhE1Oi~>ggo`9M2M;5jst?9&wD0T<m!`}r9Z<xWX;57
zDL$QivD^gN>5{|fd%VrdrrY=(AwE9!8NSEA<83i~gVy=pLA<{g;&S#~=aKGr2%xhA
zfhZzu4`qso%k38ZoNK4oDwgNr@#|X4pKM8NV!0o at Zkl<_<PIXfjw=bARtpaS5Wb4A
zQ#V}%pcXN8+))Pa67XJ$ay<XAYUVzjp16g$hsZ-LE4^ea-kvJc>$rgJ_7@=?wPOM{
zws)6{5trYp954d-C;|wD*MR=x!uo3P-?h!@JNs<^25es!{4w3%<KJ=FsEl2i&j>xr
zt#2#bOX~dod1CnI(sSF;4nsUd!M%9XGIQ|sor-19IgTW-K>#1ECE?vc1h at dh6Rl%O
z0K`8q`a?_zlgDs@<|{JyTT*<r`VxOH7f8ywjD&3+dF#lc$x<v&wtWNI)cGFD#NSiD
zJKOA>e1`8r=TraNeQn%Zk8^Yom)-gpkpKknNj0GF{=oJB{KMGiCUpLze2n#NDzha*
zxu|^dIvr3T`qL57f1Tg)dH7ua-TBXcgYGiE64tD at 7qgf#a?HZ3Pir=LhOpS<<QA|#
zz&ZhZ^!3B at 8v#rn9|GWg@!n8;Ryw{mT(c$V{p1}Y;Pl*jezgG`ve6|c{OZWcI#T~d
z`}I%2`k(z)xphS4_|HCzi2h at LXUF<I@!dYzAJEwz5dYV;FaC}EivaXRKfmlhYCu+?
zxdkN7d^^8vNi;7#s at fzP!f1~}G-2oizy(0@`SS$e(}5p#0`O6M-p at a&_eTHD at VFG;
z#`JyfKJPh8y#JHxX99 at -Xb~`pu?QdnG7vo;ZCX at Vm?f7IyrY6N0k~sB0KA`H^`0(0
zs<|g3aEA3zeBP(;^RP$Gf1STf06qSw68uAgLFOwYA7Q3p!#WCoxmvOgrIY{;I*4t5
z^>)eDUO at 5r<C6tJo{Jcc>M)>n at LgN9EK&DfHZ0bGq%lodbSQq7 at bq6MfNlP$8T`eX
z{KlD*?<l-JTz7w~rTpp2VrS-DS||q*76|mNWgVZPHRO|-lw`7HA&b;;g9z%K`5nLL
zJ<z#H2ky(aZCiDh=ULTz%aXnIUnYP)|EQr41QJPcW+h;(vqz6I<H^=Zm=MrG1g;G8
z*_qWA-Z}(8fE2 at _L`bHN8#Dx8AD6{ie32R>IaqAD#qa+w6TlAssHKk*E;^F%q3Ka3
zhu+OjL?Io8gKP~j$Dg?n(@Y0e>lps{#xuQ<zYIYPaxMVsmysC)mTo_**?JK?4=xP>
zUc8?y&Hevn0{DzSYKvBeDYX?w3`7L1r+00rt`@0cp~XxvNeS>_0i`C5IxE!9l~=5P
zBmN`71zBxx%DwSKHdrJ;eKMp+?tSW+2+nC6(jy-qLz$k)^54$>G6C%Jk06o|LqLMk
zAz1_r9WvvPmdaK!N(l5p19SOz-P4m%)(2cQ0*n8M1|%wyX|R at 8aR4kC%zWw(#b>78
z<;Q+3AH}D|w;-M at xx4zy1h5Bx2q6kZQVoU<nMY2NQl^&Dt8PSa{&1%svog?y2i5hN
zfMEn6{Bi%Zrmx<#Y)bHVhcwDT{m|O8jsc2K;L<Ib`rH>T*Tz`B58}#yyZg%out$H?
zAfThLy|QM4N`@W!2yQ>CTkrdCR~Oy)Qbg-CJirzf;$e=1tqoXOH3cfRoG24PP_(Xe
zZjwNh<5K6_YoPSh$G1 at c&-sTHb5|hJxAX0F#ixF=xbEFwCV+kVqlH3XYid<dIu_(0
zj)0U~f8H!v>jn{|6k at MI@)L&l80PaKz*3^leTF}NvmHfyHraHiZkOEu4#)~X at qbo*
z(6M(}?i0QG-0Q6Bjrv<&@%Nnn_Wmyuz&`y^r2rxz0Vi<;3ss+xga|bj;5;SwfZ!Ec
zJ(OTStO7^|!XXI?<KwB;Km4)Xl7lX;SoUCA;{C{~Y^}Y>1=r|TJwI*|qZ32pO&g*l
zUjsfqBNg<qAe~u4_vbGYz&`&`vo_&KEf|R=SUZjtc;3vf*sL at ZlX&%0x5{Rw<04pp
z!7fJ;tOHHwAx?n+85RX)j2uGh^|sl}eu8L5XWF*RH49<bLMw&y?-b_O>pYMhA=QlE
zvycmU_K8en?ggEY#3L|6)BE`TzVhGx{bd3;;6H?#9(Vc)>a9<1uCnSTq?}|gzW=J}
zE<dSSl%eG%u)Kv>2HrYYM?%3s at TDpL?fC^;$by!9d}i4!kYdMQuRmr9;tJ4V2zjgr
zJN1420Du21(!%rbTvwjdr1VV-JBE}9vnIHT)*drIEB(R#Wdb<FKP&^kmVsOZwYu|i
z5l{*y<<J3!ve0>m;-G{~a-nmMae8kh_>l#aEVQne)L0XwLMQ13mWGAJ(s|aoZa;sN
zr at w&vVKpJ{16P99+gui|ZwgN9?yt{%aev$=_ls#yWFeV%=>OokCg+yT6~ect(=iX_
z9qwNyfJ6SH=1~AzXCnidz_h+t1`K<R%M_<4{Nd}SwdVNBbR;rVN1AhD;Q2hG-?$PG
z2bp~)=T>Yo4CKPR_np3B%3J8O+y?H2`ykkfdtlWit`}dQ`?>h2=B^LbRi at z{ihN#7
zwJhrnk$NQHV3?8nv7CEq?YTylyu<y=1Ta8<ULkzPA?7gAc_<8ugEEt<nuH}xQKmBy
zr8MX}iiRIeG#^uYaWQZ;cJpRA)?5}NrcbV1V?<-cuEX`XZny{Thha~Yow*VVDvJdX
zT6r_?buxR#&iV7-;s0d<81O&d4Aub(gd(vZB|Z5mKp0`!s=a=pK2HKx3fD<rpNL5I
z(ZW-f`-VXB-{Agb0ytuSyeMl$Q|Rp9&p*3HxLy%qpOwsiN8v9MK>o{rU+`Zhfc%&L
gzTm&LwYB#D4|BTUFswynuK)l507*qoM6N<$g4i+DzW at LL

literal 0
HcmV?d00001

diff --git a/data/icon_ivi_simple-egl.png b/data/icon_ivi_simple-egl.png
new file mode 100644
index 0000000000000000000000000000000000000000..02539503312941be368a5b69b21c57e135d4f5f5
GIT binary patch
literal 29316
zcmZU)1yCGKxGoGKXprDe0t8vyT>=CM9vp)2;tq>@fS`-J6Wrb1bz!mK7Tn$S@|{z+
z{#*4=?No11)l7H4)~`Gr`a at 9~1C0a?4h{}O=KD7lI5_yXzwmG<NN<g<W0C29J+O+j
zI9$az+5TJSy_uMT7#v)6)Q2Y{#J4`G{da9J92{ove>eP~U6C;yoFlQ!H!(Fg{o{7;
zuXtvOuZQN-3e$COzcEh`ZwOV$f7fTU9QwBgCG0cR+vQJ1m4kw_28590hO(33MzGTk
z5P={vw03dB#vCb7d0Nhel#Gm(jFr~T_RiMZRne1Oms0%jhE&4bP}%2m8DSXz8aPu`
zNj;-N;|oHh?`7lbsp5-d&yIOxRL1_%_j`}HM!`OTL83?95!%df8x;{i%k+Zx_>=H`
z-(aTw%!*BVe0gK at 34V{qO|F}b5laKAOSQq#;V_Gc?0rkG@@8^nE17GW0c4);&J%P<
zihwp-26{R8NlcvLGvwEH at N-9FcxdQKdJE|@^>kDWsUJjMRLT~PgX1|F{=@$~w2QHZ
z;~(ECZ5_8Gvs=jfc=*201uz!j#pC$R%G-_*mOqfAWn_IDTCaEI at _vQ6e6wXk$X|gd
zJc_q!-?q$q^knFkM0$z2wbr at MtJ3xBQKxb*b71;frRO1iWIHx!H&I{cWz}_*7ShkI
zh;3oFXTxLk<lWY%TNS#yLK#Uoi0UHU$>#E{4Eqx~wj&D4uE(Gc{~x)sJ^F3eEB=Sh
zthL2UmO-5t(o~%WQWPFiUXrd`LOHLtPa)u2mkdvB*t0<6>X!4&vJLY}|4LN4%9W&V
zBR9We<;5~%OX=Xrp-sDrKsW6T|G^QscwWS at ***@KWA9)i{whUAyl2ybM130{UXHhy4t
zM2L>rA4DHApyq{3 at sz)2&hz5H!fPb;v+q8c`+X?4>ZvDTcgcTnGN*slr&Moi7qeLC
zsdu at u)w)D-B6%$OC0Mwj at b1%rYtI<cXS~nU)YFwjRX_fR)CA3MgI<Abx%_mOzDh|I
zyi)SQz3~U~{|>yIgv4gh<HGv!Vzu%Ki{bg$%fv^>mJ9AY;98Xmk7m0y3B^hXW%mg3
zsHdZJf4ckNn%2td;D2KaOds>Cd7W8S&|7=^>i at SM-q*p;IGAq_q_b>E{hoP|<o*?5
z!}`DP=i4VX^6~)QXHcvBl=jFymH{_*WbTc%M1J3Y?{V>}c2(fQ-ahG4=&*BWgApn4
zs0-oD%GDDhT*|*%nat2ghmA)dt((WYe~hV&gSPJ?bNK~72i48_c8>pHb^mnZ9p5aN
zu6O(BAj$^=Ou`+3*@0O^fGop97R9j4*_Kb=%NLeNTBc>T at sA=KkR!5cq>R?y=W(q}
zCN;HcOUSZr?OU-3y4L!*viq+oPkS%>N%E5TX?<~a>YHTA2NNvmJdoJUtsSR|*3C*s
zcvgS91u2n(Z|Vl3ob`OmoINDgEFH|><eTFe_5V^G?$Hh at F(zi;cL?LFRKX|C>?)~6
z2ZTTTd=%vS6`>)ZQ(FD(#`B&gUjAbgcSN$|$i+;r at sB`{sfGP=#jj<~5ZoOV7qg#$
zmP;ARt)wvA$3DJk{_%Y49xX4YZ)NyPebRs|&NOc(sWPyXowJKaS|jV>6863w4_x;I
zX&%lBR*TN2tz}bMa>qtf&}N(9Lr#0r(}Z*XIWVv8IpLG1fk$iRn4J}z^OWL$?4oFf
z7s{D`^~F+gAtq*jTl}->{)dhCDn9ULFPR%H5^W8B@#8Ta2ahAq&}X(wwj((^D?BG)
zdA!0AxK7x7S^Z6rW8Ar#-e}*6*N5Gz>g7ZxIF$h-j$~Ki_pmzr&>qov_>hDDpT6-w
z<Xew_bW-8(1G9_!m{q at Vfv9?5L2G1pk8nEURDV*>d)#`Xxt8SErF&O?6Ve)iJFQx_
z?z;G<GR73%NO;5lk#vpf|1ZzzT1@}*aMZ8gYWqLqWAMMmXXlq4+>OCc29wjMr+H5!
z1EsGczN~H&m8SvvYgpS-2p<j1{}bYX|En8rhSdg1!P|>Nw-dc1el!h8RYj)cH)|O4
z!aOS&*1xz{2J!grjy}8 at 69?*>$Gfz{m9JI&6^t{$UI#rvy*YyITFRRhq9yQhvg==d
zM;-7bWx`CjW%c3jC*HXxRbS3RHUh^mdm-N7Ct%jra)(lnR&3hK>IC=T*hAj<aOCAR
zS at XiTyrae_9<rN1htE at -;<YW)K858<DBM?P*7FX!hvW5jr}-;$rHj^9VW<5RAltut
zZSY>c;_n*6aA1gOMeAvV!{f|jw=SrGx*O-WJf26)CugA_5AIg&qOc!-pO@<bTfZjV
zmwQG2td^=;`&!nCf9YMJLvpUm;7XXmH^-d8ck_5&-n>qDu>gACnp-Ysi`+TwZU;(V
zu$|180;F$)*B`;H&UmN4tAc9lJJt}S*UGgVFsn~J1MivFB8b=<HxN5ul;R_<!5Vcz
zUzON-cf>Pr&Vk={-Am#5s6rk_Rt6UCDXZV9 at cSI3QmCEG`P>G1HdjV1az8l024((}
zr+uvdRUVKP++p>r%11#Je`Jh58q#@nE0cQGc9+*ub1MQskKFyxPb9vgd&kXk3#UlM
zx>!9OD323qKl>I}_k2<GNc<oW`PZ(Ov!y76u>X+?yZ?7fBKlvA-9nnM(}uNeGxJtO
z<#XSDdaTTgs~LUbTQ-Ng37;T6f>*ieuxE9=O8nF^`&^+uWG5=1Q(DP=rD5=+K1OWh
zwOjIBly^XdguQ)uX~lh+G4RQ?HIlEQkZk<v?ai%c%H<eO8`vSLk93B&Pb>U9PH2W+
z)#LlTBjA!!H&*dx at QiOK?Ad3lvtIKi*e84ARgC at YbzdD}4_AD}yZlwdCbq+KII4Q!
zSzPx~c)qd%qYJxQ5ARE{>s2`RQ)J8Pz_oEB%rkCOTi3OE+)KEB0sBeVBIDj;gjLej
zYUN_V;NA at X#56km7{hSlmCbX~7H#h8Md8fTLu=PF?`b3VZ8tpQcWe|96y7F$Ot*M5
z%7Rq0x7 at Rl!UM#>h`T+gt>_|A)y(Xhe&c at KQ9L63V)6=TN~*_G<KD2jNBe!@o2&L@
z_wHRsi&5OvOZ at WTvu||8Za|M;e!U~Yo)TVpv6)o2K2pi+(k$G|e>drM*DEcx?<q!>
z8U&gfz6|$3e4n7;7W@(>mij8b|6tI>@cLma`?Uw>jFF(iIu;V+?i54%Rg}6C_(62~
znGWst^;`an(oD%~pWb=ap3hAdlUB7Pht$rbq%GVtq%F)8$>Rxu at L1IT?-N4Aq3A@*
z6GGIl*D7v5)8S;#fM=1o(|Y6xcp6tOKk0j_>(ewgI}^?zqfXQ4m$e_5FT67+uR*O3
zYeZ#FyjKA)7~!{-!=051*`4R>Yj!vo*@6_mgQc73fq70UPKC#EnOQ;0_&UUU*RFV(
zzS8-Rg0_pDxz3M*0)N-e)t<;JfBDkc-D?cb3+|8U3+;JsXk~f7WX~;=dsjY7AymC8
z`lZdRbSXPcvuvM^`S%paQkOAjuHDFOx7JGismN?9Cfs$+du&rlT|(J)-2KT5lPPN-
zJAPWRvW>Lc0bi|2ouRfYapV6jGgI8hL?V6-3g2C`zrG_)?e+y#?bx|By<jLMbsCXf
z at j8aNR?Qc*b2btUI@`|r(rqlZZn!DBwDV=<-Y9x&Mo^1Gk_DX`t=iigIBf at 4X2ZeG
z{r9Q7F%@#Ua+)@p3UhAo4v=j8fktP&OF=HU6zK%SgtThKCV$|NfilTU*y3ho6V?l3
zz{+b_ at Ixh0yst^fM&-BQ_OTxPG#c=bkjD^4_NS_*f=uoH4D_pKOu}i`qP7l+@>fjP
z71zDxPKnAFOxC}y$+{iAuIsMGgibYX3hl-$DbgRB;ja)b7}8KPokGQYd<Xg;VMP$%
zfw4=Nx$p}l_y*?I@=Tn20CQ`7BJLFPHC-N(YiNAqwJt{#!J7mk8?&yB!=P(9D0c)2
zr;SAlYa1um%mOgG^BM2(q{qhOnYE45heWvk#$?|c=F248Bq+_LIeYe%#v6NbKX;pd
zlKTgp(`=>ouPCfX%zJv*K1?GeOV at B653?ntZn))2ObtKwhiOB!sJ96Rz)5x>!wKG|
z_dWroYrIYFz5%m$7!*NvY;Ilw%8wYUwrlIV4;a5#);@BbkzOR)wo+$-^v{=56rd{)
z9^ugv>7ybiR<_dKcAKr!{Fm4DJc8|^)m9$4t&?zhWE at dQmzs<EuW|ZjKPFC<kzOe3
zUr#6Ro-(^7e4<tlZ{7BNVbR^4gVL9tPk%e<e%yQdBRyxLQX824yD%M2=ZL~|L~!d%
zsV&3kuUg9{df;ZboNK!GjcA3<?a3Q#T0D{D?#?AU8EkI8aKG3ZfHb_ve)P|wt3CzY
z%PoEZj|d42VXR}DDK20l1$q4r-)7Ve=n%&}!w>N8?CHJ2N7~dR!Z0wpxI<g(Ho(rl
z5Boe<S=HnvIn-4-q|+wBQ3%cL^)q>!f^qfh%IhA4(Ao~pAg9hJ)MGEH3E3xf{8UcJ
ztD}!?OD>40qi=9i?#amjXYYkZ;;#Wv-N(Wc;Vw4*oVCil-*kBSjTCPm`lbzhEf=K`
zBqq8+Wcg!|jrQ`6ca+e4%pm*n^<DcZp<7Bv*VZ*+#{=uxocAy7M?``~Rum0yv7%AJ
zK#V8<<==vUhV9s&5<CBPO%XnB(jSbULRoIEXJ-lf&NqZqTz+K&$-Vu at h=DeCdsgyF
z9uCYv+xtsRZtR3>vH&Tc$k8*H1NjZV?JR5($vaZIYuD|;J96?7+!m3wxqHtKPmzV2
z_e at s0w2KaYPXEV}#pyV)o7XQom=jiDJ9i*%_Y`@V`SGxyZ<;S0`w%hD$tCZpJrwt&
z75R0f2s<!?2vF|FnK94uTLGL4KmRIImBG^8Xm9HKrKukE7LRhbeZ)J-okLdeZlMVF
z1M-Bv9Rjn*ct%$^Gef6%Ab#kAvEBI&e9VHK5nm9$1i?^dd<Q1Fv#`tVAwT9|M1P(j
zF<~&G>snZHXO)Cw1nHGihj&qD>*HDGv6<5Ma&XkF&&RBMmN%b^<WWjy;jyQEXp+#B
zxt7~+NJ%-+H;my(b>>gj2E_$HV6 at OJRkWXRT~)p#Ys2ax9<EY}-P0#b@)kgOl7&<9
z63_OxFpyD%=E5v1*31e{#cJqngN1oY+rmYCzAxqB6nNwd$Ptm^KLE{8i%M~BfRL~r
ziQ2D0ZT=#rA@?A!C((hmT at X}4gm&l<RQ3=>%yS2lG8Zw;djLrRL}@K22BAd0>Hk at p
zxmfq6YHmLdnP6z|Xju(;5nWq25Gq|nCECOMM7`WAB2M^#o!R}#i0lEI_EP%p!8fq;
zR61GV6Z^~^c6a6{?2^Y2w%aHa*T<0Wf2ASHUf<G}TA8$(BpjJjg45tl8s9wRwfB6v
zbgxm8b_Z>m^{e4RE8F&0E5{x;e1r2T4X3XNgWi5}SIA9~FK`Nd$mY^MeuHONY=K^W
zlNay>*;r>7cYbhdSSTFce*JgwltEZTC+G0g^`Acex%Zo_`1JAk0)7+8=c~THbQ1SN
z*vx&XRno<6P-{e74sUZGx2qZM;{(SjM*G-g+VY#b9{(o1#*+t98w6y)A4i__gB`&F
z2g1wJ?St!Qw-ZrrSiM!ZL_lw>(?6&G2=6F<`JA%PJPMadtb&sN2}|v*QG1<vLL7ag
z=&wB?>K)QY*|$ToB7GYpQp4OP6#7W<<#D84x!*i2=n&|1rLjH9)uGPI1G<C47XmFI
zhkLyhoA at 5&s%Oq#OmpYF27^bw<l!)9e}y^J>lVf27Xj>+!*4AHW{@RkpxRuhx~^GI
z*CA8#9H6-X+WWTiQ&1AjS$}po7eN{@=rwub)&*7kAqHa{?^*3h>GguQxFNlj|HvIN
z3=X;9`Bz}$*<+NRa*MZBvM;+u#AMD9<+l!)A9D|wS72{?M4YqCg?w_0aNmE_YVioz
zTI9f at dovM%$sN{oBYC6r8<jbb*095-QuCZj4!#2hiWp7yKm(JZkkUK!)-Z!J^>@Mg
zCg$tv{?8R0&|L=VAYGbe`-JaNrQa|*Wb1YqHgzj;3fpAcHW=d6lZLYzRUK_of^pxX
zC-FR%+V&SZeKGcPv=UU!AA|bc-beUO%9>}8Hh;}Ke0d|yGmLieuS59IL`E&BCJJhk
zc+n|-kGv+zZHsu`E`E-aCefkKZ>?*5+M)_JWryE=zch!k7=1C^;-g8ssC#m_Bl=hb
zy1Isw9AugxR!=6&0|rv0VB#qDBz8y#gnff!)hOwl)F-9OC<(Pje}Kd(#pqWO at ri2+
z+v(^xB38~t`xJJHq|ixy)3zm(4L#Plb;p!p1lBmtd$@kaZBcYDwg1Am*Dp<{%L>aY
z6*SYhoTIMm?3*Td!%07A^m~~9;hf;I{0VOl+?|&r8r1E<b4Oh}lY1YiM at 4^yBN4!g
zEp&zRM=S~DL({jWQyMCTBqC5-pB7B6?|_B9`xyt-HtD;X9+kF3=zb<^Exlc^F$M?L
zCxpZ`b2zNgfP1#T9;|!M_lmXNub=p?saS>y9WuPI$MV9>H(58>U#NnT!_h-KLT>lM
z?<94<7;Z`W2O0F?IL3S&l?+1GGdAv$q<UiESbU_KlwiRDH4V8%h4)#pa>#&VhARkV
zT$+bwei3RX*Q?e91;@Q53WSAj_acxCUoE}@3ZDl9?LM`xLiD_OpBpco#$2aYxmWok
ztASa5d|4nxz>-4CPV6koxl4KOst?6RI}R7Gv&wz?+$6W_+DG7TZ#~`Vuj1zvND8ff
zjw6UOGKBU at ZC&f3gcE~$U5q#HBnI at m1P|W%<g$Du^7-|Ln#GXZ<(JXy2MCeJud}WX
zkc-x@@wbQrn9X0y<`6fo2$T8l-i4kJepfLt47+$YjihJTT_+r0X4|A5waG6#hM1NM
zi%ENAN!YyM4?otcer&m1YCa~c$Zrw>WF!k79ti7!!w#b_<fe6w6%^*~kF^AOHxKQ2
z;adMN0$bS#mdN%Mr!(3Qm-T0CTG={OUFrOv3#7bqrj}>XE|;vrvFlWp_gk9_*a(jN
z6}*lx#_Pma)AE?@2AMaR!e%auRK_<Gy;f)8#&gr$C}60&=On%qs!(^Yf%HMq3!$Bm
zORb)9Tr!W$iS^4s?QvWq5v9CW_kp`~x&f!mbN$_vb@$BBmdget`%L4;%e<oTxDq~?
z{FpX at Nn^NWlXlYGa%<_WVwx7?9hr?@^X1}d%At#JqYW>1UE{t-Ia$5l+ at VJnU#*~{
z&K$mU#E(&%h^huBAId?S_N%AyHkY&__#vS(dFDgI2?)3;FQeD_fS*fs{7;4#W>g^9
zZ6K?c?}co2bNnBvcckCsE((b==HU=H5M6ZeEE)`{%LJ)S at Jk`5Q!n0<ZMMPKSKT7r
zVBjxq>7be$GF7hK<O7dLt|Ty&$SG2?R`82ejC<3Yc1kD?FCxVzIdhorXva^(axz^A
zZsTjw6$Qcv^J<AUU>sjgm_#<mHwe8GyNYVjBZTDa at 3ey=_(nsF%uumJ<hCYizaeJQ
zES at rLdX3}oZZVw))yiM+$xW at -<~3!Rq&_fBCzz%1?=c~A3TT@?9#E>sL3?}s9N+BD
z3{<NcqqlAMhjF at Cf)A4O0r7HSrdW~}lJ^F28*OGc*FW@*YO}LXo=D&sVy0Z!M;wQs
zi7L*(-<gzDTj;sWW+5C|MrE(WKyMgZw^LB4zS;MgEJ|(HpyCs=@9J5Udd at -U{lqoF
zLW3LbOJA&F-QAj2;Eo18|Dp%#zJ)$XHT>btnomSld{iR5gZ1Rzkv`aRv$mf*oCpIr
zlr}jIxk`u&9pnTfTox^a3epF_7ZwoI!t+Sch_$=v_kHQK=1_~WTqRDX4X$44Ow+Bi
z>2K(QW9Ekz1Mf3vY1g?npA~UWy;I+BTF`oCnuZNp6j&(5?YN{8mrO$)`4x7ur|}dQ
zBrX0T4KI4+5$?{F!y@^Dzq<NVE1>~autM8OJw~YS^0`*-)9q{FuMj;A?X27XusSrN
zC0<?Qo4NP77#+E_k@|cu^ZOQ=lAv?0f5#P2qxdJ?8Er15a6(?Re|<)EPgT+AyFh=m
zOyOCI8`^7=>ibB+{)s)+_tF`_`6AUfNgkPnQ)IWC2juuGVGCd3ZN5{&-t`R&6)8;S
z+QO3wQq9{_iV?WOo8~S|-uDR89#J*M5RlAVn`TPsypC+?khVM}gY}9K?kQ4J2tJ%5
zQNr3s=%g4LH%THzq&p2=>q4<NTBbw2d$f!XJrSba4Zky;uAA}GDMR@~EpKF&O*8w1
zpTD%!#kna8hiYEP$cNIMEAYv51;!<Vlz_yZvFq$~s1ZWLA!l)cQG7DSdoly>vy98O
zzf|wU$)oVe_ at Bz)DA38=2n?&i;_~(tV^4fyQ*7x{$_0kW`eht_Tw-(f$z$t>g~<L(
zhh!neyEoAn+k7^1M-JG at _{x9#{-6xE2`13Jo<cXFB>HQv4i`Pe at m*FP?j2p`XZsCQ
z{|!Y$a#w#NkP;i!!Fy`y48xfr+;0(l-Sb9tL}tQbx)Z3hNSU7}U*F4!&?R$hy`OGV
zWYhEYPYF<B8-0GSeSiy9&oo at k#%0PhwSu!EwOy81aUKzxe~UvXX}r}L2PA`kY*9!j
zfXN#92PelxB5ijZgr=iF^1_jTZ9b9V!SgIHGH{PWkRqR={gHz>C=!=vhwop^U?{ri
zcyiTdUmyh?&mA9b5CvVgSNibFpv(=wV%R=k at xW%DCxuzT314mfV9KUTI at w<bNBqIz
zTamu0bd6yW6AG^_q_b#_VjyzBMbtlzSE7o`$Unm(K|Gg46vTsUP`)7cW1>~nsDEi*
z5WnF;6j{C?=N at +Pflr{jCJ+Q7GEg)*NF;nfG)W!BZhOZ*5KIR0za~Nz8%!p%hZwJc
z<gZ1fQqPGv(Fcdl_ at oMMh!#>oP_XcTR}yFoOF+uu0Q3KuL{5a*ho~H=V3@!y{RudV
zgYS@@qBaVc>>f`!9ks!EOz)!_iIeOU|0gaIhs-zL$U&MI+cW;GS~?UWAgi{eJP`DW
z#-&erBZ!<v<c>Zrh=K-iMz8u5$uYJ|KOIbFQt*$yRyZ=2`;H#G5*1r2BAa<Z{{fl2
zp4*S-e`bMHRutzlB-8{gS at ky<-lQj>5UXEDvAvAS9^?179ml?^japA|c(3|^?WG#E
zE_#i!vqi0i6ZMhf9OVyg<VOO}z>sQbBH<krkklt5>ppB?ZzLP#6$-9IWVAWIc+EYE
z>T^`|foGu8G&V<DB%6+JAb$(>mU$H0+A+!pHEFFPzMhS)LG8pw$r_CmWYRa=XdGW*
zW!NLTbm%*2q>F~Rnd&<~3x~Nx(q$x6gSDCBPPAFp>jvY47%UpSD<G#eA2BM6!{TK6
z$JV=v#p(EDB-KyW!0p%jrr^oR%E82<7i{OfSaEDeY;onmDL78a7VyC`mx56A(_SbC
z1?}`D+X6+f4aRy^IXoHd+BF*@OE7 at MDLMAb(wtvCMlAQJP?L}&M%PR3n99w6$-E%W
znprL*mbD1rxmf&fWCuOBj|!_|NHD<=pA#{3ZDeAO$Il|1SR10xpMMo26Q?>xujd5>
zDhdpRgd(Fx2 at VxGAcuyDe0Q1=8;B72u6rj&8_746Hxcj!@zWQRJuwvoERL1e&z#<v
z9G*jBHR#AGrJ_S^-N?h!WX69E#n2LvwafUv7d!Ksd`SCZmFRBY{O11g)<Jv4bpN{e
zXgI?4$08J=VP&)M`91n0>^Wksr-0!q`H|ViMEvXq;NMMQ87d0;nH<22$6|d<b at RhU
zMMlZ8_Zyl=fDn87Rf8};lDhk${zLvw<lxsgf$$}m%&=q|&SD2451H(9?=4)d0&?=E
zvmY4 at ***@c;p at 1heX!gI{bGc{Y<ptMM2I7R#IW{^p%84s=aDH{qQQ)|-pk
zhTr6ltwjw!Jrg<JfS{{Ut~)+Y95=XZAW^aDTTn(rRy5#|Sj1h_DDDOqyEAKY^A?x9
zHY<7W8S<$;>n`M39&HJ>_3tqSrzXo{_E{cl5eD&lHoiNioAwl47<k?yy5U>{iQX?h
zGdV6P#T@#C>D{Ob*msu0TgR1Y?{vQ<7_qRmxzpG*U9#zyf=i4)*~;Dg)33wQ>lP6r
zJnCh1{Zx?deK)=!-F4)hY<2=Ne-QCky~R$giK^Q24pdr|HtrD_ke`>9KN10gZrF{W
zA~;mH?EGGzhK(M-qpnC>o{3BapMVP7Kh+}Kun)R^;xF*t@;C<l+7&@_dZc$;8^me!
zjxV}VE|`~Yt`E5Q{l>q}r1{q!*%6j$S0uH05<hQ={(17qhLex6{EK~;p1*6`ytS1|
z^t(^Y4<kDcj-3dpZ%{$i%oQGtVfd{MfTaMdVG6E(&k2^*fWaJLqKjL@^iJecch9r2
zRf(@V6#g7HhAGv-(RIS;SuMda!=53 at ZNZaqHy_D6gB><+*?g8MHga#-EUqYMrH?4x
zw<roQ*Cc)pQJ8AoL}S+lL;Zw}A5V-jZz*<2Z=>zzd#R#?nPyM^Xw?Se%n8Rg9~u1~
zwbl4y^W3reX=LTd&TbD-xpFEG?zF_&W9eMSwem3+j>Y)8({22eN`Rz(B;M>rcrc~c
z#JbYI-rqVwc+z9_k0og9xQEV_&<E^_om?OOr`E+NqdDAY+Lax+$kJ1I1XP=1$)P<4
zT0gM>H(js^Tf^_FTa)qX!}F9|lW{u2EvQ}Cz2{j>f4Z_;?XlFnb7h~iBWxCF9U`p>
z|E=FjKXVE^U)N)DUXv{LARJ9-Eg~|eu9mEENkRTE{QCmcYsDTtu%Xv*$zeF{v(cto
zj8$}!6R^R^#;x>Ml>Z=bp0O6{t4O!QpP^;yijzJmW9~s`RGjfG&j}}Gc{sUG5lHK@
zNb<F?9Nvk8y&$fSJ>!eCODxW$jHMRc{+|rv_pTgEQ^RCnI{udo=<Tubuj06Om5MqD
zd&Z#^aX2<~qssySP3IaFBhWmL2Gb(FJ0@?{n%(nprl%k5)&=1s3xudz4+STx-$z<O
zDFn>7X$w3dFuO;5eE!+l>MYqYpUO;MB4A&9)a5LRoLYm4l;pCmy!^{d8F|1Tv+Yvw
zZ1nK6p+2(M0=X8aAWF*L?lWR?i2R}9%nYWK(!L>d3loSVKqUGn0CiLFd&s`wMKWdq
z<izlx2y;rxg$?9}Tq`axROej@!#pt5|BCGHL%!wd`or)jd#E-57=<Z|?E0f%-|)8;
zasmsv8o+umkl8ge-0dV}-IZ at wgfbGGxM>Ss!nTYXp}Yx=2?OuoE at e>Oc}`si=^SEc
zxm!)peZg7bY#BY?1E;$d9%H!TQh$!b-;{sL&35 at alM-o6`vaW?N7Rpt7#Am*>>9cK
zT(0Dn*qLn2hH_lI2pTrC<`mc4T!O}J==e%ACKiq%$qR~iS1wWtR%TAJf|D}GkhB>^
zT`$3Nhhuq?IYkvGK|t<O3QtMK{=Z`=+2r`qgiDS8Qi@<*hWoGMt^3B>iNXv?iA8N|
zbF<=(m07q&?Fx%R at s)7~6TwpahRq=YhD6(@OI<QpXVjxTa^!v9UTJ|~##e(n*SC`Y
zt;QUN>l~c1kJ`Wt52w8iDa&7*qLRfQmDauOZ5S&xJVJ7dXFsQcimNcz{CVCH)ESN2
z^l~&tMDyDOnl at l3PD;6Xkj50-d{eLiSv!(ehuX-0H>WldCk?H(`4VLVvQ#52j<LxL
zZj8a6l`=Ia1&c2xTUk)gEf4tn at t}Dv(R0;T_mxKAz<3h(7wKK?K=~~Z4C<tRS!~M4
z%}Jx|5`_p;ki+2_=i~&9DaZ!OmaMJd%A3k8`kkE_Z4=7PHS0E%XT$!~;e#9)S0&5u
zm at R48Iuo+*%eBBii4#{w&Y&7Sru8`Nxe1fgI-!}fve0;q0VP`+9~H*94V at IBjsyUE
zxqP^-$-|z8>9;x##<B$Hzj9+NE1JQ at k*92p3j`hQtvT5kSH}JU4Oxuxc=x&*@g>=O
z9mY~U9qr92ODnjB^SiOwU8+k%N?t$Y^tNkKlwvF351S9NOLK772LxQDKZ$fF{e9d&
z=#Ty+s;NWF>Sw+qZ1~tz_4|)Iv(|1so3-r+>YATK{H4E at Idwv0?ToA~KWwV}43V=m
z0s=pT;_7 at 4v!XQ7{ZI_j`5t9yv{OW2x}d*VD^<tls`cTrjCl*g#>mL<!|xYnrW*^R
z{b+(j_xdVbJI|F*%RLMVA4>l+&(P}>ksAv}ngdNj`{v+MkkNDy%)4HCzl!2{asVEC
z`;@#fRSu&n?fU9{IK!OBie`B>HC7;xC8kb{Y3EFK1Epoesxq7%a;d2F)&sf|&<Vt`
z_q#l}snhcF>83qqytw?eDeU`WeR({%g7qn=!((6MZA~4;IfrpmQ%IKNE#*1)L8&Rk
z3(%u8)15%>INU{fTYJtAK|HF4wgqh2DKs5p at yV%x%bNBbPo7$pIVi)eX~{~ecB!Rl
zMo!B0!C0A$_0vl_8SL2S^jgWAIlqaJdu8;pX1B%c&04>F{96?xMw<Gg!cM%s0#!i)
zH$ap3kHOzSO-WpdMBaaTi-BuXwC at Oc+3TuM4|`~Xwz=7<8bi;T6(A#)RF)dJATu89
zx5`J8g at Szg)Hk3Cu1u(ce9C-ZT@!7=AP+m(8n-qlb%^9|-|`u)qfOS9dvB_ixlN9}
zIc_*Yn%2SGw_;b^(O at p+e}DTJym3pBd6jc5fEg{J*CVt%=$1g6BdK9<th at bN0FMBD
zw=`F~jzRjv+WMP`C$4>|RiC#Fb<2U2P$|jz&xMfUHtZ~uh`S^%p#D at ***@T2zmzy3
z7Y<KnOh~#E)h-u at sS7nbaRfxk&RE=%8dsG>M&9<z!VMsUqdH~=H6ky{?hAE6%mRoc
z1$W`Q;y3EcUJ~t(i{HiUsU;Jo5|c>*=XS;^QODCOGefeKQYAv9#k1Tsv+XegjZz2d
z5!Py4H9mJp408D}g`MuNZ~h0{CJ#@xrDa!sHT+x<5?6y&ez{E-NFkscp3AVzy311%
zp~D2 at eLT-cwPnBhqF>RH80auNLt}k}+#PN<f!1GpP^5t|OT#A!5^WxLG+X_zVO5f3
zj^<y*s2F()=7s}zNTv~1pE+B89Zh0DN&kLb9YVSY=B=X7`$c7i&@YA&kHqz3$Eww?
zjkJi1XP)FMf|U?S(O;e_{pqg(RtOO+7+edHhqNQNa{=;EZ!T|uIKDFmZ={M3z;<9+
z#(?{OG6$i}`>oy`{;TW*DeY!?w>5>_d0ujdbDY3w4<wrk>E>dJ>mZNi!$ab>3JPxp
z;h?|Q=-TR0N|M4pqlc(<-cy)*mYyIjU09XmHAG8G>CWFnYJ0Im3R+GlFgp9gbPkud
zHuG-(T0T`nNkvu|AagCBrUtvZ^DrIw%ju~rtUY-RjVPgWjX!4o(w6y~`aqkjEVIA6
zp(SWml|&2XD5{eoa$QEE0<)A5=6>*)#i%G;ZO_Cw at ZbR)E(jH61}PsFm;F4o at 8CV9
zlkW4Jz<=y;Sy at WsC%bg=WtE$}Tzu!cLr{5a?wT%0b>muC3tl>HLXJ%B$a;-HvgZt)
z2|`;ghhYP3?0}wcSh|nXbMvj*rL0a#uMKuvJJ;yTKZE7K<RuEuMZB~BR(}LnRA4?Y
z3bd6RvZ??5*II-5dLaNEJ*bMG!LG at RoahngK|2W1`XOy>ORmiC49QTHwl*cl<v2)A
z)|Uoak`JpMCa3C3TLQ`VaSw-*e at L5JlY<9lV{p}_ZH>u4P#w^tl;*P4Mbc0@$7>yE
znO5X3cSa_3IIE=`6y217$~z(j^vE$zoUPU7s%6xrYvsswkY}rn>Ocrhq(`2cO|B}Q
zfcf|Bez}T}cqyS%z$)=d|25C<O2sjx;vPwD)f^7k2ZWc7;5?y~LUYK>bmX_}zmlSs
zN}ppNpQL+3G0n&=c$jYO2q4wZ<}9m(Td6YJM%0^=TAmk`_SZHLY^MHf)12GT)RyZC
z`{_SoS)DkGqoO-{mh)4JU<N0~V07=k9x_}^L))5ou3g^;E1 at xxVvd`(OyMX`v{1E_
zNz)yL1pYMbpNr-0NIXjZ={PXM;p at bFk6n)kDa$u^WA3M{kN;@}_)uaZ`IR}rr at ri_
z!X%<P at h9x(fsm!e#O&0bhLz`YrAc^A;;dMG1JVyOLArB_klVf#h3vzQ?^b<$2l at 5{
zyL_&FDF)WAS9149PP?_#eYbhId!;Y5Z-{}YrwO-To(a1?XVh~IeK#ed(3^FvMU8-(
ze5C6g60S5$qP9Os&krQ%_1x&i#odK1NU!SL?=@!FoZK<GM=gmO>VmMtt%#b7f|Ng4
zg^ZL^dgx<p)>ws%mKbduk<gBnQCfIl0E)Tu3TD`Zi-S_)ER%(+gUXsnY6kzZv9<)Y
z6_F4`mKaSAkq|@`8SPh*BqGjLd6{G2|KcvYsQj~77?euMJwsxtRat4&yH3JmVL4w`
z at kdg-w?VAIU5mL?W6_Rp|1#k|273kehERN-Um{&mrW>bhc>S2?xKjFbBXnCcoB6Sl
z4${wOzL`3=(a}!w8{_Y+<#KANgI$SKV>Jov!Ln^u9rRNt!p at l+Uj1*frUnR5N!wJG
zIuUExlc<KPuccrt#tkA+<K$^fop1gtpRB6Tb7YBQrV*E}KQ>cmIaQz$m#I4j?Xxtc
zQ{yxf=LUmHhskxu{MrBFebZ1S(jSYhvXm7s1$?L|SXLR61#_#z|5ba`sGU_C6R5O2
z5H4LPDlHgpPc?0{Y$z#Ns3<Z`Ye)_1tDo9kA`RqYS7~_^Q?k0wPdu?C^or!O>;nVd
zN7QOPDtGa8F2GqY-_^ne=Mq)Ju&X=6cV_*0j}+0Wm-^4w4iUe-0jbacYZz$~Zy+el
zzWRlzo8~TNPeR*;-*=~jJgsc5L3~oskaBKx>&l+|a<sWw1}>eF2_E%-lUl$3{6Pch
z;jh-K-<20rRh5KgC#Y*_sA1Q%h5gG{hcH!8<rIZYhL?nlR|1!x7zTFLu(R~~^Pmj0
zW at _vvQuxzTCEwFD`XK;yWBCdyunPXdx%w8Q68O@@aFJW8#nlp)6T%QCt)VQ?7Pd{P
zURI at 6%~2Fq(#0@)r>=acCz(+lh9rR>L7~oNQ97Sfob$Inj3<d<5qZ(Nffse~(n-kI
z2xhx(+=<u at Dx(Ij+|G?t7Ovy&-uoOG5?br+P}$BfZYNctx*rdooWzm(OlnzovUlJ!
z&W7yj)#1#0BWSFU3<(k8*=Z?NJx}|Z(UjcCE;ndybkyVMfoU=o5{P&;fF+fEW_mO)
zR*dYLnm}!JnX?gD at li%p9SxbjDOsu{HI9O!*kpg%0oEd8aa$Tx{sj3<Rhf$;SrrZj
z8HLI(!u7F`cv(|AO%5|h8h+G-EyW_^?mJmDAOnCzbvSlNHc?8ghN&#}VnS8}Nwa1|
zMW((vw*Dod?6Np-Rc%-bM5B<Iz;(#5aG*cz(kQ#Ao^Yh5HpS7F`uEMp&8&qgy&-lf
z*fts}y4!1UlE%?=ml!9kE59!N{56<}hMvaA#-p*m^5d7C9wK}_{`>OcuAk~+-%SvE
zHPzT^%KVjS at F6S}pIeIj9l{xivJAwYp3rc1)Y<r3{Q)WX@)_!4ix4!^JaslJOT-ja
zhM`Q|?zTX*ok7iL(GGvfO$Pd~iflJ0M4DU%dQ$D~uz&b!L25rt$_*8MAlAd<&)jQF
ztm}#8R{M_yp*6UvO_Y=ywifui%%KVBG0Yd28>?=R41*Kz_lbVc7{$Le9U%Mwm!w>;
zGBRgr{u7&RbX(@Z+<Y<#Fuw#(!e;Fsvd-)6_Z5t0<_i4XrK7|RCF$7s+kvdCbTxJ9
zMfuwhJzd449LEiUMBL8obeZPuFJsJfG^OblwWBE_wdpC-qbb7W>1FYbJG2RLg2m~G
z=i5vWMl)q={_w%XTCS4xsUgS2;3QS{oOJcx5p8l^#jy#;S;WNJ)yi}Xk!@=d6~)>=
z=>$=ZKarEBck~s5Tha&Pw~r`{Ykyb93Yn#3VZH_2hLCyXP at ocViJnQ*F_T1VF8WFX
z$Cb|LnI%haT`~GvgvlLmyio;XZ%qRv`hY`RGXcAy1`=|?L6wxiUXTZ=mKzCSW&(+e
z5#tiZ$MAJRw$eEY#sSpawU8?a2glUtkUTSJe1^j at b~HIlYrsF$1W%qmm#qOp0~)0#
zRvoAr;uxVG(IVCuD4F0Wkr>gk0_2YCN(J~5lX{QN8#ClCltRiMI2!gx=KnB*3U!EE
z)l80*<0ma2NhqDiIYi0d@>+gGjk##Ys~oyFi5o4gc#Y#Kb;tQ`)~x-t^>~|!Ds5 at 9
z=T=NKh7tg=L%HhNM4Xy}_<yBx#M;^;Mfmv;7Df|!3jlk6K7^HlrXxE(@JWRh#%dy~
z2$-&slNn_&87NaR9iyjVERR33$lsC&n7nMMT;R$ALRj<7y#W2}`SFo}d}}8Fqf~+l
ze@*<~UO8=C71{Fo_-nCzYZUtY$;x=zQ<VlHIg4v1lU8ZK at uG^ritNJi&k=n>(uSZa
z6JWwt^XL=TTN)nzPg_Uk`XIv(A!UC at gV1vL_-yyGz;1Gyy(L*TYeu8*a;PF{a%XF5
z;_E>;K^3f&ZhEM_ma;_3dg6B_I8y5IAM4u!_e^LYIzPpiH*jcK7>uTRaAGfHzo%%5
zTe_f5*UBdIw+1e7$_=IJi at R8&UaH6r$uSuH%flg1U@~&hMU@*&sA6gf+*YPhgD at DW
zyP^K2mMtRI=xJHUnZ;r at k}yO~dy<<!QWYPK#%UmyHJ?tJU~dW><a$H*{^$`gK~<uc
zHODH?cC=~Vq8NI*`)^G~Q#TAkH%ZxiKOhI^z~vjf&5lx{m2seuE8b>(JJIwk&?_zc
z+>T+Ot(r*Ao1OA73{_7D8p7QlsELo;T$9Yc-49`Aq;1GcMwJVbp=YA4&Q9J!?3W*7
zrnRwU-v@^c4>8el<|gy+_d^vJX<aSZKg5OuzB3iD{Yj?54FiNS7g$@fZ-c_LiM8d`
z-Po<9 at M?MLlAS60XLQ0A%vlPCJCjY<fDNf(3n%JOOc>DRAZ%e<A4<^(q|n3%e^rKx
zz;IFvN9^FS&>Ru&LaSb%e!E#O)TaLm4zuU~5qS7Q#pM}3al+D*TZ;m_p at P^*x-}B~
zYs?SvE1>cx39sV8!&cGkJ6ojcnZ?6aR`1&zp~}(3!>(-$InS5uBP3)mE(#eA4 at -_U
z=&QSzl!pO;QZ6y&@OTR(U$GZB!-i7y`<^T$x0C?D$t|idT6|?PgKztHREdLl)l at AZ
zBa at P9l6cj$Wg(0IBxio(O&T)iuos0C_)#_7;ZGjueM_qjae+|@2#3v=GXpCNLY^xm
z$?O3e6JOJWjop*l_v}I{pRu-sw`vA4i%L5Aqwn{%R;x1qcqXy$*;9_teNYxv4ly;L
z47kP1 at h$sU87UrgMBitoL;1q|`@JoT at m_&=87UfZLq|0BAsT8Wz<B0BJcr=}v5xXk
z(}nm(B0h(M1!ZXX2N?#YFD6Em#qPi5vowbw&A*`|3}37?D8XiU9CjX*?!~{E<N<kX
z#nJttznL<$hH9F`M+Wg#*c+lpio`Xd81iV_qMfPHv_;FJF=oYiFqn<OhLp at NzpXC;
z#)Hw~0&QsS@&-eh-M^2f at h$>eqUjQTlToM*ovfRb>DTHzvKss7zEzpvqG$9&2mkap
zkpa4{f54~GeV905?E=}s2k9ZA?=y9^=EAKtynFZa1InU`p9vVAG6E6Zj^5B%4?frO
z15tZ{-(JbP0d)d4A4&Lg6GV9ifT5!U{BZb(<d!18x~F%hP}a{NefX3GL}N1oHr8Cf
zdrq_=B}T)^nRf(qgg=Cu{bFSh<NFD#fL`zkn`lL0EQVuy?<}S9fAH4$1^q+h3c{;e
zQ0Yp{e)kgr&HR!%ySLSEoD%Vf1Fvc>*YA1pUFHm){ZPFhH47ry46CV?W&W1_&{NZY
z^~6s|vG at BZ9zZ}q=CJg=lgL5uebXnX*%|Kr-tG2gy<iq))b{3dOq79+$giaf;>B1c
zd$33^&o(DeLge4!WvFhFlA3}DNOKogCq+qDQUo_?m$R5FD=+_EUOOFD*W*>d3N<s;
z7pZl;98OJxEth#Ynr+ANa%TOWz67Kv!ZrZ+ObR1~PAVd!bUUipNlGTxBBg^ns<;WT
zmLad%;N4oIZz5?y+tXy}N~05A4Tw9_J4s5xN+MAh!)A?|B9B-1LhO850Vnrl8oQTu
z99d>a3rDm0u15jSK~8nT)<V|1pWjkYet(b?v)y>G{!R)lXO2jC(qpas61s}o{Z~(i
zHC-X(<+}5)lN#%?L5NA`5 at jJ)+FX^wi1ad~2u5AQ62)$H8B#nBdMXj3ErWu9?i8V;
z7vJ?$rAK0gR6bmOXC0yjiBZ(<?y}R-MWyq*L$fjl{UJhVQ<wDeV;~t>3c0vTt;A&M
z`#vEJ#Uaq&JE0QLg_a;~RLhXi0rkZ^QKGb}Ifah+#k}P(D2+dg{Kfs~Y7CSFh!WO!
z7pj15`msbwEDB{hj&2q)M4939c%I=5w at 2SQ#E^C=$zP14T}fX$@Mne}R_k&}I}&@*
z6GqX2&zG~p9qd?ETfygtP?~Jvr0nBnEgi58#^<De3e6B}sEL{cOYYn*j$WD^G*x#%
za~sDXMXo1Imo{meBmYa1MSpW1{x(PM=Opd>X5*dhSYg&A_l4#ylbu*m#w35 at X1x4u
z6(Q!NSU_{U!nlc~I7`BLvswhqL_waVezLjjQ-)k`kuHh!&J>r>+$@}<Mg2~VFn!XE
zpRT~O<HB*qs6L40Q5ft#MV%xO0Orpb-cGh+8Ps!hU!1-fh}NKNrsEK$cst+pxQ2v+
z0ydL|fAmUV?kJ?aXup}&LNgO_Xv<aVQl8FepzEu?sV0){%vBUhA_>Pn5<?ERcNan4
zJ|~+Qbes^%=w0vS-^1E5bfXHUd~`fp$Ow1^@xOQ3Vyj~gUbo>#w;DF;+ac>A1&1t0
zOQ?BcP98cEX~sz`ACS>jj2Nj%V#<tyzXQf7oh>k at 33u7R%9yo;JJAVAz02<W(6lrO
zeGSYHX1i79rkLS{yH#A=!Bg>MiFDgP*a5-nxL_^vB#E&mvRTR9AD<F>gNDdRdcpHT
zRKbZx{MH}F|JayglK<it+R5s*%_6(O82*PU5qT`=iy4f(dsasq3_2i-WCXjd(gY(U
z=A7P+V-I at ce9HfL1uWM(-E*ybJ2LQwP}N$S*0Kf%)sjW>?Hnlz8rDC<6Od+%ksrGT
z2nQ3r9fS+Lei!*uy03bi3+NFyNZdYbH>ga<u4HEr+I at 3y>c~O*7raoEH9YXVZ|$UH
zvguAwT8XfbOaU8kRpNPRtzkcf4%ASmMISE&+K$nd at u!6-EPS(tn#z0gfDUUy_0q-y
z53F%YYGia%6dc`oRFh2NG-4GVVy!vQYKNJIOvnALcXmwU1bNdC!8L#(XaO5_8qNMf
ze4a_IwI$E?@Isk9w19y!?ErP5EMly{)|%%URI@;oGFA{`o!VQoK$1Fk6K(CHRkL6*
zZkpuF<LOoFz8pUWUuli$Zh9Hdl2*7<>n at cs1}?EyY?&Wus6^4>)LdOoTRkZy7h~+Z
zMj9kjxzb>ream@(rLzp<YTnLl_|GormL-WF5q^@~OvCufWY6PT7asL){K&tY_ll-K
zFoG|NT1B8*0kR%9#rM!M{T=EZwat0vM8Hy5V=o- at d#P62Jj(Q+!<P at RUTvZ*Xpg5a
zfsbb`%6x|84>N+<8>S!|7|_j%z(}Vi#C!zk1R|Kk(C(WtVejAxzvI at H|C!OhHNsR-
zHUwO}U at Ay5WzXdc*Ot^aW*MOp6b(<m*M`D|sYC_CB~!HV#zu17qzLk-Yqdm}!|_#X
ziqg~j4`j5<LSg at vPMq1bxxSfA@(F|&gfKM(noJ4^g&+6Um^YeE636$S_%Yo)m{hL`
zhSNo8liff!LZk_#>$Qar6Z=u;m=v3h9XztfD56>0MK^N&v|M at lcJ>wYrQ7G}8eEe~
zc{@(H#`j9~{o()ONToc&N`jD{GKWDE;VJY6L*JggXj3;+&_xnMU-sqEgE@&WjA=z4
zInURUWY#m~gG3T#?4 at aY7deQlnd4%ZQy`1!GBXA81GYoP%MbD!vnCwXv~hiZQ@)gs
ze95PZo4JrLU>!9cn36YT9{*Cx7T5fNGbJfWX0=V8V0<i(jWMpjmP1>BI?iO86QDGf
zM at 18-E|XHG2+cDE(jIPbXp6GMVSqRn at Dhf1lvC;;P~)W#`NbfUDeUxNkOb!fZt}3m
ztNhKQ at ***@lOJSHiJ`_HW5>h2V>Ipd2qfjGkWls3L0Q!FUxTDU33<OEX(VgB=ebaSWi
zNm1XK7f)Cc$B&Hhu47}Q6PQW1CoKXjm)K1>;n%()Qiqc9$1^viopxgMl?1V~adhz|
zPL!ogvAbDxsx(fb>3A{d06OrHGr5W-Ah4cTzGD2dyE>AprfGBwRlrpZx at n>@o2LvC
zIE-TmF!b3~4C#X-C;iZHwz(pboT=Fl4$gp at D|C%K(<(<xq|#W<qRjN}#X$5~g`sQ_
zo`48;Vy=kcY<`Y_ at _)qESfkm(Tmc!~#788l-TGjpC}iWaKszL41!AG?gl=URdgi3b
zS-K|@-3kX^`N%qrBodvq0d~WdhU`fU^!W`3E{gpE8<RM{K-V45+k5~Dq^j<lE9GsT
zTMGn%_KBkMHofV|JL#rTm$MWnR-Kqyr%?Ch&D^8~sF$Wf%@xe95}k5*3pp#;GtM#g
z`{wdFi+M7Jt)^ruWX&v11S}Y*QmTbAAX82p;nTzV>EmsZ`%st?ov)8T_)dN;pJ2uY
z)Jc|eN?U|F1K(m_O;Mqcfj@&gZn`)lUQy3W0Aq97f-Gr#XV0ktqFBgHmC+Eh?}V;Y
z$oVBhFVX1+DZf^fErafPihnC(92+Dsh`uj$7&DG)BT&e--?o=JPMqYVuK`_O=yH$s
z`~rUcZ|@8|m02o$Wwa>LSL{8`=c+55p2(2zy=>-!zzU26QiD!aE$%+a_IiEB7~QmZ
ze=0-mq)B2VI2|${BeiwIHDIkkZ7N4ntzaQPpFGg_z=d--^<6(rO4gaAxOD2fL5h@=
zJ4tO)KD(I(3BTM_vO)ZSzdsimL7p;~Xao(v1ye at cz?)5rH_NN$5ROnUwoog~tLEX4
zXzAlRpev|$5GPTnwy+MB0UaiDHAoj!Q&UA`7+D;lDS(vhNuqS7_zV>{qkTz~?h71d
z;s<I6xH2#0H}hB`rWd*N9pyGn)JZDor}+M5F*i$d+-6A^!7q<q?%7nd>VP$*`7;|d
zeUmPWn>y0NcH|iXlnOT-81P}Z#Y9ns8{SO#oz%te$z*BvhSka*RZ$nxM$T4>AxH8i
zYMu<ajfFTXsUuB^Y6EtPCgLClRE%PI{j8DrMYVzo8Jcp21mc8Z=+78gQ*DL?nqnxU
zB26WI!joh%(}+?&J!`^-dvUyRp-N)PNSJo9+W7Z;2Id5ARn_8**pY|fVy-WFQ+$*O
zW1FfL#7VMNP7F)Zg;OF73F9%vM--VOtI=vVI;!p*^a&F1#boDl+sUpBgAv8)XY$+e
z(hP;jg^p5jBcm0?>8>){G!jVV;8B{}gUOvj-y5<wRK`(A?us%a6fv!~Ioox{DOihD
zB+OwZd^eJBKww&MF=L+$`!Mk7U8A$<Qeo#s4_AC;LADPK;%zNpPhVclmjSW&5`gZ`
zf|zBda^@@WyQ>#~E}SfWh6_MnO6mz&0R)OB_7p|p<t(a%tR at 1j-~fF#ibfj+c(gX(
zDT_sZ$2$Y$OJ$564)9DXWQ|-T(X>ZZlXX(XPp0rL2nyfIIAP`Rc~yL at zw?^`@#6|c
z?iy(LwW?a&oWK80s}`js_O!&~9mJ{3vjKi9;Hu7(CH*&qb-3amW`^I9$^apP%$^f$
zz!7O;4{kSrjO_o^c2-esZBe5>Z7D at dA-EKZyF-x>XmPg|FBaUbxEv at JBs91cm*Q?E
zK+)i?h2rkPgWjAw#{D1eeZEgSdn98gS;^Xa?z!gtzVxoO-^5v0>T49)#937FUFYG%
zYJ1w=nkilS*Tlw}#iynGVYq{~K<m9 at uAGC%%eQ+EUQT3pp*5!Hw#Kg#6WVX(O-u;g
zM26U|yk;Pjza7CVt}!R7pjJ642Y|irw>qF!<OVftQnW8p2;J9DIQ1J&!!fbgac80;
z_w^k`)A>MiM`p}%p#{)Hq3^(gzi1~O8Nf{Ols}M~t<>knn)dz0Kqx3nWj at P--jfN?
zB9O)>9#7FKkv3m3pkkxOY^Kc*p-ND6Qn0f7!e3&apjf5GoX?&%oHQ`Zrp|1w&)>o{
zz^NBM+|^})L&jWZ at qwSIWq@-?vB+PIpF<#_WKf|<Od_qJWMEoVwdkE_S}bJ1K}n&=
z=Oe!%IAH-KoJIqVU!X`Eu8g#}3S~O?w&8#EF<#U{ahuJZU;ZJ%r|*5*j><shh0^xR
zF$?2Krt?}q{+++^EjdctdCL6O64v8JboVO1N7{b5OBVV+4?!=Z6jXTzx8EFr`JlhD
z4oBY{(4aeZdqB2m48RP(B&G3=74NPa(ct at dmjEv8Cf$VbEak2Z6{4)-1l}yAt~(i`
zz%gb*7ePo4gQ6Y*3*X at YWB7@>`Q|bsy(bIbF9FEz6{C403tzhs<c3R8#ZJlG4NRm>
z8K2q+g4F+Ev?^CLpWSEV=SWDcqlaYHGH$0Z!%Q+|K4=ojzEmXMVbK(mgw$p->I^I9
z at e4p^>f-eT7$AS at 8E4g%^URcpViOW<(i3}<Zx{^_EHx6$kgHurF?p66ae7D_L&Cfy
z5W*6{<T{_;1IuBAVlpDjO^8_F2_lv%>-E+|*1&j?V%7D}O^n9ws_XccL at BSBkZ0d1
z;{BN2pUA7_x^BQ{(v;)hmf;2a=VIA?IZZ^G#!4~|zVzw15WGMp!iNPJJRWBL%`h4N
zEcKozZ~9;a5yh<seP;v!TOzeTl7)z(g$JhTM+EWZgw at bMV(gU}oeb##hD3@>nF^Cd
zGFrln at ***@y#~l|xuS*VS9<+2qJc^Ui{&$!vt*`P7hC$UXn?*^YX4*ygmXyQ0tJ_0
zuLbBQB`I7U%Gg;kYl%z1E=wQ|3W^rmTJ#wJfNff8e`B-EpFXBZK4BOlk7z-F9Tva<
z at G+O6e<ckNrOxc1LT^Y@`(2-8vaS_3!`?yQHVT{NAeb&Di`$2U{)2rPZZ?3A{r3?o
zl~!=aEr;Z6TR{FZtY`>XLtL*XqK4ONIy#`O2I4xr<=~GFzKC2dloxtIoyU<m36ofj
z>&Zgi?ZPCzNf at 7;nRD7x|Gf*t at Yn&I`inlRN+II?q4xXQ;`y^NCeuLXXG0ShA=ygk
z23w4-ECsrIBnJI8Gq08Ib3SoE<X_nD&?9U{2USxy_vZr{M5({{g6nTFCg+%V-5o<J
zo-y(kvj=A;VQ(h0ROfI8hs0w<B{NnRum;D6U<{HnYGh^n9?Zlj-DX6eqn_JaGgos<
z1mD(U2&<`@YP&rjNdU~JfB$`jjeQuYYHF?WytR+9`aORzq8s2%&)GTq50N*!NN|2K
zMiw8-sgcxkmH>c=qtYr<6^8MZ$|{^Y821?4=o8Cn5qmHP&f*ep68 at I`@w~X%6ZQ4n
z1oxGwG`lfQCkq<*5%mD|L<jJIZSxB6V?2a6B43Ze5`C^hwLj}$3c7c!dWtFoxV8|*
z9b_Pz+X&;X8oYtVu?QFLw;O5RaFZCs$tPei%R08N at Y|sp?~l+PfqM-g13?d<Mlx%{
zZv(PSGuAxn-PeQwtdNcs%z86BL#&mwfm4(liuRG#a$kTH_8S960CmsLz;pJEv<~{L
z`z<6Vdu;Jfk*xJRZzZzcI-q10$@xY}CYkzYPoO>jhJFU2`rjCD%E@)xOj7l!MDIow
zXz^Dqpd%7l9~W2bZUk)2-&hbA%X%P0Qj=4R<*p&Au^~IDOj*|7)<p@)$Jjc&jW3`(
zF??C>;oioVkvl?;K<DP(^CEkouF-l+X=?w%Z}cQ%aSuY*QN%?)t`lQ^iIzrrQtuDB
z+AK$cPY+yod3x3^m8hjh`_|6QsULZI%mP8sT*O8-2!N<A-XM1sfu6E#kYCDBYu>Gs
zw~9ku<9Z3_2oXIru8dC63?)oZwv3I`MmFdk)p}|R2&#Xu-d_p<AMcB}acuOLMS{(I
zsKbWV^=bv7h05!CI^^=GE)n*#^`FDB;L9ZuyV`ZV_Z-kmfsJ`y38?DS`aF;cnp_~#
z$kbN at Hm9a>bp;A at L;r#|=E+D9fc$lDejv1)VcpwTk9tgRLj)uU-5GI(uhJr-L9UrJ
zL<kOJSEF$R@^)2ZdA!F}p9ZlwC{l at Ey8tX!IQ}vG at Btmh65)E5TT~ylb_`wW8LdEM
z-I+*_GHSfxgwbmadf}OIy?0xB{$o8vr{<g=ip^`XBAGT9^ulSQEjM9$^sjsQZwK`9
zt`YoB&YT-wy+kV%${+nW6PghGg+j?ChUSWk)I%|SdR9U`@hza_!#{f46%eK>_T>9P
zJ<^IuOILl)UZ$EvVuV(sNHR&ZdC72GAv;g9(7AcZ2-GsbiW9%i+%}VNXuDpoQ6;wU
zs}koT3t}?sjk2{rXKNp#*2{?VE+6dU=D`_3Z!XHupA7B>`v@~817`KqUiO}uOL1EJ
zgMAjnlh38ieMa64QN68!m&9&GF(-Q&fm at D=hAh9(b4BYa9p?_W{TI^{&ARWgIudl8
zwUJNHnY#puhj*rc$4#O-Pkr&Ejbl4^jPL at j!C3x$;ki6LrU9UEGX$6%se-qrj^N#Q
z!P9&NCcl%xtGP3eT%?h{2lJ`yN4_iJ3Qu(8Q?ZAb`MTo?yzk}plg87(<Qx7%Cheq(
zhpU6AcKM7KM#9Hw{I+{?l3XdJuiD=gk0gw*+<?4$|0Un_W?!|F6W*mhpF=85cTpOj
zpn6=cr2*cembr~`R4!NxFRm9+EzTVtP{Rl06Au5T$w&Q`q<d<O4=6w%zR_*&y-eAS
zD-HJM;|;G1<jXvVtj)aRgF8j8#e>3!zJa|LCBp6Z(Y615E?+F|iQnzT`?0#8phNz+
z-|@3{^>gc*_dv>-yNTvDs at N+#!Cy^zNPhv!s_2PSZkdfcCBa7?d2k>b<q+-!Ms^JI
zMT<>WRxI<njUY^2R$yC05KJHgxbqeST*(Ny>Iy={^A(o~N2ZS^3Y=n at +eFi2R3|K)
zVyx7p1x3G344Y7mgzVdp>d0z0^QSXyO(b$gTj?tbZYk&K>yxX_blH at W$<%oU3Vs!x
z5FCbBfvp5H`15Sl;?P-I!Np>^ItJ17ACQT|bn=lb><Qpos*&KD32I8fh&F73IyQ29
zq1q-3H+I{?MUY1?&u4&oWax1MzD_mrQd^L$Ezf64Aic?B!e~bBywXtcq%05BLZ9x1
ziI}Q~8 at TaU9&^2z6;u!pbnsn_3 at i=5l%Bl|5THnj%hL=b4?DQiw5gQO4Pe2E<Iwar
zhIZY^5ieKCu6co?{&m;H_yOti6^r_=t%)Z|*xPTNPyUrNYC=Ab++8Fpl_j6NLo({7
zO_T8uYVKxDto<iHwNWCfewNkB0b;JBO`I01Y2h4czI at BNJtqh2V2%oz(IoyXrwONz
znyh6VRLa-Wq?WbRBre0v(@UV0J-TO|9g8-X_9Tu?(-a(uG9QXzHJHkq2XRGRv1xj!
zLCw8B68mlB&r5=$SipHAK;|fh{Cp8%_9$z4IahOU;^L2aB95`^DjLK)&+|l1$a?LU
zHQ{D4>$TRzy1+bdd8*#8s>CO)a>(4taAm=i`*@~nt;gTLn(%(s2>o+cbcN~nZ{lBy
zfEn?89-mM^!WpE6tl?5P;_lUkhCdNxzguCNRwmDfC%$uzexid0vR0uGZWPtCbE$A|
z63cj+q!6AJ%XrhP5Z?A?AaaKRTk@@~{XZ}n2^z%<ZCH#rx#AK4rm{pfP#^(glps}9
zl4mS&gsH5M4h$zNSUE!(?X?Rkp2?u=lNo&u==Jpg19|%jq*YNCwz7;v$?~=S`ivyX
z4EhZs@%yr{Y0emnFUJ4p^%=GF3qbMs<TRK=##=>0J4PBd7%-W5AWIQ;m_a at OaD`D*
zlMQH3z<@L)|9vKEg1Ai-Aq>vT8Bg|&K~!8YUiUeJ&x~aJTmXHGAY*(J9t>U)xA|vP
zVR=gCELbd_;4{oWFLE>BNMxYRV>7}?-qk_f=kRg4awa7mjT~yuAh*6KdA8Jv?grBZ
zVhMS4 at 8e(E1ik&XK85v(RyOC+2jloeHm8*|cxMI+z8v-Y!V06Ei~+0pO)$zIBRPcu
z%ZDvwe2OsiM-1J43l at Dg#B_K9s}Dr-;V>7AnL3hg4T(i`E%zPH5mF+~pzxRQ!|fFo
zf1}*@1?tXBRl?!F<R6>@FmPvOHL8U}x`YThOQLctEHNy%2oqCet7{oUN|^}D*<wr`
zKVTe?%4lR$b at sIoI-~<WxLaWu3eeAIz3qffV|l8 at n(De?_yHKaf$u_I0O&=CsXDd6
z3?gF8A=dN^-rT^D1T(_S*RiXG-?5AvWn7l2JH!6P;=YwTEn*94g3~weQ*;V_!8mD=
zKXw0#L0dw9^NFzY)i<zSYo)Q9dMn-6hm&3jWX`hgb#o;;ABoc{HTWn^cy^VzG7;2t
zxpZ*83kD4pvNijY1`qLcxjrybHxYDCw9`Tnt!w0!;b1rs^m at ***@79w816B7$4!w
zo%vm04KIi<6IR>>5g{DiweE(1NY#d6E`78(ERRwm30DyUJ|-gCo)H2S0-5z!E>`tn
z2@{lR+sQ7q8C?Umc-Dc^BB-xxoCZ{C6X`BdWnF9)c-E*W7adN5;#$GX(sh?v;;=eT
zO_8stHNjzmVm_A4qC=NPi}0y*Lbb&hmp at Zodzqx8$82kd8PubXifh!71Uut5F3_G(
zcTTZPYxxLwdiqRlhHf8MZxQQ{U82_bJ2N>h#<+Mp_#H0Xei81y<fEUZMNWJ}7eUBw
z)HqkBx=}YOOj#tmMdsAEpLjsxNOx)HZrSI>_ZF6)L44^SI&h>>`sDlS-Q)hmeX9gr
z<0b^%2L|NQ%dfk4+{hnOx_CR at _KoA3>6u`I=NEY8;N)^QxMnfFpqQT<W-$TGF|O(n
zgkB;s5cP1_jSRWsU6;ZFKyDvwrgDM>-iGp8IpQ*uF~ziGbf-44#lZ2+IE`rK%pA$1
z?Ys1TiN#nZnI-CmYHGff+p6W&;la<hawTsFGb=YC?+b_X3XkA|&zE=&YP;rzIbvu8
zx_49G_JK>x4i&M%CR*g`jN!=59^Ti8FyuuuZx#hrAMz(}7A;91?wT1~gg&OOyUV+m
zvM(&x4DR%LBR+^cC7{dOPl0?6-ql=5P#3TsfrK%~sLz=B7vXK_escgfO~m`LyPuF(
z>vXZYJG0tW^j)S9vbJN%UJhw21rkQxA#!&E-$w2D<&v-9_j(8suQYwcZYGXGnX at L(
zeZ&UQD(w#ChPDwa_3UZTtB3P%w`iDWVKZIXumZAhnAS{LA+J6v1_IGkqL1iRrNoOL
zxfb;i{C?;wZDV-+6t$9*HY=`hxRwU3(!?)~<Z}GN0<px}&$)?Jc$StvtYw2AOSrKu
zkK#3ENy4;D-VFA=%oW at UpUead&Wh$bWYZ}5$+3!0Nuv+_-#hpKMH62 at a;a6Ywo0&b
zsblfC(o!|Dr~rcl{b+1t=$V!tD^EnY8%QK^jx*OtFv5+EF0sj9y2TD>>kF9m#3%gB
z{R=B?Ys49DlSW_(&K9mLYxY7rkwfXv<R!y2KQw&om|=}f%N6zYXY3mzNrDgO`dEL|
zKc3$3VsziV!)tjPaxMPu#u)qE>d2drWvtFy1FUyD(&T~Mp)l)@k=}fv6U84RL4;k+
z*3#rboS`=i?^MKyyEa**Q)?wdOZ=o27D>8dM&DR{4gJ1A`q9%K>%1}ady{DBecu~W
zq0s7P?$Gr=Z<J<3HFQY2q6Xiv>xOE4Chba(e`6Od{nL>8V|U&g%5&-YOtP+IpLg|E
z5#z}e9}(qm#H>TBIk-aGw58`InL=4uB3x{=u;kaJMT9}2)`&0{da+RLd}(h!`cMG|
zX_5E9(DQfi;8yr+u{m#+ at vzpSoUu;4BU}O$uuiBx-i$MZs at K2sFT!4PpL-K{WG+oH
z$N?*f_v3JP{*O&y^1|YnizLHd^TA3aYQ;b^z_#~DSEs(CKJPA!<N=`r4|M9iXeU|m
zs<<&}Fb^Dx+EV4{B&!HDt|q#QN{URWkZHHD9Jb})W2uM<8XXL^u22EmF(KJF23}RD
zNSHERx^nFKm0JL<nB0q#M8(TD9qRal%936hmJ<u=v;DELRBTI%7vmV3HDIf1tgRhX
zno;7I+0vQiuG7*rFARhv#mefW<CHt-n_3?Db1b@*AEtsWt&5Tn{N;y=O=sSvNiVc3
zs8t%zKIJ9l11f;xorCTh6`3(LZoV-|DfAU^YO}2*UJkO46-IcCXGOh(hE^Q94;AnO
z`>lY4q-;NZl%DeznHWdMv;it9BZ=p;PGDIz&6f!6jv^hmILkm0w-?Rop>QGW-jniX
zf5*<t_oRX*dgS*lFXK$~PVaj{kkYuzCx)kOPVZJ}a6jmB>hTz2`E+-k&T+;7oz132
zar4LYB0-Mmhy!;+T`yA7>D^jt*nm8zil~Lzp9Ip$E5p>9xvugrr2OJs7EOk!O at BWc
zmxbMPks7|J)|j@*ZSMTI=ZkCEK&n$-qoHq^TRPd5PC{xo#97YMFs|W{ThotD7?L(_
z8rqE1RR?5+T{+<XNF((esjc=34|}jB&C0Y|8z;t<XEqc`HeK_EhXFRY8Zk}RJnF*)
z^0_jpEZ6Q8aI5f}PURxQhIDXsLpb38)3sk!Vb^V3{x<cekm4{CZ at nA;>M$Nb(!dS7
zHG4AL4)+?N*m1>pKhE=Rbo?Fg5%~%?%6XVI$Xf0piDIN`1n)74B5rJ$9K<KEDJ=k^
zO-1^RsjLbKNUsP3?vvBZQifx^|Ek=SS<##D0lv<vTtr*-{on^&!_y#$5f$G)mB}e9
zt=Acf5;j)104u9w0Rg|Jv~tAo at DXpqq7}1qMp_t`6{(|eop(Z7A=L<H+50;GA8ApP
z0%fHmpQ`w^wau*lx(Qqk4LcawSxuP>WRRuV>f2ZuW~DV63DCHY0Fy1Pt{nvKtkQkV
zf2DmZv3gyc>LWHVERZlvoo%y?5)mlwOY`CTGrYiBcSN#0T()LqOl!71$t&ReGQ-F3
zXPSMm)$+N(d2n1BK}0I5$8=kOK%j%tVSA2Jz@%j4Ud?u!DlAQsmGggwsB0^O&ghXm
za{oH`XAo87T}tq7JC at ATkQ5w*-*cf!*DguW^VB9ae1d7-LTTe?kHvT~BGtu>N#y$O
zd;fWGjF0H|8lIO#cOU5hYMAk-Ms$!djCg;+?<MLl<9%7bU%Uvm0KQe&&XU?b#IZOY
zm2&gKs5SMYdujNB&Ed7hK#`P^Fs7Cct%A=NI*vI^tp?`rLZ5 at ***@u9o440hne
zwwQ{SO2>V%VDP5@>Sgd at KfcAzl9cBNwuQPCU7R(B8=b^=>5^cekkI%1fnZ<)dA~b$
zaAxM4e%zX1xS;U&6a<DFi2pk-VXzS%Zhb)ft1}%1I$f?{xc%!*i6^PRW2%1nA}P=%
z&SuK3RQveLvqC?*j?b^o{65nKd0=l+rO*vXB%{{Q)hp}Fbi=(03%!lUeO*QlWOu#b
zn&pX=AF9<}JMNj$m+LhQqleEwmgkf$%>VxRK0(9(Aa1BBu=%l*psDI%{IQQ9&g5<l
z)k526a<leOLmNnYOL)^x`{Cr)tZg4r%@K&#aVS4e6(|GWM(myk%4DB2Y{$@UsNWF=
z4aO<5+^61`(`rL+`HmuKZ6h91kp;AMS9h?Mxwyl>ftwz;d>wz|?u8{u8*Vl0d*jxb
zC6%Zi^p;l<QDTzp_78erHsnX_B<(mJej2XHce_baDnHn;UxAfjv=!0!Hbd9>0qwLu
zL<0{;ufWblw0G7h<R+fv>td9vMLMl~@eT6OLQ+lTY~vH0wit2e%G?*{J`tEndxWqj
z41^PIBevE8jVQJepUY at ZFj2_B99r626tbp?wuAQ;*-}i~ado=!-axY5^L&G#GSL6P
zTzYMcDnCI_cV*nNs<84~{+F2fl`pUPM(alpy#P}*p6Kp^FF>z)Y;cL*v(|?@OgeXG
zy}FvLXF*7_aW4?-)8 at BZDq6vgbF))j&~C>?=YcK=4>kNMTiyTkssGjaD-d4WvGl1p
z2+waZg3uYodlpZSZ+!i3|1)i0`+9eC9jK>mx4VbTKlK7mpoj=i5Z#vEp8}~!9(E72
z1f*Vu66nX>@p{D(oWDJPSJfR6ChpI=wB5Z<N}KF-WwyXfJNW)aqh>kca|5Uma}^D(
z1Wi|-nFWLqPz?sm*AGXGC<oZ+A9go>r1j*y$YmIdKy0I`tt$!QtWl>uoU~b)d);e$
zAmESv?iylRC=2TJo{`o#b+<d(6_iP{)6D at ***@D>`3n3G4j*cK2t$DXbonStPd!|uym
zkiY5G8bc5*2#H*)dk4B79E#w%1o;ciN37WT-^d+xXD5RE-}gs!;GLSG0doTqDJ_1O
z(@Nx)$5}}u_NWCD71nlv+}i}~CdqV{r#9 at r&Z^#zeW6HPK#@uM>BF?lZv^wO<a;xp
zF_}{#K(4N8XqzSdeLSQ;nz_%2m+uM=nNLww at g9)rvIRg`R2e0$&G!YEC!y&IL4!TR
z-<YjvdHHr+0iu4Yo5%b$rp1sDPk`*AD(8Y-UcrKlegcGqO0~TFeU04@$bJL!tWJhr
z)1b_Q5`aoK)rMVQ!pPkGfC#V{tx`{xI^XiUr_u=E=dJ<-A$o!rm|u?yB0v3t<l8c5
zrP-~wSO8c6s+nrM$Vm(U4<cPea<(UokC|I8y_wi)y at ***@E3ImTD~!zQ?HL<k2EFD*
zmQ+DZ(pCJ;1d&wgfR358o3>Vn<gc`wguxy!96%5%t)gAXp6S|X`xt%kkg!k%O8~}H
ztyd+fTv03xl|jOJsC>dB+8A$t$DY$9*t-tl^@kS14ij?h`yPey2)XhTDr}#*{!_1*
z7`Qp(x++8d3NO(^I?T0-k|JnS;husa!B~(Vl?Y>FiBSodRrtflAOIyF5V2r9S7cbY
ziydCHw|L}cK>d&-{YtLCWL3~Sqp(NHF!Y{Ef5OJX@*AvFjKSV6cDj;JOV_f%tPs{m
zA}7rAzP4~$!M+C8*efSSO0hTmzSh1S)^;9qI3|2%Q3R8wkb at 5Mx^a&5*J;OQrkZa~
zTQKmb at w+iE_qQPBjA^Vl8*K8AF8}st5Xx1?2%e3)Fr0*w`>fb)cGEFrV^E^PvSDLw
zvG=}_uqr&c_AB1AR~0ZxyO{fhnSRL at ***@0<6BRrv4o2BFBlJ+L13qgrp>4x=_o$2 at r
z9_y32)WeTw*UtEOkKdj>oZxu}SpL2!e3orOae6l_wOWiB9%w;#^WsJKvH<UTdhlrz
ze#|ciy8ZaznkuTufElSJ(HDR*N(KJ`sYzVSBA~M=8ml~&&BuFg`=XA3s^53=_Yw=<
z=CQ!{rp4b~2t49r!D{b_;KD_`#71(xWrrN|gy2DZOr5It8g-+;e^I_T(50H!ur<{V
z3*O$sG*H5KFtjs8n7<Im#RoQy|2_u3xO2k?^3DBD(8qi|CVYCK@?uQoy^DW(@J=zg
z_q&1L$`H&^H9;5d(cfh?n8vjBt6GV{L-}}c8mHAiST9cS1x`Oy2gij|-UyEWwhqJ$
z+ybvECj?i)@$S`}R|&r1`yV*1iZ=vzu;Sl4eh&_MNDIFGBR0^M(jw0IMEYBkaZ3CU
zjcn~Wa7DGgoeP at ***@46K2F-3D<t4I$#=-Xnao5flH-Wh<tL_pXI>x~dGV1*izTq8J
z)|+1?@|PzBZlkhxhkX0ma#@arB#=9ojG0pcsF*A^p8YgmCG|hp5(3bJw67}avxE{0
z5f{ULT4VPQzGv6_`t{1{n#Eb`o)S!pmx&Gg`V)D at ***@t<b?rLp-IVC6
z0bgO=eOvw9;s%wmD<X-bUSF~3i$j9~Yv=Z?hx1FIsQOs0gM at tT1$9Q@&JCUf%j897
zdg)Fto9|+AeU>}6?<nHHhf8gYYU9EPI_qv(pXDXD*8<WSyX(I6C(qjflx3M<?4f{C
zV`S~Vfg2S&_W4<o-utNhh%8Bh*>kektRT;sb1yQ9Cy)Zq`+xmZnu73IBM+UiyD~y}
zNjpTB%obf1S+-yQ!0O!ICEJDym*kVX#&{q8bgjqsC?-3D?961$3Ls}}Ss!zyQB`8o
zK~rmwx-`E|Ja#)~%x>fm-&gidQA!ajRbMe4l at Q}&9vDHT;CXp5IsY7ndkGrYoQF(X
z1^CcVtnbSt;q|Z4WL-pot_S0f8Q57KbXr at iNU{pN?Ji~|na^-wOXE&(&@b_m;RKro
z_j*sS-Vm{l at ZdZe*Zfli_9=r#k<ye2ALz9y%8y{u9PEFcu9~XJl|vNGhzVCsPH5%k
ze{F#_YSGXre+4$`A&zCmuDGU=GFi}XEn=_7W{@7qP;09LZ>J*YPVs?AQt3u7F^zSC
z2b^CKQ3m)5e_OmUDMI5MJA?F0gxbTzmT~8home!q_)|#RYUo(_{>|qcsL9>l&7eHu
zBz*U#FK5HB4SM1s_PAfU;cQ3qR630$2!pyqrt~_T0#fYVUMxzmw7-20b+1v)lqMIa
zhwkBr7~`;2Oy7q;&Z0bOAlq6ZQ;|ns{2PUS-E;kWlk3&PHxT>$E<{9*-MAVX)$3lP
zh9e&<V(b7ID|GmnDdp_Yv|W~NulW>B#{HBld+BVj^jO*ZklnERs2KgIZUBG$*?Zx~
z)!s3){!~bMPG-Q_F->$<k~|()ANpXV+;e9j*HLCU{JEmynGGaBdnh#8fQZ{h5m?29
zvgFb>nT)>;Nxn!h;Ln<hN0ldw$~SBR3z at FJC%=4EPYkRqbcsu5YOPN^oUV0<NIr8k
z&~cj4nkjD(;^4A>Z&zYJKB-Y`xnaPSQQ9D=YrF7EYpBtUOFY?jK|jxOj)=<-rvYf3
zv-SHqSA<&wFe!g)mzrzL%Fc&ddT79di>JWO$F?*%C7~fxecJ8ahoN3<gXNf+Ka~F_
zmx1fy;s!%^ga(0ci?;GLxU$1-P=&HXXv(I^tv#xuDtRTN{(eGvDEq?TQL%U{`)|Yj
zU)7<GlKT6I=;R>R^Sqj(tE;cow5{Dp18iYL%{=oJw#Yd)m<`R)$6-_TLSdj;@t<N$
z-Rl>3&rMz|!%j7Okko~v`WA+N>!AZxMSQy*f~-%{-}YC8njgwAk5&Y|?`6O3WDAjZ
z%&b1V!VfgD$GV9P&oQyD4y-hr=Mltv((CRg5Q_0N>E1n{%v+gw<1X8MGeo(*GS0gv
zgr6{GpX#R8T`xd6sb-(*s?=Q$psdZB`5y2|dXy0VoWQ<6NUJ;VfimjKj&->rw_dyZ
z%oCrZ(f+5yOto)xxR5HP9hFeI^Z0nRu{5|Myhw<$v3z#ipv3GB2mfeD$RpWq{!6);
zGc5ceS`e64wRY-{FYhKuJu-XhkQ@%E6U<D{UGqo}7nl;v%*b22x4^GbojjF;hYxKC
z89^pa)#}3!@`d1%O5G6*LjFLbZk}-4o2AmVxet_qfSfgZN&KMG+0zQm?raI6`(Ekp
zm3qp at 8P)ENGQs- at t?nTF+A5fppS%9trSB5Y at l{~Q+?XQ4bq?d`eaK%=YExPTiQT^w
zOlf!|i>0n89<FbXDU at 45rLGTNLg_)D1#V2Hcb`i8PJg7o3)0#+kEMKCDZ##18X4!A
z!FW<q-L<wuv-qqw<?ZAGa+vpjrPrMNq_}QOZ*H1affra!9 at xbje@-}yN}sN?E9&@Z
zwT)|MC0WIM(45|am>%{sP+iuxBYpcx`zAEK_imc=Z@$$6*ltjK`cr+0euJv&*XZ>0
z5j(s0CHfs7M#3-cgl9?@jPi>L4MrM2+x=mm_DC%AaY##-P at Xw7EZ>HF6naHg>cg%+
zGIc&pol&;!ot(a7UFKs}lulM$CYn*YokT2D#a!YO5TC9Ln1PcNZy&kZEmM?j`zEFn
z$d#aM3ewf(exf)(jZ}rq_=|oT(G9i>+^O28q7 at 3F%-a_Kmfo>Hb3bG%^i-;Oeo|@o
zs9mxhgs*jO()d1jduAqn?qiWNS}x$y!)F@=?!B71KYY^4y>TWfeUc8lrDb1wQVlyc
z`Q-ihIc!d{g!e%)?1c6+#=UVEs)?PmLzD0<ENa}O6zlGj><xmQKB&@s*pI!>SewxA
zb8jdIJJIqdn75|v*-H}bu`&feec4-OcEcAMe0K#=qGKifK60|hnk2YcTAD5zvJ=lp
zl;7%V*6PYGaFcL&mg==g%g%U`%ou(ychsqIN{G6RWfz_;o3B at sJvSgREc@(GrBwqi
zjQYXx>5yH!rb(uEL-`XmtCnlERIfJfC+d;UNEK+*&h}3cQA11nf7p$cbdhf9QRmv9
zjTCfT`80bou-PkBG+c#rdK+rkm#OmCcVO(G*SbjC)F_ki(i?i2UT04BKzkkJ-9IEj
z7oU+V2~k03T1Z`WlBYavr1LTRW3CP|=;x>VrjNZ(mjWb)r8>&SxM}UK)-PN#qmLw3
zQ{j>te?KA0ceeRYgA$wXvz3gVlp%{jtP_u|L~$J)eD`%k8<K3u$2y`8=Om2B4~pY+
zN}MKa*r<m1wQLRw6fP5CHY>$LZv5_bQV+b$;$B>7y^1yMq9}gAnKkV!J>Is8T~WN)
zqK|@!qBzMSODjI$;{e<`X;`w9 at ***@M|lvCi{5kDEAlzgI7o2RX484+J9%w%tn
zH0`9RHCIrOtEmY77GEUBWN4REU#U5%Q&^C%rMQE`)SAMvpj&DYR1^OqI*Hn#U{j$z
zKL0!kD6T#LabPOuPs$wCaI*@JcehnC{!z5qz^1gETE01=s8rd*;bRSt_W~!vX)89n
zCzL=Cjk9Q&5{R~PbMBo|do3$UOksfbd6NG@@#fgF(&NC-&1`(7$K%}1l?J89Zq<RH
z7Iu{6m&E%qDJI1BaAA9;+F5%4MOFs>>f4Rx{`}!Hnk2lNAQHUW4ieU<rstPWTC0!Q
zIG9h;!H*^+-Vdss-#b`OQEI_YO*q3VtmL=iFK4TW@$R%bBTd-IQE4HX+3b<G3Z3%=
z#4)XvbjRr-5N8ercsbo3{!49RUEZURki9C_R3DwraxxN&wj9&ra~!ugj(+hX)3qra
z90CqKe~r#b7GloD;vD~`kSGN4r{ho6z7ZkmjySUota>ZurrpdhGlW at fjH_}ie}p&+
z;dqwoRM%;Bf=O^ZQ#j_ER5}65B-BRbt1h`A#boRv$;GSQl_5Jj?B4H`JEQA}Gk=t<
zChg&Ht7xCz62Ek2WNXg+xq1Y_sqAHI2B~$v0+aX?7p_ie;((}1R&^PO{Y6zeb#-2L
zP?fGy)rB}ekofQ9ukuI}-;XGFcI=bfgR4WHJakVxrg0vdv^t+86gr>8r8;K^l?LqT
zr~J^BYj-2RXwzujN0KUL^aAZ0B*t|XUpQLcRF#K5OxpSVtcbbo8QhI4mw8yS^Q*4t
zfm@>)!W^!;6+In}mXn4$L at V`w-nwvTa~q`jb}H at ra7>Nqry*;TVp7V7L5 at rZiAkbk
z=mdP1-CccC{B=yyOZf_7>YCc!>ZH7HI>|sY%e}y|BkdKXg|{4At>vFQ3>>rXbxJ+;
z^#58}jtFx!7*<R>*3<^pC55Z%2s_o+mUIqoU+OfL*VTTlNIJ4FudisFY#$sPP11R5
zXx7k%ueYFWwS^=qJBs~17|f*ennd5n4wh7WUO{bWx|N2~fsWPvS;i~R%mg<Gy(+5^
z)pH!_930xyG5l8jXZcMzJlTB9yf#T$QO7W$+RZXAsfk6;hh=oIb)y_k2HyH+!$B*j
zj}n<2EGE<e;WnM2usBRY4N&|&gU;oR>1Ab1RRiCC$GH+LM+*feV$#ul{@tzS2$mRH
z)LqV58igj6H_OT{ay3?2Y;mzS{k2N^p+jh>tHosgb;z-_X~|0UT-8oE+UD25AH!*<
zUn9Td7AL|VyuZbAlmO<d<1alab+nu}`f47T at r8xw^?CA+nW<jRR#+rR9dXT87AWRe
zF=aSUI9QK3Hhx+uvTS(qxoP2-9aDuTyK|jmVOyWC;R975QNeLo1nk+>lY&IKBr{a@
zVOrsf3q at K4eu>{A>{Z^gc~{Ou#7Dagv_c6N?f2N|eixRnmWnG{aIfXbhW3HrYO!!K
zFt}$>;jey>EnUsh<3XE|>@nwQDN7<wK6E0VdCBY-SiEHvR+>jQ*JYZ#V8J&9^Eh0!
z{5$_B?b3eS=C>L)Qca7_<@Kc<8M}0xEu%xr$qe6K-?d$GmiZpankVCT#v8`2RcC*z
z+#4B2kD8$Y+znTK$COfD1dXd?8 at ps<t=)WMj{8pImw=VgBS3uK0ru50nkz3??mDf6
z!k~U=gAg+87Ji?+CMn5;o*!RahaAs(WJbd#J&V1<-^|V39Gmxm*gB-VKz!>!C|`(r
z`5rVQ{RB;3Fgv(i{VPf;S#93Nn-bOH18)mAB||{K1#iffW&)eAP=Q$M)Llh53bqB?
z<{61PQVu7$UI0Iy*&~k8*~0<u#=l&nXIS=Ffi<HOb7Z~%2AhJ}Hx5uw>&UNOeP~k0
zdc=P5x+e_nGm<2IarjqiKNzm7z;z4O_-_~)8Zqe}Rv$H}Y5TJ&OA=CGdnf2L=mU0%
zDq3Y#wN!^m$LL{2cGq)$+_#=T&vPXTZOv~IL)&$_zP$gZ!~%U#0<x7Sihnm=9OIQR
z{<q5#AB44gGrkDJK?{?7n)l9i|0!XN6T_Dn?!^M#)$q6m$g+0`WTL^TC!;(!J at V)T
zE6=O~`b$a*t~^vq15*qRj4MtQyuM;72>&Aw8&*A}Vr4jI<@+57eqtnel*3+>{&$)g
z<ThU!TkvHYwjuYT8Oi$?xzyZ=_6Y^LVJb-ENWRqSMJvmeOfa!t?7ga)FkANe1=_sw
ze?IxE@~Tze1RhRqEhg{h{AQ<Zk^21t9bbpy23LWDx$l`*g=V>Xd7C}Awa9h at +OGEN
zPiDo0JATughf~U#_(r1|{OZSn*Wdg~ki2hGd$lzb<#e1c at XM~yG30NWI{N4Q{R1m(
zdHG*)LVN1HXf+WrD2?m%V%&4I(&ZK-)3!%gKAZdli(E5Zmn at -4=JIV%pf#4O#GY?n
zYlB~g;m>Zu8WTJJj_;)(aB9 at blWL<MyuN)JZJ(T at p8R8oFSQ>Y=t7wNFO7UgVmnI)
zuNN??X0hk7-L1)$pZ_}g*%g$oeV}*#<$BG(dJIM4*)(iH>U^Vb>|iihi{CH!GX?Db
zj7wjf(2qp_w|mI}U+NE1W1Q8@?~Tv+{-LsjBw9k|p;~hD>WC6Zx8(58)kq8N(%91T
zYqwb1{N+cqvn>1U>!Hwf(|-mu;P^cTzUdTNawduKZs%c;=iKJq3WF!+{8OD~=yab$
z{eshN;al#`xunYU46!@SKVB at O?hA7V2H!S}hL5~U(5ey#)e_23F{j%CH?J85S3?#k
zfMK&uAYy)py2NO`0X>_(jxbej6m5H|c!}+`H9NM_`1w6ldfH<AaDVvGpvX|+o~2v8
z0!^5V+R*~ZJKY|N-sv=XWK~kiV~Sw at h0~2X|EYXD_An16moM;uy0cY$Dkn!%f`x1T
zQiSyB$IKr`>djHL{hQ++L*g=hMS{3FK8tJ^-Q|{ZaG#DuKz-#iZ8H~o1J_t*Av at -+
z0@*a3D>UXmz;JZRfuRj4KD4z9c<aBjWcSZHBfnRi_j%#{bMr6ie<Ctfi5g#pMEE?N
zd^!4pp5o@%kunmKKiZ3p)`edBPAa0%u$;LJpcYn3YxK#$oHm?BzT>|ex^TTk!00-f
zaZEBrqlKa&yrbD0UHJk}Y!iPVknIn6Z;z(ZxLpXMJ!<RDuKCXd|6s-n2h+4_kS`u}
z-S;7rE2C9C4qw;IwpW9>`Bv<y4 at 1Tl^r#tboaUWld;L$y=GHV4K4qpZqbrAOdm at Fp
z=J|9S$Q(w$Pl`o1jnO!ow_l4Ik-27mf=^{O0{`|#1&q3oa=3H{+S9OQ&vOsA&dXeX
zo9Ets-P$d&NgQ!b#xU<YY_{=wq~fwyq>^D&GG}7>A14a*f9sYEE!ksUl=|&NOiP0>
z&s^~PR`<2waMWd5p*PZ9301JYo}Y*wWwh?dUrY2?o$|zwF*WtT;N|j(MI+B&(XREE
zavL^ecSqo7^4Sb+6C#sj6;jT2%_*MNV7}2qExhmigJ>Tf!T;+d{2u|-|1B&0|N2CS
dCE!W&-Q|j9UFEMVv^nx0MOihO%8#ZY{|m|9vL^rl

literal 0
HcmV?d00001

diff --git a/data/icon_ivi_simple-shm.png b/data/icon_ivi_simple-shm.png
new file mode 100644
index 0000000000000000000000000000000000000000..6aacaaa8743c2ce103fe033911052d737511ee24
GIT binary patch
literal 71120
zcmc$_g;$&1(mo8u-63d at qQ%{V6)9GvxKmsL#R)FKtrT~M;ze7EdvPf44#nN!mp<qD
z&U^lYFKcBb_sX5Dy=V5!TyxEpi1#XTSm<QvaBy%~3i2}QaB%RjxA1VN$gmfKPo<WB
zuUypSq~NMXDfVF(h*pxyl5lXfaTt%LNU&=(CwW~LI5_O?zfbsnaOp=lxR)XY8A(k~
zqr)d8S0lM}zUY;PXUGfqK4bsb$&8V!j$YC7 at 8b(wT3XtCGJTrlFsm*x&yW;GbVRoT
zkJ4BhWcE!_R<v-|Ak(sfoK>Zs^JTWi6(^zS)ysF?>u3LE7JqEThurgaj^~%zm+Phl
zfz}()(-FA!<>vmbc(vT_C9(E}@u*k4t*jmFeFF9^Y1eM3etGJB(Rz9~IQcMZ^myG1
zZaaE8Se<SF-ydZx%sxDMgI=b%+V`K at ***@yw{<@l6)v_C&by}Vrc`#&vLH-YaP|E#`D
zwSV9n0>9+EYy>ZqT$lO!eO9f6FZH#}$vM at qgR{+9*kyeDO%?$A><$gofSmjHmahLl
zZz+YpJ>&ouY>f4m-i}F$J}S~s)rs9z(~3USqn_*%uX|bIi4U{%$<6oP3YGwJc8E7G
zmhgQNw1bRSIXc1Til>V~_>b8~aiR3L8fs|Ib<K$W%zkiRL?zJluY*wr*x240=`x=W
zDXP6!i_DMY{v!Gjq6wYsw_x&Dhek4PdtTO4sAeZ^GB4KMu$(?W5P6PXuV0}1JW3*o
z-_^Xz at zV?(166g9*tg$r(fD2LOFv%Mh21{w;+*x50oPUSU+#M89uwOAHPyqdyl(6k
zahk>0b2GpAs(9V9y#qcGZ^!w|>E2ROeG{{UoL}B}ULW3gzO=4t5c|d9th^v>uj70P
z1HGqu4j2=^hh4?p5-ozoO&>1fZkMh6dw_G#w|BrZs|Jqe5LN#x#*dHpssr~UIq?@6
zAiA3-|GuZyCsL&L7asJNQ!B!!Gmu)>bwK5z>Wf0_Ee6%|u5l at We<wj>iT at +U%A0$P
zm9a+*@qv2`w+)Wp5ij{Fk0fpz?WahK)#m}LOD`CH883+K9K&5XAis9?Dcj>RHH5Xh
zj5n!Q&fwwu3Jl_>uWz&-tH@`b%S0M~Ty?bl5OcmHX?5C3T5<9&z^R(u$GGu$=xmqt
z4-p^@*ds<ru;)XaZwywO^Fw73#_EMEL)WK_y3ZE<=uT54=_Wkpn0^Y`@~)7IAS*M(
z22OvewFa3}{1_pPYr|kL+4~#;sPn-uu1Jp-vMV+ at gO=%hw;-DV=fobhSed*$rwMvn
z6OU45VC`zuId3jecnXe&whxJh7-z(#W?;mBvZDDUN}M-f#l`X}c}=&&O!Pu8pbKNl
z$xp({-fr at 1<5NI}^r9(1<XBjCG@>t+o;1}uB`OWuOQ-o*T+4pAf1wg-?pqx$<eGTn
zG*Bv2Ts=gQG1B=+3C(~*G at x38S&AcNeWl^k>*cQ!#f#E}o?=pItLCB at -a&EQ*&CY!
zR;S^9I4^iN;zr8eu|I5pxoR_E)@e6*3&eiW?DRRgs&^%T^IM*1zY`aw`%{eJ`z>vq
z%id~}n+#*~BcNY!rK(?)ub5w0!OIyW({~@o$@?g-`FSR1?fE)q-S`BAx3b3(ZgXuc
z?|5bRak1j9T9fwKev))jx|WM-3>jS0s-WpFIYZ9vsm9cca(A7_mTR4>66`sr7CQH~
zB{Y;5|19SXD?_LCT|?*XZO7&dZ;#ub(+D&tmol2cM)LNP<Y{d8xw&q}UluRB>#m>9
z6n5cn9c}_|6;CAhX8bw*xI9sf$i)dyqN$(^o6v%*LOg4b!|NX-WTAc+vgUL7T!1Ef
z*5XQvu<zyl=KJ?(PIJ6?8I8(aRfdVqPOF5OqP#>Tamu~Z8dGcDj>0|^R at 6Nf3~AyR
z3IbMiLvGmT%R9MyqpXEgz_7Yj`<il7^F#ahi+&W9XfwJu{lA^Hx%?zw6|;_Y*gqJs
z8YPB(AU`&LO7^i|O^ADfpgU#Cu8GEUSdazk^S(0TeI=Rl&N)Svdfi)S60E(}_8|Sm
z8`P!o(tpczizbflk3L&!b?a}o(*2_B39K$0NB!s%02ShWb;tXv7g%67&$#yxF1t2w
z1-R(kO+7y&NxitMt_eXlA;Ri__P6(r#<q8NzU<xz-uXWVV7xrb8Qg8>IPFe at x_4t<
zWaO9I*Nj?Uq|6G8>FVxSgnM72R5PzX*y at dlH6X9qAyYq}W4_MJhz at t4TN5o6Q(0*2
zTHhIQs!>Q>xTdp3NpI}P);g+b*hH;JbwZ9JhMMkw{jG;^+E6kBr%4vj;i7@}$y4-k
z2D`JtlyZHp7rmr1ee+{fal?_^QfyN`Jb01l0TSK4qtIVt8Uf<3RIK8IOM>P5T=-LA
zAyO)AX(w|TIfH$h7{x|5r-`q+4i6- at Bn$O at X)0pQ`KyQ&sa_N<0t_=`aN-~b1Scoj
z<3kFBrfmdgm-iwD4y&)U9WrJc{ny=#4DAg5 at DMUuQFYW#w+S}TmBE(x{NVren2Om^
zgh1eIJ}=RX?SRvit>tv|8^4ND?{{O4M9WkepQGDJ2zjt<hgT<_!BUDItVV6zaRCD8
zS{OE#s+^nKnn9u{a~(}~Lkrgg4&sLTo#p-<O9rmE+Bb|F*Jqh9Q?z^e?ID|t#YQ-#
ztpedSAIGUGZS@@<zJ+2QBDY&Stobsu&%pW2?uOaI at mG<D`P%ib{mN`ZrCcDM at YSDf
zT)1wqj456B#cebrk&5f3{v%~s34fa-4w6Br8TI2eu)LDoON|Yuw2UeYoROz8`LJla
z=noFIkLUeKj?Wk)8T7>d+DN{P5AG##H_Q at _;!t)SJqhIK3i*ib5PZ0xwb-UyP%x0r
ziJNBUPJ5xQ4*T)OF`QmFRz2QV8N at i<BWbPi!c}7EvW=3a4&@FniTuBaLpAOTOqPiW
zvoU1nrwd_wyvYUz!KXHu2s$dAMEq8uRO4-9`_;dYYo-MI%4%Lr!`t3M$I?_Dd>jGC
zuBk;E*wM<!_HTp-h<G3_72inA7rJ};=R3e|=9?|{=)X|5J5BH~f-OaV3^WCYnacOd
z&usFG`>p-EMc9gM+eY?+#sn&R<Ro!yu_WBaK;3Yc8KQ)n#W-)*hN*5nEm0o*EL;BW
ztz?F(J!cld*j_)BI!E(2&S)hc9EbReHNt!U4HNsKjn(uiQal%7T0a%Y>lv7>eH*`1
z;<m?g+kuenJQg=!kV|IB0>177ZQ%Yy14FbeZzQ7bvc^p%QCuq=8jgT-!mNkk#6u5j
zt2ZKRNozfN2)VmJOSnGlo&y)}we8-l)1e|tJD9gi8d9{b`^r(Y^He;gVEd8-1f<Ae
z^<-SMY*ub(o$W-bG*o_ at cH0YN5b4XGeonLQoXM=5Z%ecOHS_T#nnQn6jAwig%=>h`
z(Q>clTgq`&*2X7m7?wTVb((1Jo^_fm&GFOMnv_hoWST7CWD4$*Oc?is^-t`5xo|;S
zw`v`q-YfxIV~j-kviZcPS)KYhA>xtw1uEkp=Nli+7fCcrVj^=}NiK$Ej;`h<+UQ@*
zJ*W1K6;ha^Og#aYe=_{0M7*_E_ZA}#rG3j(uf)U`aE?^idCYC?JICKS*#jl#ygy)E
zsOItMOi{*Q4@(YhJ;F|fFCakm0jFnfdwJrM0}1a7T0=59q{H?AP6rGOnbAkd+YL=h
z&7z92P+jeQlpEu0J!EDe1a*c#_5)Hc0KRopd2)Spu1a3vjS4uXS?}S?Z_!=N4yg2F
z*(X+)e)NASaLL>z_bnIytsNH~Rt%2GtL<}9iV-_m=Rp|C9M-w~<jTpZho{xaI#=Gk
zZ`|becE~qzg1;nx2JZJ4_}f(E-1-+dCH)D6BLUaYkz)U+8Ak}nbpb?{g&o_Ud$7ov
zg${z at HG=afE|wE`=(d<ld#2o;N|AkzdZ0Vn_8z4M^w~pkg6<LiM~JvY*c$#Ea&pJ7
zb^xVsl=EN<D$v`vWv9!d<@BE=rrc|;k`<8j+m3PZxeIhr>p-`~drFs3kYziC>F9`q
z9glehQB$r(?zN*1+Kmok8|5r>?Ph#0eQy<D$7K}|z({#dXYn4y`t2YvTmMJi#f<;*
zjQI=ar8pO5tI9|xZWBUkDq(~(DJdX3Axu)&qOZJ3u}UK4_EU5ud-v^tdUUQjHY!V}
zX1m!^-p0-kBHAM at n$M1e)W>@8$A*J)A&TN%na6a4XX5AVel5iw-FGo<AAo-peZQVi
z#IFCUE&glSOiond&fiHjXnj=sai}ie0}Tb0l-i>59K*02yVRPs<bwUv8e2(zWa|dB
z?JEGzw-RBez!0+oVbQNyq?tpj;xIIDv8CW<)W4PgbPj;o$_Wf+XYZ3gApoS{2I471
z0KR;V5hu0S%e=?+E!89__{GT_jjkH1FV%aI`-(vguK-L$eW at odWpGS4!G%M*`zgVb
zg`}3z1=md!WnHcg&qt8_8KrKm6@)<rX*Zl|xtCr28dqvA6fTxvey=hMpinfoJ%ofv
z)_CF<Z-+P_(m at sSija5OLYCJg43LYq081g8OgV|jR_o%Yb91&f7X at I*eQwSsKBhuc
zXX=eOtUA3AAjDfOlh6d;cdg`+$Q~XCc0yhn7Q!_)xy~o0l+Z=PY|7LCiRs~;WkP#t
zTCzCzxUH$>aZ#+@&1)z+oBFT7H?%BzG(lB6bYCJ<WRR2!X!~-0Nxn|vIepJBdSkJ^
zQ>A3Ek{qb0&+X)=A*=#c>OZ@(5&X%I^`Kp17WdR-_cs#tukzY{mtZ{10LT>0WvPZ_
zDNJ!$2Sb>L at 7e;-Rz{?5ad+H83<aYZ*;^wLoet8Bpq(~C$h$UWH=IIyL3yFp>Xem!
z!wv(1ZGfF`0CVmW(_dl0S+W4IIozb)mE?GUxK2YANgr at 8VglvGZK0WGlk<8~R0++w
zXY0~4dXTv%;4o}YhJzW2l-MXz at -o-%XB6I^UijPrQh1SiQRbNRt5z^#Ywb%OYxBua
zPmCd{(@Jt|UB;x7t0Bv^aG^=LAvZs(VqZGFg3fnNydmP(W)nXVhcglb=Iih|&1FT4
zU$TllF00xmn*K=pR$As9%s2Io>yT-fi{L>ILf&#R+u}x}F}h$4bHR3rNRV>XqtJ}S
z7~9oA=S+NDpb$K`kCuw>JveT;G=DZddECFyM{ykNoU&{F&JlCR=lpL>L6E5%9e@=}
zOBfn)*IirYplAN0B_^d7UZO<G5>vep3<e7;QymrNi!Jm^g;EKB=r6-PdI2>_{8Fax
zvlj_{k0N*W?D?d9DDT#9EI0ndVrDL8Lg_SrE^BtMY4$WICe{S~`fkFW1hEulP>$+u
zW_AV$aS;di_2#ao0xrpjVvgzZCt at luY9Q92t&EJ7iGNNj&J|yfZ>+^CnY6i$QcNq9
z)1HB~<w(Qnqr=xgwHovtII<8(k7RQpK?%i1vJyoT{_JSa_m^dE>0qjT9Ih|CX<rh9
z_Y<^P>uE=dv&aqEl>J?gJb_BBqU0{wNq-&84Tr`Hhqr7EcYWQLnF!nT!{K{YMfdK>
z{y5IcOH$-rG1;&$VKou#a*8{bD39;nA8Uo&?9oT<v+;~>lZKvw;zJiP8#o+BI?$l&
z=tBb4^3bP^*Q}}i<7wzjZ-L at 8#0aIiVx<+7VQ&lAh~_L!2!$_Wq*7KqCh~R-=iJ*d
z%BvEr=R+%9UZ=Z9N_5BCQ?||A3OxOP-tNBa6`%gc*L9$NDp>&H5U(tDkTRzuZAH*s
z&kx>W?0saC^+GSSbtZ!xyxp*#Csdnp?s~$;LIudAC9VzcQ6~?p?<L}px+o at AdBIU!
zl~7Fo(m5;Z-PJCPPY_1Hoi8PM^uF$cw))m=*#lX{Z|EFV3TjW!KMqH^bcY0SUyjXS
zic9;Vd+B?(AzTK`H({uG3IRzmllVG`dou5 at kChDOG95+tW0RN}z8Fgtsq3)QCw{vk
zrIbec88)NYH{*Mf?=mLudO#c)n?+}`$VGv$0PUO>CImKN_g*B^crMT);$$EdR16yH
zI~PzB@;=(W*;svN>?!x3uoj)$rM|A@;?-)Z!rSYqMG7|A7re|4bYL>oETm2)A#h)(
zHV8>{B8W`~h0~1g_p}D^4$!d0dJ>T at xJJ&1$|Kz;SQ4QB;^J6Az>pt$t787O<SMTC
zs`vB3R80jdX}RBxS0%jX1RNs&9@?y5Ypsi_v7o^o#zPdSYiACp+)=6fTm*v)v_eTx
z$IV4ufOzzoWn7VGLlVd7ixib_Ic^#IoqQhSZ^Ued-<eJNqEDkA%7z;f(;!nrWAYt)
z3eK0`YWJk#?8Hu~7S!gE)%T(95fZD|>#3&X$T;Qix6~D;(vj)%OgYUCkZ3NBB(`R;
zWRCUW2Yl$@%Bt_^&WQYbF4~>>pTkKFe52|beinFK{ZonFMEUmB{;lz!Y$$#TUbDhV
zC}N at sL3B_9kLj`8oE#p?I&EgiBKAh<;M-jXQsf)dNr`%Smr=Rl5vk1AF*0u^D%h|j
z{U at Eww1{`;Jxxh%-jFSdTvunKfG*u_;0~8}&D?AV`M>zXF#bn4(SxgwE6G-86IGD?
zkKZ`tS^fqN-P?gWyW%L<;^j4hg9IAf8k~Z410na)CrPG+tqTfcv>{8Z608?%%~Rhk
zy()h#0(G(?v4#>yJ}yS55f^E%up#~7p++ZwEcd?lUR>AwR>W`WWJeSPU at -xRxy!Ul
z6#h>7{6M#F2<o}Kl<r|NMvOZRec=Rp;+zFOP=lAK)?&z?emc2 at ld$KU2e~+29i8j8
z at eE_k-u;^<VZf}C>+_#Gnqc$dPlw?i2zY&{Qk>rj8n;8#YE<$iQ)T8J at KB<-!nyh+
z1ktsXwa{-alGG$|ZSXx<NSq7R05)z=Uh=onoYB05Y$z7Q=G-<dg7Z=Jjf^9^pRa?z
zZV%%8K(kzZJ4Znhnbr8WT8PZFI at x;|AO2VZic~)jEL?TYZPfwZO!;uWVMOY#i<%HR
z!t3k#VlE}m%s!bBI#I4rT67DK>05m=+_SH|Kerhl$)}iDYvM at DpcK=e>wJ0HZO&=Z
zA*PhKp=3$b_T5nMRb at BstSDk$Oc36)Bkt$D1da4@^P3ClIRMK&D$Ct_utAOrecO8I
z1!=Zm(oTf=a1IW=mx*zZh<opMbNveP#u^8fPu+cS<=~9SJM1aq)^hM=<^6l(KN`Lw
ztNDSc+ekMwE2o=tc_B1E+JT?Z5>2A0ql5U8IZ^aOP2V`D$`};mmjw1y@;Fn-8-!l?
zY_O9ZGO*PzF)f74=6_hCCk>JkOn~NZ>rB>T*od&U^o)C3{NUifXYGzXkp8+mg7e)F
z7-GmiRNJDvuDS at f<XwVNg>?{9fVq#oLUCGPgW`zO>9{I1hhI;oIQfc`zn##R8))id
zAk-I<ya83^!Uy~*5!$B9HX3;`;jdC_R<)P!cHilKLqcyl!y46eBF2K;7<`<kf6 at Y&
z;lp1n<4nM;)JPAdE|SFkM(S50P||gCCOv>_?0Iw1IdZ4zZmgQws=7T~oL}5x3L#Ev
z?jkDBSq)sS6VbWf;wKhwi}{WNHnqHCQ(|k4V8(GYGaFP^VybG}ZyNNGJNffpBuftb
zkzUJN+((Q#`kdYTeH_CmgzY0|0b*CWY$_6j#Tl1ftx~!+su_zub~&OP3s#dO(Pc11
zCO>8vMk<6>9gP>7Hs%?!#8}bVcxCWXDlWv*#k at VJy-}<cWQ!NoQ8XH+SA}W~l>==>
zoSa#&udsXaa{SMyc;Ql34`a)pAe&3`&w_4N)G9xo1Q*bnXasTV5$#UoOx)GDkasmx
z70Oo<EKYCUNDgMvE@{X5GmI%64wh3I=fqYL9ur|Ca%Rz-o<=zDad9L2roF*A^dean
zeruwU!RbBneoFvVHk+_S0q)rCQd)x1cu98yYZt(g>9-NlO++>KK@$9w{dPV at tTo0f
z&e7C+o=qwDRUB(`AdQy*C-sf+y`{0-*s$GRx*ry$Ms>bnWKn~1RojQBs(;fM3{Znf
z(PQ}H`XtRoaG}a4EoQUQ0u<~woSeeF-s_{Ez_$d~OdIhFyd7(=m&`Ik&E7Z at jRuE9
zK$E#5He5bZ6vePK`)Se|!^TYs8c;tKV#;m9oF3U2*hasns%PhD;pC2FnSf$95cSkK
zG?0-ueSU~Ce~j5R$iw4Y0eP+Rd|sE63ZHx9aXgI?tBt&ozncqGZdv0)><`*8e`|y(
zOCm1WR3B#DPchBE1^-Gk>TF97esXM^=Fl43@#t3%DYW7I7T=cn8I{E^WqqRNh&)tl
znbtXgsy6=vlejg0^trd>fOq1%7lx!~O5l?24pzy7k>D8w=kTtJG6R&?<?n=|SnA5N
zm(@?S+HvZ`Vio&Vt)<x5qRIzJD<Wlr_nJFhrlo`B7gA%wBe<DI52~vd_1=mX&0VTH
zx0?S+x&1?H33#~aKb<J7PA2yqj at 5?YA$QWIB4!|%F3IR1T|}&Ut*HkxIxbECejWrv
zz;`qUF>qh-wAUZQn}IY~dNzXzy!%QE1A=7IH34|=HXf0 at zmKIScw_2)eH!38v)}IF
zK6Z?^z44+pVr>UT6?8^n#(mvf#%VN63#bz_b2=+peRjp{=)D$m+CHZ?xT1V4u-1MI
z+f*O_ND-$K`gVQ-kohp+ncId}6mDXDzh?=54*1%aJsjHK#%i#X9@{!>*8p*3=+;Mb
zYf6~dTL7U`G95B5Knp^;Uc$eBvz#L!zon}v;`o^k+5FZ at qGG}A at ***@17y>*g4M
z18O*AkR at 4`cv-UBOQuovMXDrVFR+NlSXgzFEpcM3$8rn$a7xd6;US}KEVp#p7Ct7*
zu|ane<$2t<;|;G0Hty)wpZ+iAYMPhBxh at i~3}R3FYt7$tm8iiccuFwPr9x8?q+0{N
zA0T=VckUmgz%eiy;tdo;pACUNBj1D-O4<y)&!kaaNaQz^r*n`|m*EVquVcjGGyY_%
z_(P}!SDGwp1_w;I#%{BkBWj(Z6DTPZSHsDOEJt^QRozqf$Mde+PTFbv7q6h3!jlak
zK%?3{bf|Qtx%>SB-)Y#YBT`)7e5xDf9Ua%zv+tz}NAL%GA>^q82!t?i554=TZuo-q
ztI>RRMEAjDjk_-Q&Zt6<{7w@(I1IBn%=Gehmubs}@cI#&%n8bC00sSc;MP0syL+ul
z at ynyX5yesGO6HwEd17iD&RBaV=OdYLiQ(IWo;NjllUF6 at SZFR%#w=T!AURJ at Lz%Wk
zq>t)>8sJR1t_GLz79Z at iQL6<1eb!HuW3;;)x*xMa!M|Nrmo8&hM%D%H`J?`2XrO)P
zTd7k*?!bS*3Y#fGbXJ-a>W(R_XBnnve*;|Y)Y at R67%TGJm at xtew^+w(hwa1Le3o1=
zfB}~Byr%{_E at V1+=?V43P~jYEm at x;fK4BgC4g{M<BUcP28f}ey`T3xeMH0bNOOAE&
zb#ou5a at iReXSeC&+;D95vVgocP;MA~4iUzJf=}PyLZ53g<az`%qgF9nmRbNw+EAl1
z94>}PsU71Wau4(bNmW8$S`<eJ&j{;vG7+;5H)wF!>4uWPZl?R;x*3BJ`u&XX*dE;r
zJ5;PK3-k&_?F`3z(;%AhI;q+GiAS5&+h<X!BgU+1IS&1IMC5PbXY_?tmrh*h7G0^m
zVwtOY+ea4D;mV8fJTuGhnZ3UKJW3!Hy7fyN??H`b$RlC*P9mzX556CYY8T`Mt at -4^
zeI)ASo>J8GUm^k=lh9wwYsuOl%YYfwo59J(Xx|+p=_HF%j9rP^;uOy{{ul^@#RuUB
zZ79cr<hv0WVXatf8;cKgDfM_Tdkz)qf+k1b at xEs3Pb|)_wDz$zCo{PDNVZ at XbvCjX
znkt(eF3>tykgzo!xx|zivnop!Tb<klDkT<uwZa~?COimq!~)&T^1+oXx`&+<b)sSc
zq2mKU_lvmn01So2TH0N9WUHinMJXi9u#~R;7J%9;2CfGUPM+Mik+vIYJB{_4*YjId
z(tZ7T-Q(8Ldjz3elypvgESPDSE=9M_luvk^!z2Q6UOZn<dsfUm3NX`cW-%Xgmkt=(
z9i=%IlDux1Se{ZP7%MK_L&&?&TQnQ at -i3}8;TNlsZmMKS_0%S!in_kaeu&+iIo at n;
zyZ{(90)sba3Iv<(n22_mVk<#ids~Zqtq|Kyyo-N9kX<xfY!Qr+Vu8^I^C1c~Z&yTd
zJZ7V67>5hc9snETG0i#{j2ry%Fub__^IA;%u;@&L{2+py at h6tUhVTQqo<)M?uDr;E
z(`%dgY+fRVhO&V`o6b(YGUzqUmgLf%=n|c(&tS&)tprcLa8dnig5CjJ#>Zpj(&T=a
zVa4$!Q&Kw1Rr}hD;pb*+FshUff?GPfaVf<fQ5L&489LwC2(cF*_fKY8UyiX_SnJ0Q
zO5&{T8ihO#-N}n)VdNkTU!|oS8zco4Vc?Hk&mLpy>T|jt4H{ghv$gt7;TE<MgoLPQ
zJ_fcmJNJ=W0iKVUJp{VibJfp^2-CezC?TZgwEO$PSv9d<9=I2$o-CT8(x<%8EoRL|
z0E?ku(pb*BJxPn7wFiLAM#|naWjQC;Wz$0!!Dz$luo{PL8hbrw+=FDw!Y+z{<$MI4
z#x<CA{|{gS*Z-0;w)P(XX;l=3AY?X5G>9$~rZ^1P<PlL$_<u<=bl7yB)x^67T92!&
zQsTXFFGTigk|i4|QBQyco(m}`8Rd>|G*mF3 at E&}Wk%o+5mHGvGe#-fI=JBShz5 at kn
z^~60?^O_NPcM6*<JF;o|>@jTeI8;euoL2jm?`g|;2+kgB4|Df>E8eCU=AbiOJjF}5
zy>kS?T6!zFzTzfVK at C7`YG^|E2PWOqyERBT?tIE|1_Il{cXu;sGJbZ|zRY<v%a<0F
z$t#nAg(6?XOh6Ygzlq9&H(Zzg?Rs*7fC>r3>;`hIbFoBp!F;KwGIgH*C67EQA4hE4
z{Y6p!`lI-msL1Xgp)GC{)dHzyb5ts)z1K^n_OoTKDWyIoWg+T)V%T9dy~orpTL?O}
zP9WmZ<*`gJpylX7SQ*c?*+zY<W~vxK$OZ?heCw|KKPYra2--K9O7_4BJG`+W`(&mr
zi$kb^%wZ-f^oLzEDb1)Qgd2 at fe~<1`U^C9Z_t>+-Q0s5$_47~B(A<!+z$k$({d<}$
zUe>R`=r?Rq6It~~DzGFA3s6{2ASr4jj$-r}%wX+*IBnMrpV&(CoDCMuR55a7R_ at 8l
z^o90MpFN{YY{=41fca^6?&vD+NM3}I*M`Hy64Lo8<_GEgYuM;4SbdI9`uZa6qdB}I
zvu$upAx)UlK8m<Kr|Kx$^@h_H5GZqMt*tYDu~M7>iisXpxKuei-f0td_eCE~^B69F
zaUkgDpSzBUd5i~f*Zw~^1|vP$A+4a$HtAm<=H8>}sgb&?Gr!woUTyKC>V;J$=jZ6b
z at 4;!okoS32hk{TZ%zhlTd3UvaevLaV4YZ=@i{0by%QQ$D-AQM7L<^VGlH<;B%ec#L
zcJHCAJwbcM1?>4i{$O|9QSj`4__u=H0mEV#=bveA%^Fiyn*u{x-y%4f-wD=h;dQAQ
zm at cfT%!LL!;i+^f3yM=$K_XlZIF%`kWFeDMyrgmq!w_pOL_H+upF2pZlbk==K<6vy
zy!BWg^-PrYn*IPStU+FSKj(EC;zaSl^<e5Jdn&0aB9mrt?Yb$)`6q)3f{N;az?&!E
zt*d5Ri?y)HZ~4X4?hDKQSO_)OIF!zJ!7BqpWP$mYYM=pkkol`e3>?5VP~#MFIT2`P
zDnrWsGg8g3A;8pu$_HSXy_o4ZQ|wmrw&nH*R-9}JjFf7W7F^oT`*naqbJPHb*me+A
zUbP~4U5mo+y9X^&JvPDbHbna#(n=Y+lHBD#eu5uaiWyf%nC`491nE<1_5un99*D$k
ziYCFjUpm=ZepXO85$4G5B!+6ic}xNRJJN@^<<Mg~4{o^?w1Yqq00USqv2AgpW|v>*
zW)6zI+?el>QdwhB_op6-O~l9LKVz2vkh}N)aJ#mLrZBo%iC)QNmq|)6085F|9e<}A
z1|U#Ll%-_x1=c-tn#I5JBFZTskWc1|+2kwBKgrWgyyGP}iuL;wSf0HCEiNmpv_4eO
z^RNawTCY0j)Xyt7$HS~W>S*?^h67^|cCb?vsMsTz_(Um{R~&QkPTz=zJfsnPO$r4{
zy$R0<DlB at 2&GK7-P4G^)ZgK{YcAWEzumV~uUMkC%Q$4j~-dhr2Z}B;A^q_zE${>*r
zsZpfNnAsPDTKnzk`#SzBrlsFM+OCh9fUY>*EpoKu44CuE!3kF?)Mg^Lodr=i>;~q|
zWAA64eYJ;~T0%{4z^PeoBb)5xrXZ<2RkxP#AiLcJX$yH#--Y2u$gxP^&}C+Nz+%&V
z&0xE>`u;A at qZX66<vA5*F3GX%ww-`0iXKj()b%n{T&&5ADap-bmu+v#nde92a&#wu
zhEuOM!7qKVjKWY1lYK27(ue?c^*r)NzOuG`fz|?#s5 at oS_SQaeXf4Ope1@+bX3TVo
zdE+_^6HDuNO~xbynUE_3N^obqLUdiwx+Gmt7zHS}5+k~}zBJpul^jaUmn5 at s&Y#5P
zrTdHE3e(&vs%Wu1+D~FJn#9&umQlD0op)LS2ORP3twCS)Ukk^R2pdzcgv*r(6q9D}
zJ0*CgZs{VTe4u^zwPWv5ZcZl~esyDW>*><gVk2keTVFn}E!8(|2u;z^6tEgzaB#dm
z_aoxU7%+JE#^1BD!i4x0Rc6o5H$rq-q<b|9t*|88^jC=|pTYcDOJ<H<nsyJ0i6f5U
zp;`P-C#J5u@}8U&AF6V68R1ODe4Up^$mJ%*m`ofkKiL^fDA$=+xpfg;M!I&!Q!^gk
zILY9*=6u at hnX<z5*&@8yA#f`GWPR=1|5X~Z49D#3 at reSQqgD!UUUsR;8M at 7eY#;Wa
z+5sR>Pw^Hk*1l}n+%O+vUmhcG_Z|LBd6w=go_ at F6z}I$c`je`+or`t}+E#3zR`sGN
z8lwefIGdhrr&d3$=$ZeA6t|q!4})OMq=|3Nd9d`4>ts{7(DYL&01%`2Ol?)>5DU1F
zLv(9Y>9C{1qns90mO=`g+~`L;!&FH(8TDQ#GN34AbOx&IDeKvwsnwG!l8yTNERJ8w
zLs6=}Lul&bIJggx0Sk}@>~6txDOg<e6f`J)#v1Es*-I26Hu5GkrSy736*ZgjYjRE7
z8 at ULnt~@Em-+PEWtRz7(9+Yx^WzGwCo#PgAQU`xq^AS^=gX|&LE-q at 9w)7FR at k`0%
zg|-PblDY35!jcPzRCbhwukoT6PPIkb7=;VI%Sd*C*`9L&XQMgdl3plnlM(LcmD4aV
z7-*0mw(!uCMRgE+b}xNiRX``bU^>ALAlL}eFp5QOb%RG^-;M9#6nvax_8cb{b`XIU
zXreRsf9*wy-p%B7;D9R6#jFf(E^6eZ-z;M5doP(9Hkn|yp5iYmI~CzG)XxR<FdQVP
zBKb;Kv>JP0aj)vce3{jP at vkU7ZCe4Qvxj&ygH)2{hj at YuRL=#6>mr{%G>rKFW<flq
zY$czWr&6n4q=WjtuK8ya4eeuDOC=M@=4>WNE()=64I6>YHCbR(5XZ*9Wc6bB0p14d
zQo{-LBNG;^$650k9pB@%;Y;rObSp-}qs^UKugP2UxqkWLH&$#__UX}XaF4(f7S7Tj
zjDS!eKbN&)Wl(7t#-PwkjLc}^c8dEs?82ZrxTw5!*3t8huA`JA_mP4sWw=~R_IduO
zZi(5`Gn`pt%myTmkQ>onLR4`2Fj;#mz26KpP=qv-i at f=)JO>IleX;Zo6GRWk&XQ3x
zaeRN*&{nNsyAU!N6Eqzuw2Qiv?U5cvok-(9eDLgavK~C;AzFJBkui@^9Z|8OI~y~5
zBCWc!;g5!f>0DQxEq9Nk7+W2~&n^<XF4%3x{QQn3^nCYB^RwipM at EEza*vzoidg=G
zR`gyolDj4+5W0niIYmHLS+J(K&bA`Do;2P3kc=QzR{t!m-RW}5(u`#gq5q`4u^=xZ
zD6+6_)<(&`WE|+?^~Q;z>E1oLeV?-R;LtwIuHeWi(YN{AUq?u{ENnVbl7>#p at 6LJg
zq6X0?aH8=WcQt>mLAUH&NrDxPb>8 at 9G`UJ9R4W2J%_8I^7sPxuVw<ErZ#?Y=GYPWD
z<oq)0mQ>!A>p85FWzlunZt^E+4zt#VY<4sQxQC97D3)$aE8YWTK>AEwbi~E-og5XI
zz8WP>evPJ4yO8#7{n^%HD`$l&y1#nUYGeIV1~3I4aG`*5=)D4ri0h+yTE7Jv3_%3R
z9k*js4O8RbnTh7`pW$o>qhEQWMV(uv#xSsWm+|eYbmvc0%o<|ak|4)fVh)larfWEQ
zAbW0xl%Vj7I`hd{xe3bYyOY~}=J<^^x)RIu-D^e3yEjMJVP>cyy2Q<uEw9qh8xCXV
zxF3-v)N)P)XEj0#v%mqMa&!0%$&S=a4psuhFU}2E=6t<Z450hxeOxDk)IY_D+WJ|V
zJ#-_;&5zc$RFM3eDHw-RHm&!$DOh!(t at Mhu2dzbO*Zb=B&mYnFeSad7zsOF3y{+D?
zE)RmQ#dU1|<(9oFJFd>$EtO&@WdUX at 4Kk?jXwH%7rs90af^}q($-|{NHYOWqwSqI8
z2&)K+kLiyehCk<9=M~9J^u4U1?Hre2jZnqAr;uXRTOdw{!x}5MTlxBx)89mlKB7*L
z8i8Z?Ts&)Bxa#6gzzjd;i1!MgD8WfjH^SETRTimb8fT8E3S+fL2p4|tdXDb<0FiBW
zS%$BPN&fDNY*gK-gJfq2#&>6c0PL}cH4 at eS_0=4e+s+1K at ht2`xm~Wp)3)yyj!3PN
zR2SXqUViA|h;LsN5crrg^ye*(Th|{rlRPa#yQ>rES8<O2L=Dv%37&ozIb3ZCW-b!o
z3OBV~+<H^fb`Zn>uj%LggmQkrJ4PK%Q+57$p&zS0hof<ZW7hezouw^#@ylY<d#aI4
zZz3^kt at 0SpQQVeHAy2A{Pt0?z0+hIO9aP6LS{uTx7e%E+f=?~mg6D5o?yZJu3e*Q@
z{hAT4$4Jb3AyK4BtX)C<QJlMZ3sS>O#^Gfa|3_{89UhzJ{LweJuIQ%FFgK3OlLW{G
zOTdUi6T%8FUgV%B-;H=_gBe`Lbq0#ia;KTXJZoyYW+*S7L;b`1di;^eu`Eea8_%SA
zLgh+Qthvv93o?ZZ$mQ}6Pg|Yao*albmv3d4;Sl5Hf*rd5mW+w5JQZTw{cGDIJWmOu
z-Naq&E#I)MFo2S-_01lwk+*PxUfP{i(=1hV-%PNBKLxVMhTQV_bGM)8)t%?hOP>v#
zudUZU$ig6(o>G*%z3gYy5!xZn)pCGZ3fr&hi(Qxo-~$V&+Yfyl6J6aqgHyD~M4=-H
za@$3}LjKTxnhW>C>^xY1FVUB>5>VWT>LMF3MlWhbrQhSj|IFL^+?mL*1p0Q2+Biqa
zJ at k>s^0+%Z0+L#N{Ec<_Y9V$ftH~^8#PVa)(m?G@!B&>rfR78-#-9pVd1;6zuR*At
zhE^BX1a^sE`>Qa&R*Dvov22k+<TQ}A^ApP-AC}55p6~Xhl$dk_xZYxL=9`E^mvZ9Z
zy)MQDO1 at dV#Aw|;1T1;&{C9>xW=`5anVJEzbd at y!JIgaipMsLU!Kw%nYOLD9n#oOt
z^=}3nje&yvbX8sRk<C%a`JoJ=DGB@;3Um%~T6(!Wn9hZ!c~e5tQ at E2ek-RgArr=4R
zPZ25<Kg at t$>!0^RbKBbF8RN3~F=dIp_)8#3c;Qy7A7neeneI_}wT1iyza!m~)dlFP
z2e7MV#YAf|io6V86VvUx?TTy;R{pD1B at b8uVoA2D_N`aOF+Sz$J;f2{_CrPi&(tK#
z+$<)LCc+_RxIFE1JQtSP!`B)yKejROV`ld_FR7q6;WCIwWm1gOe<oTmFM4~ORPFtb
zp}ne(=1O_VH&yv>mn>Y(2Tpbrs{M~dzj0)9-BpODi7q&L^N$3L6_iX3H}mi7 at NgW<
zgXe;coJm^EX<I+iB)vX4YLHKA0<Q%GT$ejpZNC$o7|J%g_1)uYeGF5K2{XR7$4hdi
zDNf<&=)q_H<5Nt1F%Gg~_x?CaW8gB*<;Gv|dA>#^GbS0Wj+M=iIK6MwO#W%QxV>Qw
z{NZH(f4sxnpWea6cl}ci1B*3Cp@#BxbkH=jBa)*Cr!qCRTF+ZSw5C at ZumRZ({_b&)
zAuleQcRWLZJo%A}PU{x6`{D~9S-7D4ukre=1)=7|J~4#@;@XsnQ07kSa}zu-nrwsc
z%a9j&U}2*6HdYXx1toN1%M^01E;^m;KnkyXEDO`b0KD3Nl at AO^rCg%Zk&CUi1R;M(
z`txxwXZnv1FIr``N^g<s@*BR&ooq5bxF$ajqGb?e3^YeoDtL_XC08#FN7c;L3t3DK
z$y+AHyucW(tBQ#F-jy9j`K4LV9UYSk(64O8Ri?^~enXQc6!RCpP<%maYsQt at _TPbq
z5;m(5if$Jw=W`Tz#1m9O3}nQ+KTwuo34KBraHs4ajFGENqEgOwU=hn?xE1ESbf_Rb
zchs*n77|aQX*u&=DoOcWsHf?Ia(iVIs!zUuM0e;^@g at 7Y+hT6u6tevgrED!;X%F8=
zJZ2>>iu3eoH=jJI&ioGrw7+g5J#sPR*Alfi1KHaVnUew1R9ta{%`Qt5`#sla%<R~8
z$tkWwJ7xbVu=#E5%Cvy*t%LcsT8?ko*bFZwKScooEUKQYaiREsCnAKDsInuBs5|Bs
zL+hTi*a8BTA;v(mAYyFf{)dwaK0%Bd>B2yM3exm={``sGq{-G2^&+*BR at ku_+v*cq
zylv}#c)kc(<6GGn!U-sJgBWKY4<L?$z#X)9g*JIRK!7#b@%JrLJ6Y#sA^4#`9eC&W
zquEMJbSK at +2pPVL(Mt0CvME;iyJ02eNqPR3c6Yt3nNPv0Ma9!g8U at H5cX3pEry2X!
zXBo_((wUv8?Y*1dluySbrcORW?kLHrQG5hr+g*14$@7ZG65F%q2`tw-H_^QGO at _=8
zwJ}fY0=+1^Wsi&5KhicUKKxq!@@furif>@RLA~7jEl-Z7{i4xau>Lw+NQozhO8Mar
zBxc1zY6aF6rZrqVIq=hbpGPL-QPoPNm`;xb#YeU~(6fhBcdX}IT-qwu?jR^qfy&Kj
z`m~wFh^qDbDC$-7x-^){`$uK!N=X5@;*^P{9p*vBrp+&!N|!~mr`bW6)y(oYnL&g%
zgYvEqJITWyleblE&O1$s^I`YuIf+um=G6Vxqkre7j&cA*#npG_)Br2454gkSXe~~H
znm;jj>9p2%Vv|nkW7V{<k#}h~vSrCAXxU^4CW`rN3Q-j at vI)5=>9KIC#O#wX-DGsh
z!?`oZHqdRvIoCd~2Sx|PzCQ?A*E-+xVT$Q+1@`byoGnnB4=l!)d==z1waxtgQ-;1@
zGg&l(8`q@{4#G_EImXYcckktQ6n9;|p6<OB-{R_UUoYsX11n%E$9G~I=TgQ$^*-1p
z%ddq30n{7||5mp~fhE{bo_WI{D&Fg?ZC=37QA2o!Lzy4)>q9`kLv>54IXQMtAC0`V
z)EH=)WS8_BoV1&At}*V~*J|?x1Nl8%_40T5K+&+&#FCL8&%JE at H7PXh2;FmOm-oU3
zQ#OLFeyc}&OKxve>X)MdJ6-cwvveiLdUct^OT$!6O%*+N5O={x6QM>m8;Wd>yjtCm
z{oz(Ql2JMToo&N1YlkwY%2Ll5Gt2zmWzs!4u-NAnNb)N0(q(!irU%Q91H#u!+0nNd
zi3$F`_*8~jA>ZB*sBLuZJbI9=!sJ)Q0jmr(aUuGN$~k`?i2GAVVAF<|ntkiPo#rHR
zXR&LZ|EMULf-KTs`X$8yIF8GiF4XTTE6ZLQ+S(~rf?WVVNt?_oq`csI++`h5|EC8Q
zPE$S+PaDB=-Cx#T*_8Vt<hwzqgbdnU;DbLR4q#AzRUd(O=-`$O*bi8>H||LcYl{iy
ziW4OQH^`KVQ63DqIFMrtraFA2Sy#b3WF~jOAL7jAL_x?|Ej+9!)hd1_RraQT`nq2t
zi`9`-(zch#jbeyj@<gpy9X7;yf9DYG6R#RK@)Pt8Q$#ch?<5n<UO2u at _*JI-YkjM%
z+TDYUso#TB$UXp^D1oSQ5o%sRLNqx-v78j3Fitjga9O;zoCjyA&C>qq17*;>f}~+y
ze2!^_<?SNYas<_|3&d?HXmchbe%2M?-QHcjpMT1FoA&Mpr}@tJAP=EN|N3F3At{y^
z%k3f=_2N+*7bWY}_{f=P^x2rm*$gVLAFG<48Z;PXsW)Y(IHfffDUA84k(vHBuRgJ>
zNc7#E$qR{OXS-0Csrth7sQ(cG{gtEQ$L7_dFBf;DsCE4n0sSCgAbs6ACv3{!`b`}%
ziUyaxYY-3=m%O2~@~Qc-k*8ViGx9r(cPoZrK9f6yHor4qs7^+tl2D0;jnC^xaJ|@D
z809-r=+!u-+nj*nI~c`~Bx at p*ghxF_LGTk-FlrwzMnWeMm(^B|P6EaP at K`aVN>!?S
z2 at Ed~lFwB-EViGM`7+s|ZSqk;T-JXr(kL$Z!yEmVJ%-lLe$$t*B)7IB3BvTUVZVQF
zpYq3bxW6V(&DITCNsBWfc)NYWEPI~h<Kq7ula*HNxZ3qS0>H~p-1wAVlPfLw8K&d7
zsgwx8J`Z(?BysnZ9a9Y?O8~1qLka6gpHtRKCUpoq_6X7sMI5hBz(&rfiaWrL+cL<6
z$FL($cXc=KZ0fFfUKm7PHAOLw<mKEJak{pDr1gz+qZtxR=#F_HUZMFoiNwo$F(Ck9
zM at onUg2>rY!}O=7n$R<$%$m(iEGzw(v#Tv{Py8HcshX7}vNt^ovkK1D1I<;Udza14
z@!VZ8gRtXF_e9gnMy;Dqp8kiPkGA?(!}t`<iJA=P;?3F*GO5STGBt4|0u8PGOAB;;
zP>iqwa<d6G;|IDO;mM_k^W%_L^w$xSJ14>@Or-^0Z-GA5dAmlr1N%VhqaVA?d9B!L
zNbw}g1BtR*G49y0&0wxqA|SV5jdT(z=-uZMc==*eV=08{SA__JF3W?tBADRAVNMZ{
z1`~P9&!`F6q);ZFsX9eY-?1ZGiv!?tq4s2Tx}WWDxFw;rFs}C0u)LR5(w9sA!)>J0
znkmZQ4aISqDhjz*RMaPyc|!9g!L;e9>S at ***@bt<6^8Qgn`4vc}zYcxOmlf>wlcU
zhsv(~lO-O}yR-9G$b>a2g!R<kS+AhEH!7L at kcAJ<Rs>1LLI(hJ+na=z at lPGtyhn{h
zv!pX^{h~MUVg?HbcDQGa2%-noK^J}^6u$LK_CIPNU^GiD)~<mrBugO`0&lkcw;9Xk
zsj9uk08T8M6^%0_q9X+8W?Yprcb<3lCL+t0XU~MW90f26j-}$uY|J|!yBj8hMIm(d
zMY%5L1NqEF(N`q`{~J`^- at q|=lEJuE(Vd=K|KJAkTrS+`wCH!qxH~%`t)y6ziey~t
zuVL!w;ZH-)uh#u8_df|zHU`VJet`1lCs@;`FV`+dGbm-~#V6<QTTg10Bj#TXV#(Pc
zssN}6$8p2PQC%5f^np3zKpp+oa`tNv1Jdo7aP6n}?*(vmw`#?_mTlI=G>UW;+vH}7
z at ***@M22&Ry+ at N9IFZoa^umhgbQmY!zC4&k6s{cmcaK{z_hM;(gEdJD>(->*iNe
zH(q8+Qg{oDA51(35I(Llf2>N88?%IYjW+S?@~pEp?~YrPjFcVAON(UlO)St+>AEiv
z;KAze+D{?7|HXSGBo%?#WQAo$GB7It=DRdUp@!r6yM<pOJ{wf7q_sm^HT=UCS&Q~k
z%-st?O|zspB;#{b0xA_fX<bBf4=daizWxzu(>Xfd;1JR_-`G38?QP22 at F+O1$iwed
zPh&Y&l0}j}F=NrgZUv*aIvtkPYW8rU3i6UsJ;<*29Va;DcfIpcb)bkfKM30#Us#`O
z@&>pIVRm1CkglCS{?BajD6gSg>92gvE}FbWHXSy)6*LW}`3um|`q0S`Iw|DlW*=0g
zo5uH%|I^c66QkbnDPdg46I(@Ut at Z6EL1Dr*aT~3fj|f%V^y6nAdBUU?u>Z=hVuo-w
z5N-T3L~%L3k)qvx7LXn&DE466?*N>uh>GIw#vV+y;=NrVZX*aO)XLNO%{TeQaf<(h
zPw{hvF_{lDIVs6`ytMATYMM<s4?;w5s^0)P0onYAH+C<j|ILOSH{l at 5_F6a%fANEy
zg`MhlsEzZ at 1kY36_mAflR(PMYj_EF~`Ni~wrLPEGY?V;t7H)n<xjA&j>wr)rlpoiH
zSIOlHL`_sX)uywL_h(HgeMvW&bdCvYT+!1JRe~7dzfg~+nWr62 at z2VpcbH*A25kwB
z1 at yoS-***@B0s(3O$7yIdNwCC><&$EHkpxTqb0N{4SMrLdQCUS^Qonl?1%g
zd}qPpo*htuv5BXu$`N`|u<>1Szbss3QFd*(cwO+ at N`8&VQJ7iOGH!)2KVo?bX6LWB
z!L|15Cak)gs2ICgU60>`0cD!2m;dUztBknkE{pyun+3l)rjlOZ_qWLcmQbTi(CO at h
z)M|+FEIW;yAl&()B_;^Y>SS~jp>{Yhy0jz_IltF(QidQ`h4E-@*_+5ro+ry-*lJ-*
zO3$4^nfxjbuQZb)lLwMhmXLcvxDh(46D~ltHGz2kOLzfkc|hds{ZCQ+qd<|Up9$l?
zS5LhQ+)~$Dzw(!l=2r1)3wcZfl=3PJa)&Q}lt)V8aPj5AT?nj}YRx>W{Wr=a*0}sx
zt6ET9jI%FP?JgE7yX{LjF_qtR%R`?TNk at B)IV3L24C+QaQhd>OMieAoYPt62Z`fxV
zG32Z_O<p%(2aJ6JW=5WM{9vp~)hd=2n^iiCC6!b;b#4h)@_uef`o+<i2=@**Z1RoG
z%n!93hrJnR9`=Tna07Hlek8$fbqGsg6+xTKB8MD$P`=B1Jr1BMPAR2_o(7mq0E3c_
z^beA1zhzEYxO-MKx3>>-0>j4Ek#w1X`0x;zo5G`TBP;(ERWa?ca}Cp at FiV+OlG}Wj
zqz)&TI%ZO0IF%1h!xFP2#O8_1-PXUD at rmoxCx7n=ziIye3ex}i!_z-9v!#(*oPT6y
zj=22bE+!o!B2 at SF_bLWv;ZwvL{LzB$v{hZY&310)KDGRWTx8S^*CZUlo4O*+I2P~5
zd*OA#Rgy;CZca4Hkod+J1#<^Fs&{mp8TH1-Hi()vnzGcvqUUa{;ktn;P><FD>E$x&
z?Cj`^fSY%~*Lq0QnWC%X{1mNB2tS%#*)62_kgILP1HOHhNE1??Cw)swCZ(J1CWL<>
zTv4sH^Nja at -W!O3tN7Z4s%V at 8^IlYwL4Qc<!`{HSKiHai5==sS^s^{GZpN?t+|O?3
zi6;#MDuDCWGD`w6?y@(uC425Xo7_ at +iNE2GaKCZqk_jW?`@0Lxt at AJRyR*nSF~ibC
zk-x~@$Qp+{OB^rNRoKcNv1T%KpTkwKo40%7K at LdnDICEFNIuunidCyTc2o<mM<iPz
zb;E`8TF_snR2uQl=J>}Vsxl0%rIuULvC)CMZ4=FHQIYL#hy~b+I_+-T?+e1+FDIk+
z8j1?1tgw4-Z4fwZ at soU{{4vQ^ai03FrK=}=CmcQ+yILG@=W_^Sodjcdw=G=$SK9_7
z0AoJp{DCYeMM;jQl0hn?;Z6UMwz06BQV$0i3Vxi#MP*zkJ{Ct>jIbl$uy<m_l8H({
z!r&}7!=qTy4>BYgauW7Max~P9;3RuL{bqnp*-(Dbh_W%)8JtBw&Sft9>K)1eh67+S
zQ-am&%YhHJ<ktMF^C}Fl(sxRAZyZhQ_|cayWX1u;-503me%KZg+ly{qQ9B6rG)iw}
z>3K-MWFgQLF~m>+Gvay|!5`kZyoCQZTT*Xm!twJOV1_mAJZmicy0+tdP#3&sOv=A$
z<rajH(2dOF-<JnfM|!HH;l)+a<(n?j;U82=<Msapea!<_EqIw~S6QUwu-Dg2<Rv;;
zA$l3gtS7n1i at GdOY>Ktqm6m;OaeDTvbNgWGZys8#`D|Co|NqE3$M`y%c5gRs(wL2#
zq_NZ3wr$&K?4)61YXyyM+ji2}w$1gf_Sw&U at BMo}uaC24u5<o4Ce88MLit at D*K at U{
z0hK(9o{jv9`G}?5n&>4n+7{b!I?TX+uqgFVB)VzMlPV7ToUh4p_zG<z;@ei;0~qDI
zc=`qtxL9h)=!#vzLA~BcOy;`V`KrGt(crWZQXvc>Lj|FSqC;y$o}yB=O~`%l+~&GD
zM-^7u{YB8gn+K!FQBbhAXHNG*+IztUC`~uV_TRQ6OvH)RfMNoJ%7EXW653ag>o<ea
zO(V1^f)^N`gy~2ZH5fpR7AvXkifXn+hhuL0i`s%I0hIenK(&4|rj+$*!eg^77cMGq
zPsO7t>O^EShir+PX98c=V~pcgXSd at +*d|h9Qy2_GGlvW_uL|IyPkTXM{;I=R__03P
zNG%h$g57P4&Yf=Et_F^!W-5q@(cPo1m?BTIm+C1~cBxqq`&dZhI9WSPgDzHm$-t(*
z=E0loDDk$mAPb~UDHK9fw=bbud$_Li<(ISX1vpqB>Bp=4*MeFVKv6JdI?b2Yhvh=U
z^;1Z+a|>EGp5D&D;BN7v!8Tvmn|EuZGA|dHoiLi#SDX#!ZgD-az+&UMrEiyfPN-NE
z`YV*?no%>E?{tdq>nr*qmAn1O^@1aE0ti;8egIo)hvRSz(WhiyorvQ6PmC1NM7|?<
zwdD<zj&BgRfttO(%Gl?Hvr3{FpRJNMZNH^=e2u2>ZzLSROAPCDV-UI$5Iq`H0uvKI
z8oU=lqB0Zna9AN~pVl0aCAD2FBws(9Lv!}H?E<WM{BlnwI9$x<T6R801VsHugFn}L
z1vT)H?*4xHK>aOHr$_bp3&htH$Q3Hk2?}-N&_f4WKl?CF-uX>+acx3N#rP&dGK93C
zasHhY4Rg6=^B;d?_&Q1Z>ji52-f+=hKOqz)R=&?HCI`<q at XUhE=t8TvsSA^QSucXl
zb}<Sw+uB`IClq6ja$*ED4#YKXU&U%8Il5bTdHa4<gl4sfm(OZF<Vq|4U}B6kD?BXC
zZ9<;Kv at 5P*DU^x>&<)!=cr8tAzi5 at H%+q6e`&|SU%7YvFMw at J?7VreTY-k^cqp^n<
zs0 at TL_iltI=MIZ;I_hXnd)b8^<@L?DwBq`T185N@?i491UdLsh#4`KDQw?(S;MQs5
zzcm=2vlDf}PB+q}Sk)*msTR)OSMXXNuNG at JG~72FcS4+T+KE)nk#U=bQcV&nPJ*$$
zs&4n$seJ}Z`eK!&hwHJd(B*tt00yP|Lr(z8O;V)E*W$-jOt;uT+8!%yXT~x+_zSkG
zm8#F)r!e|St^~=2<Pp&Dzi4YtNM&lrT=3x2Y9^Q46j|IwTQnxa=_J<cvZimdf{?u8
z)Sp$}x*hFXc$8t~wUG2b?LssBzbz!{sN(9 at zjp#i03)O$40Z||ic3Cp&maAFv)5=`
zINRPwaFs9?dho3vo5+HAxsEil&R-mK0a(Kn1t$l21q%Uc#Ch5MAGwLkg|zGh$up?F
zBGoyob1O_MUx{l~2bfpY4!5db+rzmpQ9ajCGO`A7>x$`S(OwI88R{w7H2Kw3WiT0V
zEq?b>KY((QX}<8c{>rgFi2XpUE|QdOW=Of;8fefu9%gBB`C>goeWWJC$71;*ZUSao
z9bm%#+o_wc?(Cu(^PZ0AbE4p0H1*(>AIwmbuAe8lqXQ^@)tv1*Fa}vWw@@&sV_kzN
z#NFH3diS<zcoBr(d~RBpHF4`I+4LibXd=`EF?CW~vGCdHvxu0o8ZB?A#Oy=%!{J(0
z&gNbIhi9cHDclONd9B-5R%IW;;J2(wh96c6??Ix!NEb)k0g#hjJ{J~4tvpajbaH|N
zPq0m%hIn2`QH*F_a2ZJDxVA~#s`U6jL~dYGS9M2N+ywb<KhG^t=#~m7dwA@*9%gUk
z8#ZLextvcS^cL4uC~rQLwQM_-(oxt=Lm{O(59AhPT(wD<aa;X{jmA~|GkLm?{f}%i
zn&BN~y)qt=UCq3|f~RF6l*owuXY2%-!sq;W4dr;2NneBhSdp&L(ceHu%Tr!I(M+C1
zjEQbnQr%3oF}6Rcim2c8Z)aao at H4!W&PoBwNd7O8T_3Lb+YUuCrPCXtM?9yLNjj=;
z*omVvdc5&R$>@`V*;6_2=TN8cA-S$sx7r3i#U}Vej`X;cGSp>TJK+-;*}5qP86;vy
zbH;|3StY at Ct0t7A6eCp~d$8Z%X{(jf_~`vR$CMZ$Pt at x~DbZrR3$5Hc@}{KfM%Wf3
zP4l#&)7grIcE*??KI3TsETjC7iGTXP<yKXCvu~$Cl1wiXo}aWke4T at Ei9Sy;%5T|o
zu at 3y!(~hU$HTOMJul1FAw9WQOz)>K$p}^&H9mGznjR-$LhQg|B>7C`HZ{o;>_$2V^
zyLI+~o^*HOhlk-zn3KFEw~*!vl_ at 8@%e1fvt$2k)rfKWE=>i;^Du*S;8R;AgQ}4BF
zBGUoy`BQ(gHUe(lFnYTUz=-Ma7J!laVy&Jl*yS`B+orW=uI1BrO=nTnn+XalLxp`Y
z1kRi?T`}~|S+FNNSAN|!#G&$8Fb?NswEe%$2ax0c-+1XafT(~`lSA1Op5w>C^YR4$
zDsuvXD%iiNi&lGNy0ofQ6TaV at 6xu<x_Hv}4nTBR&7umu{2B%#{^N791yl^hAUk=OQ
zn}tVuUHeuW>XzLi$;&tkg;gDaz;3rNC<t>Tw?6hIdY+bN=yvC$_Ar;sDyAMsNUJUu
zBjf54y3Mpf1;*~v7PD)U-L)vV2~mdw1EM at Dw7e*^lB&~9jAW0yVlXO&)WRxUq_uN)
z#Q2b#pAFVqX=49H=|6|-kP}?6lo%JgCjEOz!yQ`>BU3HjxY20!N+o19$Wn9Q4tX*Q
zPJNu+jgtLQeune2FDZM- at Q{$X7wZ6(yLyX9P079ntG5^NL0kXA6?T}7Hqk3VimLE;
zwX(|PG#UB|5tsgo5w-22t)P26f;`4rQ8NDKybXrzM(#o3uMsPWrx%GQ$|2{A31Ka`
zdjUANkw}Rll_6hIBH-uMb)(d^g|8c|9&ajA&;XXF;aM2{$G-On*5{l6ZlC<^#=M%l
zTo_$ZxeI~HbV;NP$$l?>DDRmf63G*1elQI6k at P21&)~7M*hfpQz7A^(M*8~xHN85K
zzQ40g$@=U+qfHj`?%!g%HGNN2j*i+bxpetQfPd_t-TC+9sHpkNoWDu;_v!}+Bw~bw
z_fRs6ym6EnanN_MB%&)kwyXFM!~U!u)m6`d;RSLet!$7MAY;DaO>GT*!9Wec=}(zi
zoauMbjaE<-W6P>5v>rCdGjw9H`{Z%`ZXHJse(;EsDsD(s<<FFp+sld9;G<Eq#D*%X
z5mqRD_CPD3G_n{v23OYV*r=)T+L3lE`K&SvV)*!JALy?hTZUNKU;%rVm#Vp{7O4?=
z;zy^*%g`5ej@~8 at Qgbt57V=W1xRnQe`8O!i>k-6M1N8f*w>K6qBHNKx$Hy)=U)b~$
z-JnPUGRAPeC(UYj6e=~1FesA0I3b&?{%&U`Zk=j-V2!Zo#C}M#<DXtRLB3hGY<kcR
za&$edIyqvZ at oe}UPe{Ye(P?vyxAR0gg?d_t8y_nqu#oxO)oV0{sdZMd(kUA6C6wBW
zSTKkeSgi!DzuDwtDp4`MxlT6LaJ&Qoab%;Wc-5X-c+hbABLsdfi@}NByOHGjsJV9I
z*sqRlnPe-`CDf-FpSbvUHgFo#AGm<|&es@}6-nDBy4YpZgs|E<54v&en~l2q8d&|O
zvi`S=$vh7M`glSK>5fiZl1kqP+8`U$k(K>uMwm^gAbG~o9{6wU0P|cD791&(Q7c>o
z06%lsbf8>^Wc-z%L_gj*6)i;=)b8TSqUq&e<7#@)4LV#<%e_3S54CLo+gY(;-5X%0
zWVapBrO~tRx;!6=+9?39bvu?@k0OdzF?O<FM~J^a%ZAtHJB?gqeIKeIj0jJN_4m$+
z7!!9<CYT7Q`I_3|T=>zO(rAs+D*P2S@>GR9enTu?SEAGM8ARBM@#TQb<WcP@?~U_S
zUpYtjn;s at Lml*Zxsr)Q4 at S^4NT3+~&B`&pYd&pybj_QBAPc$|Mfn3!EV>ZK6b<Z<u
z+Zkn{Hcd5yE!Bqa5S{J2dZa|=rQB?bQJ&7)%XG9*u;CJMUI+DF&YDy8&iS>o8OKN2
zM=T3t at y;uiGMKU6+J9*^XB+QgwKnjru&v-r>&%VR6zL_Z7o{KBFggLXUM8oJpN8E9
zkEpwk9rMLTxI1g&&+K=v{q<~{lu0E}DM4joJyvokCL`PP`Q!{4$khHwpMR;mo?JYp
z%4&Zy3*G2Z-+h-k-^4kELx)wqrEYK+Io|*C0<mG>j$nRY>uzgq02-`vF{J~8(!7ir
zw4hRd>rwfEwCN0Vwi^hMu#P%7KTJWT{99sKl2CxXHmE6DYtKhbQYEz#Mk~tCJVIJN
z;UO!4ivxx&KV6fhfv^67Yev1U<FFCDgBe`HSvB|9Iwxct`OYvd?zMQ^%-+|Q8foq}
zA>DyY&Y;f);G at Gk^SkvEF47bo{w$N{n@$BVugQ-L%diYgHSLa&%LvUOu(R7A3r#c_
zUe#F@=?-?_P0FB5Y>Y=Btes&?RLMG{|G85B+O_-${!;NnZy_HTv(IV>q3S-EW2T6`
z%)r<BigA%;N#oWDQgEgY=nz)|iE4e24RN2h22|}%DZjIk57ccH>YSR;z%~UgY9-CA
zwS?YmV at e%Xj`LEPmDi}~q*w)iJMijRRpR<Bc(Srnl7)}xW56*`%5vKMZ~)jVgPu;i
z1R#oe)S|*U>E>VmUC7t=#F5Ig#`ppR27oPdscoB2R;Kw(IZPR+%OLnlMX1FZ)CF5T
zMMnZ%@(4L;L at tx)Oe;)>F~p>(^5eXXeR&p3`dXR8)hFuow=p<!zUrRoXsw+o5D at Q;
zEArxSEk3J`6?6kJle5y!1ycZ763}EnKnxINkaJW5 at 2?+WWLdRXKwZY^#0Cn-S#AH3
zxP`Z=((8YUGqbl^K-wzffZ5>1fx<j#9PutP7W^Vo<-bB3lq8HWD0v>An6we9gv3ca
zm9&Mqe}1*|h!IoWO^h-ueQi2s(EUQ6I6+w+P7<9QzpzY7u|DbRhT9sxX762yWk`V=
z7i*M|c;9}JbCL4dQByg8+sTjSU7Mhy88b)51YQ3i`NIMVZYOd4hT1=SQQn0IJr)8K
z%rsi!%R7S&?SE_&s|u^^!ry-vQG=6qkjuDHJFo0PItv!wp`i7ErS+Tu_+RQBgwL8}
z?kDNG`)1&2;haa{J%m%Z at S5E}SwTN-rjhJx1J#4$mpzt4w at l=MQ?udOJ{?!|^X&hs
zC|BJwK7_M=b)($p)eba3p8|P!<7qCrQ`k-CJQ#AevaAP3r3rdJ==^;Zp7N0cK9jlP
z%wy5Q+={mA@?6O#6R7vZa00UL%*K!IaGjq)tsAFmWnM~yE_$0SjRk17mwJDt7?z3m
zpKw4Js at Dt6olQGUql-#SgM)+es=L{w#oOWkO*?sZfvX>g6tLOs{;PT;)2IahN at 1X4
zc`U<Lf}kEpa{AU}&gXA`!dw<D0o!2+iRaYNWeE979qDI&A5quZ`&**!H)^&yR|2!@
z+;$`(ZU68kM$@b*Y0l86tFIAlM?wTgbiGkRt~l$I-dy~;$38tpJB8BK^V-+TbP)<4
z-1#~V3z{Qtm7B?5S)Ygj3S9xFMC?nH;5IN~04fFC&rs|jD8`x*hv)#ex71V^6I)bG
zBQ<-r=2F?wKihBfYFxe#!GT|TV{gOrQ)V61NdOw-mv(R+l2QB7@{h$>=K!1Z<%wov
zpSa<j7N#sN12oxDf{2uX_oj{&+*Ya8$h~Bksr&@Q_vEoT<(8(ImoAC)Y1NIr5NQ at 1
z$BIs-+i3H8Skk+BlB;r-%Ol(9 at ***@s!0xS*YU at iHRA~#J-RR{oou8!Hu$9rQX
zaiMr^l at ***@jT46SAAIPa_7Mt*;qwG<*+w?X^z42gO{3j$-gSLnu@$$O!<bApQu}>j
zY<j>#SqR&5nbjBsEN!?nHx0nuDSq^yXTPb&h??^3EV{(yv;A35*zjx6+8^VBWpKu9
zqvA-%JJ)V*FdSL{)FUZG#`z&(v$?(s{a!hYtWJik^wCH+1F@*cOhZwc1kvSBx`=IS
zF}4Zr02Y)jQg3ylxc{>g-IGv|$HT;13meIlwhFM*8ot=H#toDxx9tuao<54_51ekU
zjjmq`2dSP at VSr+`HqW+fZA$f92)lb0*S|f15?|v7x9>D%KE^$~)m8#<f4cJ657xh}
zhuUsOk9l;n&ywNkcxoL((`1@)FrD at fDS|qs;<cYlDhN&NblhrU`;U$5$N>M0KxU0X
zv8-M!iqK_`>noJe3}Zu-LNB{;+K68I^Oi=kyW7|I at JdG_YOYqSu1JnRcn=`FrVAhb
zy+KD~ntK*aCwG^&#}9K4NS&GDPn`4@?4~1fw5gpN38l7N#^fH1Ww&#2guT*1fNq&n
zho>lfMEMVDjN}<Tt95qw+#W$oZr=>aWM34Xbm}MgP>Rh40X;Z>mQt_PDRhbEo4>C7
zx;)oO+TBSID}1u&w*|e80%}7orvV`kZ<z*@_9X&`O7Sb3ExkeLbNtkW$=cxfEQ|@|
zx`EheErUrc+Uh;D at R?=4MvAMr!ttt2hi at KZ1t|*a30pV+-INB5AID|>xV-rLDTN&O
z`5&mY^~`Pbug#Q^O%(%NhCBi+y1DS-5wH48NE}dYS^E at P;eu)#=s-!new-QMIt3nZ
zY_Mr*m7fGnQy*iJuq0+%^2#kg-417lQzBu0UcMklqHA4At+C|vB_enNNe7)3TH`!H
zoH^wgfD)#%a5ZPf;wVI`tU==I4)1G~+Lu{>CI_Y!2;Ne!n0L_+OxRF(`nyFt+nOkg
zHN;SK5i~07Uk at z7Dqxa+=_o=K93<`Jxf<6qX~zF^&Fq4yFc`wE#pDoD^SQ8b6$cMC
z<1;o_j{@lS4>dUv`oq*ZcnPI7qgoCHsx!~F_^#L+Gk+AVD<`bTxF4wa?&>Jli5Plo
zc-{$E=gS}<IvTT3vODh+m3hTyHYrjrSx(9{mVKe!UoL%ZTp&KCg;^zNMjeb#GJ+8D
z#XrZ6<J+*loeoqv=sLP|%rczlvs$rwtgddVHDjJ&IN0c|@<kBRJv)xyMAGM7b#NoB
zedy46$XuN7;5uj8?VOD1OfaZRTAw*o$knq9?|N>qzpw~6p)T7J at 8?rl#R=iFj$FGP
z0UTv7$a5qsDPZwh1UE;g8HkD~NoO<3xlKVDg#+}J4UFKa%_FiwV$i>r%|CAA++TK<
z5Mg~!aooIp9#K<6T=1{tNPiUuYC{x6BvA7rjM$cI*;VM}oEf}N!wepDH}RS=X0fOR
zFr${+#+w at C>EKvA#?-+R%e2NfT&!nUu!53H{B?T3D^xr=ji?nP)imnSzFgsJOM#bh
zbE$P_awKv9tbo+phlh4@=_}PMFFyB;a0S1LuUVyVf(en-2krKi<%CSfFk1{Jg%*6H
z9Ut(~XAGFmXcEhs758yOla0(LgiejoFP)$M_YsWNXrCah9!^X(^sr=@MCjMM=Hw(r
z$u`P#-uMZ{m385_=SDSEzc$*MjWDx^Q*>XmYPNV0+Q&`|UiQ>;*q6eJ{V0yLS-$9I
zppJ*{TvGhQf{WgoRV9lrKHFTM9=!)DQmM at T7s>6`(k&KCjESepu6whjao$|)D3{@s
z at PaXgmtg5Zmi;oSzSJ{zFp%WJQn;<GbI_&f;RDwMxkkYUr3d##Bu4Nw at 7hdJAX7<!
zfc4P4=P*xgg(xn&UXKTNRYQOHN=|7h&#BdCZiXT|!2vt*J8%1)bndMTLq#5}sN&C%
zeYSzFHc|9T(c3hH>2IY(EhenO3!T&d^&|gkvV{q(jQ=V1v3W1|bbSv+=`MyTm$9 at r
zbHIgggfzfHTo#iTNME;`$6iv^sRD at pf^e`UCXvU6Jp|>XNg#?z1*gX{Ks{AQaVZRn
z_AL&KH&9Qt<(m at Nw9oXc$l|>d<pflP-@>Ab_?PHDYWmX1L#cHOLHnV=HB-B;36+qs
z at xCzdn$J+6z#tYAoVl3B=iC;sgvfXeg3J1c>@mo$*qYf|t-NCN@{GJ?1&??pOjk0j
z^+vd9zB+UrC90}xT{1&eyjQ#L|9cA`WNx`JyW<l?Y239p%yzgk5|zT!?u=kVW05FH
z`3}}N*gA5m(o6J!P(}Np2T}K1;+A+3k7}<DjwJ2AvADEvv~UkBPSFnCvc6(FuyK=_
ztc63nM5^>0eiE}P^H$``w at bm;XP{8>5j5NtPM{{^?L$p3Z*T^67X5&6 at OwLU)G_l)
zE6TUcT`mkHJ2^rBTC%r+o`+3yxK(jHUAEQJBfYvVrmY3N5xMSU at I^(GJY;v}hy&%A
z?^Izfd!$smKqM`<Z)K`YzKrW|gVc_%<I0>NNB|{RfWi7sL5k`+BwFz=qc9vJHvtm(
zp?V63=rQQSxb+YCiYMO$i;-4#pQ~g`qE&z1O)+hi%J|l9+j;zpZo$jk82Tdv77XZ0
zf>Lez%R-BgJN?21P~l};Z>&n-+rM}qIqd4i+~1<02femiqCp8!GHICQc+8xi at VQAs
z^>X~oj_a&5Q}T5*PHBE2jbz<H%(ncRCqK}peH8a*ez|RL8-*Zic{=(Ua)UzGYh-mt
z?Fef_QdhtI+vX}{RqRyzk_FZ;?i_{LMg$2*`qD!ht4jM2*c#j!_pZg5Ow8C!itf57
zB66gQonDv5Ek5$4MV^j6H62 at ***@9Ct*_Bk`uD`PYbUwvj<|E<oqqSUX(f)E
z;>!hhCXsR&Z3j(L7XVs7%biFNfwP>~psuUK02TVM9Sm`vKRw;)LthKHT14gTJ7V3d
z#_fj^@<N`SkvC_yPVRnv4|w+|0iDJ#ZF8dNovnyh&Z at men^fu2`iH>Si97nfn3tO=
zR(C|4RRHWsm&K(+?e5#~!2lqVcOhkzU`1cSM`baU)$vO(#c5#|HIh#NTvb|_Jb%!m
z{D>UXa88c7D$nkQ&DK>3Ld979Kq@*l-m^3HsquOHmeFWnW`Z4OqP-w24|DH5(E~1H
zxkc!?@*-j}LIkSRk`~!-vDqdM^Uq34IVah=zgyj2&eZ at Qv+R$c!~}obYlw`K((&Q|
zADPcM=y*yc^aW(KOiW at UOd+RBH1?Q`Bea<Y=x-CJ*OgX9u){4FZntGNb-wqc`!yiR
z0kX?`IW at U|ClI3{sDv;)ow_M`PA%9lSxcNiFYAjeBatDQs?qd$T<?CJWs1%&g|7 at 7
zsujPsHBY83s48+R@%Ygas~(%l>aiF9pka$uUBLu5rQNkGsFu#R`*Sn6Lp=Lb`xm at K
zl7~{k{-i`7FD>l(sNixxx10R^v2a2Ty@`XTvgQ9>T|zJ7%l=b at N3XEnhxtsp)v(Ce
zV)*uv=?J1lm0&|xISn$P^0C#-t((V!IlJpmevKRC{cJG%m7_?Au?yv|-^Je%JWi>r
zK7AK#k at U*oGn#lBec at t|OYieifTGa4U5Zk;eRn;Qa1zs#hw)?|oP7a$q+YRKb6 at kP
zCDgzI{J#XhbFL*hJN%%WIvTmWJ554aJY#@&35PKnDD(f!Tg>M;(_zk2)X33y<8pAm
zXgZ7W1ph)ivH`|O-}nt~=RFRAZuTZ?qNeA4qpl}uQWHmxI+`mPjx8~aEeei3f}m5+
zmISS%u`o{3Kui7zAn%VWAG^`~K)0UrqZ9KAQ5V)1hCamm|LX;p5|V&N at +AFnLhJIF
za29)h8}lK|7i&{DF`(L$&<TKOh!%oMqQ7F;FTR{Rb2+nxgbByn=8ZGVm~&c?rWMm=
z??VVnO)G<NH#Vq(5-0cBVc at ***@Sndp0{-kh=QtRxbOGHKCCU*Sj?rc%q))kU6yTv&l
zJTuU~RAOA^$39>;(slXQO#NVD+<kX;+*|P(2|MAn%WK<@zBVOln&$vN3lRmFm<*?o
zL6ADK*<t2r3_&;<;8f93tqqwvGijmyyMG-!#f>L7LdQ}|I~!dXIAM3r`HUa+!00zn
zcbj%eZp9HNtR>k7*;S6}MSv9PwpdYkGVd%`y?aLMi_cvMvyyh%S_3SO0T-I|VtqQi
zX7j=Id#)SDy`~N7wF3=8E{0!k20!n=BOPnBbxJB{{0h+kPAht(i<qKHYI$o3PXtD9
zFnjHC_M`VH2kB<Gl)}9^SBbrB4$9*5)6Yc5iV(J~lw#pHAN%XD!oLArvjv?D7dOCQ
z$C8EK+sm)gl9T11z7 at a17dLtd?g4*6Ve;A7lI<o$Th&zXVRXVIDy%P2fr6EKgpo!k
zTRI*$oUs?%calNAl)E;}a2~j4OV;4WJ<FBP|I6*JbX_zf`D48$krKxcnHz&pJhP(!
zoX=3D`k1GMj-O#^%)VZ>5c at ZTf_RrI><4HM-Zm|<m}`*&bvY>Vq{N`^_be}LMg%&o
zh|(Dn1#u)_+czkmj at hZSx<&=`7`6>%G|fSZO}FdsP0`v=Iwe%={c#~iLsEclE}5eS
zk=^Pj`0xWNBFuyDh`1D=R1<zy94(B+Uee~<+H;(VKx~JkKX<dsX;{jp;_wn7x+GN3
zCa?@^M>+DodP$~0E9;-Wi7gUlX_k-83;&~B*t32?rNy!l4&borXk_K3!-uFP%<)mi
z=H>~LrYOkpg#%*bP%59S-Oy=kh7jf3egSWI+*bA{Kh0WWOm;u^IKs%571uvZ-gCqB
z50On1BB7#Y at eYo9J{NrHSgFqI#dLH|MtljZbM=$@g at 4a5scb@+adDB_zshHe2^}QO
zCPKfL%6vlj-KlJ8-}C#<N5 at MO%HAc3Ss25vruSQ7?=ga>1|82$`BvMejgn6UEXRQ_
z&Ri+IY|EY(-EB|Tl2pD_i9n_O7v(&a3pO^X at 3SLmhSrR|-uv6$pTk_o&AX-&Ie3Kb
zM6d6aXV?zg_29f=Dxo_gS^e#DD}8m~@5(=kU2syEP+ye<Z2uj?987U1KqNYZ7Z8f>
z#`)d`9t_mlkVI%f{!`i*KxXZxP*+1W?e2(XPdDV;+~y~_j6x6$&4tgf$2^D1>z-~{
zgO?G;#iyRn`{g1^r^B$Az>7v(AA$4Tm_|{;DDg}5eaesQJZ~$IK{w at 3q=JeXt^MN^
zd39+W4^z?ry{hfaw0BlF*M+ga>hzPm3HjOMSRVY>7F|CclOD3+?~3*qB>nLsnU@>g
z%zjKx<<3R1lsXhlt}Z4xRmm1zLEMju&?gF*Fvfg6eSKq=CJki&+5$oXu2;u3GLK6?
z>NliHJ5N3blkeq7SwcZGy*`*dR*v#Gmp@>(qB|bTWiM~h#hT)?J=K3$HK1sWCdxqc
zF+Zww7&9rm><r91Igm-M<nol|e|RiT38WgWBb2<@Fv9%-ieEYe+=*Lvt at _SWrBCQy
zEtqtIemMqlIkO+=J9)67WYJK(zvFS=M-TLulN^}@_Zkc%kEQbr1=e#e&U*3NwXL_4
z<1M?2xtvtE&E$Q9+c*l%TUZ7}GG|5>y_T+QGCRJ%5o#s)?!C~Cm9-}Ah+?q}__c{1
zX7=0jMe1e|HTT at OVwXs9oG41P&Uhjfl4l7=`z#eA))fENAh6rYUeS77y`%N|ejwxJ
z1Zov*@a}L$gPI`2+l^|AgXkdCR%`V|BQ=8mAJkSNCi0&&izvzfWxfpKMQr~^a}a#E
z9665>Reb|GGqPUoS9!Na6Q9K at c5`08Cg|2|F~9NMPu%&V*@Pm>43X*6Z4ahYMz?2P
zwYiRu6;nm*{k$e7vm;mp_z>>Zq4GJL+n82RU~s8I-Zs(h-r{)@AXs at orWFDy?ttpN
zq!qfJQM`~JSA`C?M7L`l&UKY{SB4!TW{w$hkV`C0C!bR*hk5h(UV7CC2YHNHAK64<
zFi<RSH at o|M=W(g$c<;e?_MZeb9 at 5XAl~UH7z5J7oWY&FKX3+zcF3xK3g;%K<XHr4~
zG1^*S>E|>A0J4=}{f!OAI}A}t03jWRr=d|Zb<j0gOP-!c;YYL6tF}<LgW8XLE;BTr
zEDXixyk8>MM8H;~Q1BbSH1tF7F6e~Yd&G@)xGVy*Ngt966(p=m7d1XhA)$-O-CiCG
z at 1!zcxta`$<C!eBIP}Zc&N;6pfRUBetFCXfl3Qb+>(-rzDPpX-HRf^{U_FgCT-sU&
zP~(<GHm*KMP*cf%%H>zg8%9dg4}^WH*IxM0aN9<E=#M+V at Vm2=0cg{PVy!R(P+p{|
zY>bhC^4T?2I7YH<_cvo(?}|UM+q}A4xVpqynX6=Zm-$oC1{t<zM)x3E^MTDhPn=QP
z at ZbIq|K~KcKkLrS#*khmOFVW%z(P8145|4!UDiZ>YsA#bjjfik5Wap;fSH1XHeDjV
z0iX5;OcKf?%8-hG*<!LU7(>WD5Y!81Au7TF$H;T%1~uK?TDC-7uZ8O&RLw>F+FJ1R
zL#k}=BbeujE1sYuh~xlwD^Wg1E~%D1D?^TjHe%z~mBw3sgCb4^)<t-$#v at _I16L*F
z=PtKGwr^k96$;Ys!h7ULQWRy at sEah?H4&ObH0mTN*lIZLb at 5D`-+bfOfHwc0 at KiK#
zk*anA85k#>$*hztp8^~SvbWlqAQ^6FL<mdnOSOEQE(_U&>RdmU;F}I5^-YcYwj#-*
zyQRd)Lh+TMRp at I>kqU2cMkhF$ZMFjgn-`7FW&$Dz?$dC5Re2f>vd_r+ST&=6FR1ml
zo=~OBsQZ^^(dL`|dYA;jtmG}3qj5kq)}OjMqF!f^r7$gC%cs at N>?W?|bQe%XA$FRl
zO3it4GL7+=u3$8e7rmz4de-usD?Gg&V%XVQ1l+jazGe;Is8RYV<-RIXP^z*8udoi^
zO(!%zt|(k=)?YSWVJ24N3*A|CIB#yfVe(!+mdx<w7$)nu<C7-SmJjW*^t|9)(|Ok)
z**%vZ^MI62J!a_R6 at ZcS!5?UKC+Myvh1T<RF(K);oEaPxJ5(q3$AoUYc~Wg^&P8}N
zzYJ_ug(moY63RWZn<t~@^d(aHyY$fv|BNk_MG;9K7d1I#J=>T4U3EuQ{yJAuq-D`D
z{YPHhfMI}pG-le595XbvuF?gnyqFM&-95$Y-z^8Kj at s(+{>!KNKlLiT$z#0EnGGq>
zs3GVTVreb9BuB=s43Qqs?ip*GelXq1B1z%=N-XHLQW|f#kuCtsPUweD7#3)bW+3H(
zaXw{LrtSm+{*|z`h0!%_7Q=!OaY4I0m_xPlHpGp(4gDNMkh5o9SiNerO3dF?J2058
zI>Pz+4IY at w^5VOQ3q#OiG>s<pxIwWDRqBQPt_M03l?olKl1;AdhJU>M;X7HwTy#Cs
zX`#$6*W6+$Er2x+RP;^%-c!HnMuoctzcuVwN_RK=<N^G!{~mq#Q}HlX8C*+CeXn@;
zt-e@<Ksr;J<>mPP^yk}IYj!%vh0=Zpr&4A8`zFvTd_`)dt9lAf%y$-Ng=GcU28F4z
z|GJ#Gz*iWnKtq{=UQWkzL9N`jP~<1{cG8t4`PA{E^*EH6{aVg;6``xG+nx}neJZ_I
z at Z*59BRD<0l6a at 5^!C^P>6sT#Mw@?R9&n7p=wlSKKV5+BrH+7xoDCP{XNb;0Nzq(}
z{PZ)t_huiuF}KquGQ3~4$z)+*vw{aaCkT;?$9f4$Ogy)R#{(x#MFgy+%6R8GJGem;
zQ<(_E22FJrqmQC1tj)Zj`GY7}{7~-PWb&r?^Y_)XCR9-2JPC4Vcy at TVeEb*a5s*eQ
zuLlmi0htlM5@=FAo at kbiC?`5PQB`GfLm-K3Q|2XWjgvo<NiXv+G$m;rs#- at AIHyVB
zo>c9}Rk}Vv!f+;bGy^MXNKMOC=kPhO;h(66eH(621E3*$Z#j}>-P-lEduSK$aDRTE
z2x-$L_k*k4e%gwT^W4oM<(2ujLxPGrBr$_r{l2!{kkOa+s`B6C%CDgNQ>RAWr+Ie{
z;`zOFjh6+FDoL+NL-9q|Q(I<}N4}C?Q(?9>eX^Jz&&$1(bBL`S>Y^k$9`85fbE=W&
z<H9dp79Xd^I&XwMfDQxSbo9?Fy;KOKGNlO0EVnCt4$j%<3aCd8kCZK`12X9)vw<gL
zFW8ub^!3~9<yH42qt=}XzI6$F$s?0f%fUnq-_Kia8x-G at 12zWqJ+{OzI3E!(u8sCD
zuji2}+YJ&_33x)ntkK_JOPLib71i|wPLJ$tK{`soHLek|G5lgOBjo8Hs(_y3SSz0A
zX9G74Q9lrB1KXcf0+Zy|S|F2tj|mD$^X|D)ceiRftqR6+P(uiSFA&Jj8y1?`$FumV
z$x;>uKA at 4~x0hEu0hdl5xh9RS&q0HJ$cdc+0b&6;eFcGNf_CR*ug55R5&Z*Bv*T<S
zHBqfQv1L-BZ?S7v5?s+PRQQ!W!Rv6UhG%1$wyhOKRN$9Y_o0(}bwl6t3Bz!pcT8LD
z9kT+%MvpByRMJ~KiDA|gM23wAe}{ZdOoLg`@tppybNBsK=O0Vs!$A>+(^^MHmu<;a
z0|hw at T6ktk+{W}+vt$MOmsj(s=7ULFgSh6cMhU`wAgGpcXN%l}^Su3PAy-D{Qa|=i
zuG1eSZ?@{%E}mVH{<h(S4#MO0<yn;6*P_W_zsof)MHB^}#9lAsxZP<7&BBu|_%=a)
z8^ubCo3r_B*$|oX6FJLbzp12R5|NAZo_bv`L`(Pf-OlC0z_f*Mwiom_-x<Dvnub`f
zY3y!>nO_8!&Z`3zq#SYVl9Hao0QxaxuS_^hZROXm7c(mz0crv31LAz)*S@;NuX0D(
zk=vsydU at MYN0W+2#lIN~bp?L^Oh)lJ{g>LuaSD>ULE4E#?<BiRf*O7V5ltluS+{Bk
z18bDQSN at b%lt1+Kx*+u?*g@~UJMB~!+wyuwQ1`u#>dP`WX{2n7s-4q`L0F^@DO}Mi
zQPC$Uk(<*`XqUGG#(}X|_^HrEfhlgxxz^du{*THtaBlZHLB`kD1n!)z<7CWd)d(&9
z5-NczT$eN^{H0(eU()547SXn)7b|g6HFUPa91nO<mWQyG5-80^RE<VbWIxjB#RSeK
zv{#XENT*)M@~2wI%lpG7Op`v`O!=J5Tkbu!vi_4nR?EG}zNo-IY;krRZ?FL{^06V2
z++?M+_&#_^9wuIocf;=iKc&V~vMEKmv at ro6Rt~~<ND0*McM*eEJN+ at Q)T&6QV3!){
zzC=ECk~?-9okXWFZKPqV at -)NhG;UYizfr$dHsY|EmGxzh?U`Q70c7e{f795qYKDyQ
z$B^FuOXH;}j$O^+>1=A<d|&c~#tO2s(Ov)nyd!2dTn`NS4TRI61vY7$_Rp-uZ^K#Y
z*)zw*^R({2Y)VYMTF3 at SAf*|q`xq7AMve^t_OI@)?s=#>=XZ~u$fr+&6`%NWz$H;i
z6M(!J%DSy1D^fo%6jOVPehY}{{s3<M56f-<Sy>e74-JGy1~Y9Aq6b+(y#ST0`<}_b
zi|bgYK;mwiF5kaf-~g74*W3_<5(PnvstZ-^IhLSxBUMa_ at MoxV{RZ=<WoAlfb3cg4
zE)!8`S~|w4Le^D}#Ma$&nJ?k13lIdlNe3ag&m^=JYogY9+A$)U&<>6_OG6x2vU0aC
zc%YHR584b_<$G<vO*<!*cNZu8Tm at iN1u)HUPbe~3AMJ3l-*-WDgm}ejlOvmH1#R1m
zs87Z+GK;6dhzD%=Ta$!et at oQ_D%l!43HX4uoGq%h)A$bl`*k)w<$+&oMDupFEnaG{
z`ebTyFw?>(`sTT3?8X>$#k=}o%19&KFTHQf`Mgpp^|gW-N#qoF3 at G=k4>UqL+||oE
zJuyf2PUTo9{rU~4Hc_}L_ta^dh|TQ7miDmW{}VKVSNDsqR at Pz~wBv8$ja>o*Ovv(n
zJL}@lrT{kpL5yIt4$)hkg7QH*a1zcD&f#nFpi0!@sl^3X17UAJZ$Z?1#r>MX?-FVP
zwqt3zg;;`0o*(b+w6?Sb50ec89g{TczSHsh`|RgMJ!E8F=Lz%3<!HybK2AJsB`j`K
zi(`^|Y6Nsp3B;<DzMMSH&S4j>hoo-!kEE*)zJF at MGS0#LpmP}}QFK!Xl<_czG(}_W
zex!=zfAd_XmfzT%N^Xky`Uh25p at hz#KDn>Cv(F>~W`iOJYMw at m=c3M75?U0vqm_RQ
zP2!~ax@;MKNjanG3U9ttAHyBm at eOKc80|`wdnP~k6CpiQn<HGUkU1aBZfv2%IGbUZ
zD#VbL3OwqC3Y)yihI799G3bNHk6rA0!Q^44Gq at VkSbb5=r9Jud<^1l$sx{`1^#n$I
zlzHwh+ZW}gvtg#1&qulu9<HMd3<r#+2m84jnP+pO*RKC&nzeUw8TY5?;MZE~O;<W>
zQj%f=bW at S8Oob`En8DlzzAqhMwi-*P<Ct9o(eQg>*V#W;S3d46E6`ihyBg7%X}q5d
zte&SFh<t4>+B}fh_erAeNcdC|tUb8CQdMzAmdC6SeG3|}?Yck%wuZk<*5SENFwi~e
zdOgjd<LDbkJ{visHQuDWvgdpKiQVU$p6>m1?zxWHmd^X8&gJ@$)U}H1_iLw;(u27f
zXu5;4BUr6j63g}t)Mu;Q=pNJYN9tr-yc at dph&;idwn&b5XXNuYOpJ3Gs?4N2-9q9H
z(IBtHuqU`}IVp|&I?TO0E at K7LM(@t9a-PnvyS2X&0wYGq&N605`qU1V;DM2y6dWz7
zkRKupBB%}Sfz<-`I at d?|%*3ZEH(;C^6d(><5_Hhb^n+&a(lkzHInC&goJdtjbf|RF
zab2P_Cw1}szF at gyGxOFo=J}w!1(zsc3X3cef`s*yz?EGIn0&C^SUMe*5wi6R2|ch4
zqS6 at A%mP;3XoOt{@@viHpP>(0XNYNg{Isy-Tv`1RBjSxCdtJr(Y}JuWPIn1dhI;ox
zqPhC%*%2B at 5j}1rtNR$kO%1(FD4*S0k?jIC$iNFt_6!dF@&E4{bH^Dn>@C_x at HCa1
zu4JF3#3TjCQX);WJ%S0^qBF>;EZMEy*fpOjod6e>gGnlVkTJ%PqF{KcGda=`fkl|F
z1M=i~ExP;#x%vB9-}&}{BT&wRs}bi~C`RqDqzLmw?|XChXSJweXh}wQFj8Y3zClSX
z)AMA;oFp-nrudvsr|gb<iM9hO=9(-|g&Ed1A(o?da<vWKvn8KKQZ}e2BP++=?3U}h
zm%OMwdQ@*iX%Ddh2H%TK!tE+ggH1#9YMVUve@#eb+vWQ5>pUuSgG%N;l$q%AVe0v>
zv4eVomkL2wdP=W4on3nwd?B;<SvxZu7NE&WcZZE02mJ55W_W{=rOe=@^q;}HG5J5k
zFrgxkrPU%ME;BAtmu5>?ky)ttfr26JS&cnQg4Ccegi#4{IBSjqhlO*YGgckRS)GV_
z-EWKT;%_wZ{;hbyX*JuNlqtdl33{pKbgDLDAljlzDH!7JTI}wgJ$@Cc13lNTym!vN
z*umOit3-FSi+V^e(^-^9LQem&aI+Xu>?J{s>8NRkezvM8Ca0?ua$?`}kTws2CL60I
zBnB_TG7k6SCepPb!@fK4+fN>TQ3=zq*bj{NLleg)Ph9_gfIBD|Q at lNp3J6wo18iVS
zIkWmw>RwFaNJly$MUv}*e7J>d1*yX+{yT=#MRMrr%Yj61XZ(;XH~mN91nMf^2g{C1
z;BPCsq{gl$NbXK8;%_J)YPH<Dc7JH%q^+1x*VMf}+-t6upZHnLsv7DoGnKhDr2MGz
zBQQWrTL=8?2Af58FstFn#PRO=o|s(GQ33}Xl&hD1w*Z$ad}GeeALhfqNeqcEyeYGT
zI6#|cr at 8=INbR7|u6O>tO5hB(67=1Fs|;!nX#8<(7-fh5)t%wAQ)I96o>NkrW`tfO
zK~R!$uh<*A#gi$bQz!qCtLXQNk1WZZWBSH5A^JT~zeUk|*6!dhvgW^~E|!6C(Ju?J
zqJC8$3y@&7;0(0+)lZQ3)j&8Dd8(;Yc8kKz&)eoXeh+B?MI$me_Ff7<W`(nW+XdRe
zU>0n*;JR6hZdC}UC2>8Wm41)_R({r9;VHUB;4aUvD;!5I^j4T{@mso9F&EWlbhy<U
zd(_ at J37>ewg&)Noux3eu8Mk0FbQ6pAkkS$@M)8RXJx*|GsNI3!1)MGw!ieOPtv;#A
zVL~m;kF*!!T-z at d>LJ+%7ZmWHal=hMp*mO!;Rqs`<)$!UpQwSKJi<kQ-pYedRuXk7
zO+Es;|09eb$KZtbn>`qwOHe7x)PHNOeik4S#o}g+r%AIOc5OlGgwQZW6^&=~9_*W0
zS?^C(%{HwWSeS+xT)*j>DQsk9zu-(8)EQ6(N|6mJRTQSnHD?V2Q$ID}@srG2d{Rua
zV`w%!{0PHtqLl>v6MnbO;)LPBHUz0vUeQE_f|FCZMh?yg6yLtt%)cKXGLgTdzf(J@
zd at Pk$B`OzO*<GM&2hw=}AIhp87JTpCN1|2Sa at AZ&JjS3097h7?4G#Ij30M*{?;IQ1
zu5Jf#2Tt~VieD?gY(MHbddqoOx!bziV^LKlXh?c{)QSv8+daDC>FR+Ny3iQ@(KeAt
zo=|1lFM at w=)o&mHMLZFuC;}41UK_hKq}o(l=z3qE=wc$GzzZtP`9S-rq@#Q3K((oQ
z0~P9PtmrcSW1WSWw)HFqy;=cSON(}L#9_=7^o*uj<j;E|X$Ysp7B^I}^;@E7<wSSk
zcQ2YR7cM>>@Uk2(AF-{XwXazdxih778^27lAXVv~`<!OeXctQNrE^Etl^#^hUZ5Iu
zSXYE;31V|TuR`!9d&gX>exXwws9P$VJXG(A3l*|b+>+85>vSTd)a^Hy#KsrVaHgQ`
zX{+ at tNj|!m`bYB&%<DHy+~K9+X{_B}hSEIB5sYX9_MJAgl;ZngU3a8^NdHETvL-gr
z)nfG(4-k?9%fE25zWC6$mf(I2qTEU!TVFN at _KhBlrByZn)9!rt{k#WHS*?2Gmu*Dh
zZ+vwwkGT5QccTEj8kX0-dkLC`$2hzYvAS?T@>Fc|abc at _U%ns(*G-FqjpQxgi%jz&
z<oTc3)|5iaZJh8xJzJO!-`f7Yv$3}<<-PZ$R3I#==Dk&f>=D8=Q#J3gh?eOaIrO|p
zPSVTjdJjzFI<wW4X0jX?kZOCf?Z*%rJp~`eEt%sZ76!=CD3d%|&{%%22V!}u`qrQA
zY#^$<|9#cOdm6dOE*gsjEQ%K5t2*RtZ|O42V*w*Lr6%^5(;k5)P`~yMKz at Ovui27r
zbFp^be#r=da7OeFQiM8RS`9>xm$&e<F~Rwj2FGbs?K^I-#3Eh at nFvim+IqqP#nWrr
zMP<MWy*t($aUE1(c#}GYafxk#q(g(V;>J at DyCCyy$;ZFP{lTQW_&cAUv2kfM$+1ZD
zl)gq-;Hmd<6jyTFxbQEjT4WNdH8F<ej0|-SloShNrup{J8r9&fgt@)`AaxH1yE~>g
z{C{1H&@pvu`*oy{@K(zTo#k*+C at 52xyR}x6&@ZvGlLuQ9nKY+guL{Sd8ER`dYju8q
zg_Nj#-r3i%JM}n>(%5U9;@QDDUUl|wFC;NcpCmdxq|{#ah%neCqB`aMhOJx)>NGU0
z1%`sI!mr0TZit#e at x|0*nl+YhRu6i$j~Zly at Fo=+1L at zc#@rt9J{z$D%}*|_gGw&B
z`~>q!I+Kn&3YWEdd^3C(1_*<I1Txl}PU|>gpP!Fc+u$t5%FIno-#uqv8l~P!AAqDh
zhi)D-kdvH`>Mz%oqc5GdtOw>AboalhP1kg#Tot9=ErQPUJl?3H>GSo3M9fxXOg8r9
zy;sKn`yyNJ$j72T?{0xIBlE|8AUCp~j#KV3*q<e}*bnjR+jc*NUlU~yN(JY9+4GN_
z?yZAzhoiXq?8pjAv~uBE^1QWXmo<2h7dfq33P$z0W_JBM{}6zCip2^9{2^ZThU0{i
z6Pr~Zg%!~G){(@`EnsxcXpLcF#Bv at txHEj>>S-es9orfKZw&(6U{RuFCm;+DX(EZW
zVH_DoMNQ_xpLv}I1F+g-AH(><D2*C9MSek;*d9kfo at ytCakYMnlooBp*uoz%_Z>Oj
z?h#z%IxE#J=oI?rc($kKLR_gN=ps8<W0_~wT at UYP{@`6huvH$a2-%7`y?wwKF`2g~
z%UD?JwAbi5_%Wg6bz$_q$zvIJg{ltRespZ#<){4s%0qZ)yA#Npq#g8Kpl>_{UT_<d
zTYK8}9<u_F3ng;YRC}GfsPJTTZRuX7jN=f~m~-Th3UJQeXH#!W)_e=uz5(?((8CXq
z2H5wDMpRUQy3M7Z92XD9TT?FepqQM|@9%MN)9D)q-Y2z;-UeyMD>{esWyUq#qsxNL
z<5#=z8of!jb(rBja7(>Uh)379->54zT^{rGs@!~OC!z4YVRd0rZ!YQs-_rU at WuHJ_
z=i<#3wKsUJzw}bE3sr1?(Eh#iR&fLe#r#x7z(6xK>>m at d7WT#?tHoRz&q-JV6v at rN
zK?gAoS|LOr<`CG`EF-mWX$FHtN>K~I2$?S;P8yQj{V)@6KoCl66bsrkt0NVus_7E6
zO>Pu{T^X(GB7-p+s>*!%P#*W9^3 at 6<HO3b8NVjV at 5dEbgWDkci<I|LJ6$gRzQm7+$
z_>L{sbRyI2a2e!k&wPk&fx0=KNokn^12}~hD9QnDB3CF6dPa<y3EN??hO|j-pM-{r
zqHlour8M#AV&<RYxo>~K2sj?F=<F;PS)Z}+VATEQbvxu1xX>$!V&95<Rp{v8EC$V5
zK83l-UduCE?%lLh;eL_qW6ygOBx6#ctSj|YIS%rkUE2L_!_7W3Wp-I8Jw1FFkXs8!
z?4_ap;9AZ~tOpR${oXb1L+!xekh&zzRN=<USvV<B>iLba-xtTwR<7We9RF`vl^6UV
zG~7fW65~^6#hqeB$zEr2>#ZM&qxxP=(1m)KHzdPg`-Jubv!m|Zq!OuKMuwVr*)X3>
zf<;eRChJ>ZyOHdAkoow=T+O&z?K?-*@?mbh&)IVA*kkJj5X$z{G({F_PI#kO2J^z(
zEkh*Ml}o<)taz8&H+b9y7%bzP`<HJH;%M>o at zRKHZpds*;O%gNZ0Gk7AB!XysBnE$
zP$$$8><5Q-E9B2VK!25Ze^9{SB&F8;*KtoFUtQ0gkPY(Xx6uiH6*M2wWu1BM4;B`w
zFo#A->a;f>gnj{nox2Zpt_4E^42J<ny9%WxKl!g^?{E>x=zGVzsVQ+0F$o&iLzmVX
z(sDO;3eOpxzsM<)eZ{rFn)q at z0cBk{cGz(ElQb#bU)HQW!Wx6^;}6$Xdv%01F(dSl
zKQHNF+{O)0X$85_)}gP>5*oh0fuA-x{L)N)r~4;Q!awuohUdx?D8%+Kug>N6@?rk~
zV=A7nPYNVddn-M>A22*jbfuXLqldD4tWvDn;zqqb3&7XD*<Ur0&-2LNZQvFR^~NHT
zqpx>#Y2U&3s*NIcC5BVGegHj-5Tw(XvScuhD#mKxH7DY-2xy0w%A#fU9AyDp3>Vxx
zVVgrQ7<0js>u$6L^0fIh6&rJT-t)r)7B|petQQNheAb(}CNx|{M2trB30jzYA2zJ*
z-RW<9gMll2X79i at 4pYA09KNFiS%?<PcV at 6aUzBH7vX=#snnIJ_XxV)XPA!+`_LP at V
zw2d6G`I(HJ24Gj}`0X+-5I<yI>-t&ec3<&uT=`VSg|GJ+0~lOCT59(!b8+}5ct5`S
z;Ux}5{y#`AS|n)IaVTW6Zn8h25?PYd+0fo(iw_P;XCG|f6>S1EK#}`JQB6G0P8MxM
zbAqmcDao4;(c-OAsybIUvTM_RAm1 at ***@_aPQrBEgw0~UU@*yLv!_|x_
zu_pbK`n40v{XR`^;-1S#ay#c#b42&{x>3wp5_zUy`2J!PXmJQ<sI)m{>A%M6vQHya
zGP)GiwApulhGxBBW8eHLt3M?)F`oQR_GN9zxGNI;mFW?TGoQDQo3s4Q6;YLXb|e2E
zZ$g|_yo+P9mwm6Ha$p(uAs{6lV0Zt)3DLtZ<^-zAlN$!BF|XG^0yS7JB6l#dr=Hbd
z$esLSHt;;WR*Yv$-U}udjz-Gw1%jUFVjrq at Y^UJ?60wrUFif!MHCfVk@}dpuXq+tt
z-!HrOY%5(qBqK{*^+WLfB%7EFOKX{i={T#I_GdfUyd$rc5pOk_567EfXUL<^z9)!l
z4y_nBz~GFrYCW6xt5;u}&9)VskStBmB-hmv*vs^?f!qKeTOX}Ubkho-apraWrT2`s
zO)gq<U{!C_C(SuJe=zYN5hjUzejnf6H0X%Ds3>i0MeL%y%?G#ld0f$p@~Or*xB8i_
zO!wI?@ClUm1hJ_94SOmpD<s0DQ0Q;a|39j}F)*&STYDyU8aoZz*ftuqjh)76Y+Dms
zjh!@h8k>#X*tYG=H+|o8p7TBbXZB#-Ywv{%qmsF$G$Q|{2iGFDLfgM%QZ)ym+RtQx
zFn)jg_*)!0ky}_M&&|BEJ~z&+z_4dGKa<G3m>+IToXor|Ok_$E%MX4IrPugML_IQs
zT7D=U=E_Xu0macoY(6wK5hS0~L%WF9op(A$ClBY|9x9-|sXo+I1Dgaz-ttZj=jZvl
zKum8!s at i2zfr#hupVas)gvZVf$$lH<xwM<8o at zw<YQ2m=<n(EbFR77DY9OYBDYS&y
zZ_ThgXZFSa&TkU~C~dFkt|>>~sCwkJ5EgFcb*t(@WE#=ta8QaM;Bc=dn0(uifK+nR
zVwM!ZcDQ4JUe3 at KV6cbMWqeY$0-bZj%*+I|Aox5Ys)_sON?}~f^4(|h<`nCYifpF7
z6{!gPN=-F@$28!#hdk$iFXwUjqUqQtODH>>AjR5gO&|*vNYHaj?b+rbp{I=VlzAS!
zUf11cI0vceYhH>9Sa8M_<jOr>l%k)eZbwHSPek_K(q2tzD%#&vrG1g=6QALUD>H7_
zujjvkYttFo-;%1=f1In+b|$obeN<<96V~WBfW)zk4a!1QQsjSp#QNveVIg4MuT)lg
zOo*6!69}GY_9^PAa0uLE&<OLnk5QwKAm(J~?1rA8X|)Tt<EmCDiPi}%7r$02DEda&
zdm>9-k|u}CcPBOPO-h*`RVrZ)-0TG0XR_hCO0V=|-Dq at m2kXVU+&qmsoBQ#fB}{1T
zo|C2hTIrLawrMHd6B5OMNd;ZG_f@@>2WWD{_aYk;UU9nI?;4$GLg7Se8l6Oc7&8Nm
zYhE0L!e1bId5`2K(}0Y7UhN7Q-{gNr(`1c27>!WTTWRNhgqG?rXhhIC%An>CXY;5K
z(WqZ2&0q at v)bSKR`vOE#;gSekkcN(RUaf%_k at 1-V6hlppMkfgZRN*#06#!GN{ecHx
za{sW!C#84T066Fc-TU=WyR;JFHsbM6Kqign#J{>1W8PZc^o#*@FGcZ=r7c><025V0
z0IgyoaL^>W;`Ko at z;_D3qfD at yT9)*ZUw*Zs#|<c3RAYKPAJ&_N;N%}$fC_r5a5)yA
z6fhvPB at q@{PK-#%=TBRpfb32*-M?PY!-+ftg&KM?<E>FDN>RE at 6X8TSD%b$=bkZTd
zs{k{p91GYx_ijLFh*pOQKq=k2s|`(S^y(b)gHML02RrUmp{sue!fpJ3hoaGfd=k)D
zuIAnuTH!$byOA^3^xVjsRO!E}8SDhA9(IUHITZSwMk|REK6@==D*&7XoTMVdD`Uxz
z<LxN&vOCG$#m?aZhJ`IH#K{%DF+#JnznXmDs80aj5gEtSrs}Oi=R^p%1j<R}Hvp6e
zOW6UMS%26PhqXG_+Tm^LPJ_|YweG-WH;JXMYXX1vYzaZ*nqc{2TZ_{Yz`oPo_~B at -
z^UVEaJ-5Q|6;1Y2RU%(V2*#CYaemUPtV<gwZrS8Q*%qt#1U=5Wzg7M9RQX4{(-sT%
z1r?fX0md*l-q<u}56Bi4fQE?pAE7$SdbkZN`W1nx{*|ztL_kHBmpI|tRJ6z+mAX^*
zr5fzw?`5+Dpw=D5nApQYBR4SdNGd3*^j$(bRL8bjs>5cOESJ8Eu{EfQ2w)92+~k4w
zOv5f~$e8Yz1aURZixJpx9EUe|hO%#W##jE)${{&R1h5=Fy2<cbK at w8>*E!9}XF&AB
z7}&(~DDF>lUBDRqzzWU++F6l=tFTG&H$)3Io<Lz=r^SXXdoz<)IN)upvjOb+V8k~s
zh#vicITxQp(*`C!nIftF=Eesw0 at bX6b2W)5prl_$fFF96wu?Zw2V2OO{J}cllegB#
zEVj-SZ<;0^4|G#$eknrbrdzsfL;+pCSu&2eF?;yB->Tl6(U&Sd{P(XMQ~v{CM6Ef`
zTh|ACAG_O7mt6&PGeF0R64%8m@}wH}{8prfDPsqingMJk0bb3Nv32nni9oj~4(l&V
zN4l_6Pw6Nk_xjR7IX=uba6f?;xxmk!-l$tdRbWZzSUKqG<@qV>Sds)!66q|+`!|5+
z=|Z2q>E9(gGc at gU6M+a4zExf1%?{tVn*SrUGED#Do%=aV4+Z+X26BhzC~?(`C!B~D
zhjJ+^;QJOA+x0mi04XT2_udjt<kJU(CoZ_I6JT*a;J`-!@wSl_;9T-S^RFXy at rQYD
zLI6AP;T{DbcsqX$?o7M~SEzBmzrcZ3NQHY5geJpx*4AL at Gy}Y~U|yV}fQIuSc~(be
z?d(1Xxeg!pOd}z5&MIiVA8_(>lq0-y4bbF;49!Ac1n^TF_;+U@;E at p7v=AQ}CZuG@
zNVnIN3SG<zfSkbrBLD{?K7r at Ye?4}(YN>}lOA7=gJmhiCVPeVY>sA0EuNP*6W}&VE
zT!vBq`{G^~46yFzMRD;C<^7r_!-%7u;La3i7PyV&F<?r7$SgiU75LTwm-EC60=EMn
z<{SZ#vpviUI!b77X*lvV1~A|Ryrl!l<a$nv*x*@`;m8<wAxyPbo&TFq$gfFv2aHbB
z$O-EjR*-Ffz}@q$1r|#|+bs^)pd5H6z-{=!CkehCD{km$!anfBk^MS^GxD~^(Z>yv
zDg#ttndU98vjWmm)eh+xRZDUTP(Xp|a3a#0xnNP~3)C_I8$fj#<om4|Nx>MPVkgG=
zTt9sVIXbgzzSb*?q6OaeI2+4^essH4ny|%efTP+Y&?Gkjpt~3cxtn33Obr;QJnOR2
zX$trRUY*lUp at 6>Fr308-r~#eG4$kpGx;u$#HXYiqIlxIe(0f#nTZXu<Z#=LVaxp$k
zD>dLSBwu?57@&2F$`3zZa1($YA7KYacvSzDs2kVlN|!wMD5S>O#lO_D9Fge5k at VA5
z+JX2A-%xf&yaBckTRXJqweH*W&j1?@3!u*`fTIYQQs503<4U=j0&)OUp8>in2s89v
z!OhUse9$>`oTX}cIu?*0Pvj?L{y6ImsJyebI}<_`F~-TEgJyZ~F?8In95zk$1{j>{
ztBL3s`B=XP-7QgPc*Dlc;)AZW7~w%Xxn&Vhkr+AO!4<P0W>YYIV(0L)`Y9a8ns58A
zQ%?U=3-H}vdsUxijDzv?!ON%fXF%P)!Noi(z}%s763KN=r4xOlFG at tY4qYVC50XVw
zJBsVWl-(xpyLwB#0rVX$=v^~#FXwO~Y(KnT1<*R0&~qNp<T9>BHjb0L0o=5fbVwBY
z%9+5}awdAZ-vJrZ|4vw+XGJ<827w6lEBQGMPi8R3NjUPDT-S)-$HC^bn2Wr{JqxPU
z89o($;Ik%*h~%zZmvV?;b?F6K at cz2U2%ZZRRVHtgR%?u*@2+fDz`(i5U<b*y?gAn{
z#}a8Y2Vhx9E8Lv}5YX9xb#ck51H*>)7Si8UQiFLB!4Ir}*J1)Leu9qGYsUEOd_JbQ
z!N+AMU=Rf at ua(+*gC}eqOq*!jRq6u8mGh&xcrUiA<>DvM?JIPSG;h9&DnIZ%vn~Vr
zLP(z%)~zoCS|3}X8SA1;bA$j)au*4u24S4M`O at 7+NOnbMz4hJwygL35?f9?$`cbO|
zbxyxZ0a+&eyT5v=s;4m6qyDSOJSdb*rDz{kmOji&$rH93JVwbNa!iTTEr50DwFL}~
z&2F~jx+n-iB>4qqrN^_7Z&s;k)l4mNi~j;4j_+W&=VgLk>A0a#DIf+c)*Jvl$J2K_
z-K4x60P~&OPgiZbpi at aW+$n;C{*Cm6DDhL6{Mt!LGKrYpt182fnL|TZqzF%`%xtuV
zCe&n^(U7a>VDZ(mjtv?yWlq-vM&!D7IRNrk6Dt2|c^-PHOCEmi5O>fBsT!V6Z`Inl
zDVU*Y)FJwSL^5G{a%%wub{apd#-WNyH=NV$cG`%3D=ee$M{AxzPde+j936_pVx6tG
z=zkS%J>@s}DpG<y6Z*xoxSGE at X9U-%n9y#u9^v#5kj(G0aBGy>jAG>0u}d-85yy^k
zZpn+BgT&DStAS&VR!Jh)_bUNvo>QL=PN~Y3nd5MQWM0da^Lg>Fb_z`*5G<Tj3y{ic
z;M%QLYpc=(@FDA$z~+?lwyZsm4Z6yPo%VG&$DO_5X03ZoYtI&hb(Ok<E{17DNFU$?
z?NzbuzULL>NX`0y at S?i-Je*0M6!{c%{?p^Aksy?6g4MH+mfd{+I+!+;AnW(|N*la`
z46R at tsSNbwh>tLnxhdB;n-(#pHcPM3OA&KC5cu$NpAh7pD^MZsY~|eiIsSF65)jj)
z7Nz#nSRs57!ZPuualOzx^}&D*N<&ontT^s4A!SyU9tZ0OmaB1X%ul*}t;^*3F#){i
zabI+q&)OhoaEeis56>Z#E!UBP)^vg_yT&1qEzj`-9qqotR(NfZz!-15_Atb~nWYe2
zQSy!$mpa{%mM<IAr2=40cMMfYN81z9$61U#^S{bvUxj4F6dv6lk~1rR?P<B7jf{j(
zemo`DMWYRx82coiJsMPN1EZM~sTjXCY0)LP7q&@L%z)r=*o4O=P>l^U8$>20mNAN0
zb#rZs&z0SEc`J1wil#rhBUnvRgB8(Y!%6)+d|fxB)s}Z->4UUjm+=Jdbm*wmzzpvJ
zE+<y<OJVN8oKbKy);k}o^5&YS!Kcle6fqXlaWW)vU*&-g#cbUNi6T-S+f^KNqB3kZ
zc;&<X^K~nGV_TvOw+SSEA=@C;2`v_J>tI$1*_0}-PXl#udvD%2P^#ksLCucgrX*fJ
z-9f{vpw!V{^&}de=K(mdDsxb=QXMJ~!gdu0lwJ%B_8)Zu|D!aYY4a|+32?!c`tBP9
zZijz9!HVNI_>BA)IW6-huaO8Y!g3iieqq}o35cfxIB)%W4>3!x4Qn+c(<Js?M at mMo
zW5tOVFMD?8+h8@{7bkrCsqE_5Q*#szTC9a<Rr;lkUy7B=ms*0X8EzvN9C6NZ)5JfW
zu|X`c#^|m24bN`rt9Wc9-({+_F7t8CtTt>BQLg%t59n4Z(kg%Y3%0VFoRW#t4=0FQ
zUOBz9vD20 at ***@K0b0w7r}f^?!)r?gLv~AP21aZblH|HS<Bw!a>+9<9*Ni!fkpC&3
z<h-+jC1aR##`D-Y=hobv(6H#j at wtS0h&Brl${7$V>ASg?3-niJ-0BFt(9ceL75`LU
zeXUm3T~InRv2j0*^}s3X&A`}p!7z_DC1A?>4RNV0se at -VSkiSO?!Z!Rv6aY~rP`U*
z8aP+qRs$#UB-9bpuj^UaWSssG!i&l?&DHAS2wX{xgxW_$aUbY*J~zu);qd>;KC|+j
z-=d~~RKNBu$pe&Z)w1=icAUneh!Rt8RtM0~BuXxP?PpA(&|KxP5r&?Y<_<WGYy3JR
z(A7$XickE&<%R!A*wH&8Zh(lUz;vuVf42*d3c3VDs`8r%WkB`U{?9!qx~Q(WDgxl{
zb^p7UC<p^ePIW<V_i;A)N#(zDDhV>xHNF4Np<x{X2Jb5`vLT*8bH6Jh#)0qDA!s$a
zYp`H`UusOb-S&lEGC);qQ}EB(S7Y~!!u%35{vRB3?GZ%u$N_8Q=s)E&kphB$a0?FQ
z_1~MM5u(xUl}hWN6)-f;K)VeAn|JJEXC-AQCsdI?vE at X3l2`oCSaO15{FY))$wWo^
z6X!=R#iWdhZ<Pq~k&g;<DgoaajBWEOk*XL_NnKheXUY{$!x3@%5>~JO{isEIr9-Xi
zaK#YzbZO{c@)Zz_8H$Nu#PKr&_?rV{B*+Ls6&!$4gc+aD9A5kqIpy{&m`>DP=FC=A
z)hmd_{J<k|KEr}%3Gt(^)urJg9DqWKcc@*<5I}t77*!y*1|+Jz)*E!h(v^^-LgdG`
z|8pn;$IprUv#JD{4nmCsO_G`}!XHPcT_yc{(x#P4qO8V;<F6tM+$u0ND=;eV9~Sa~
z=NrQKd@;8b0X)HfG?k`#pZ$l~fqH5%KY<FQJ|SOAkUIDZ)Ky>Ar2=9mJ>P2>vO=lS
ziaO7NW=h*Sh8`cIIuiG}v3w!ONp)4k%Hh{eU5w8xM>Vl9Jpysn$ncwgLV3)i#T-d`
zZb!mJ-q&-~@!WSIHFDJ%Aejz<CD<!|nsG`%?6vAgOFxRJ>Zuv)PpzrIl(tc`3_7zd
z!Ttfns<-sCmvTHLLsEYk;mS?GT_;(9`|m&4QH~%EZI{eelU8%3wz~>|kO3hIxZK);
z=Rq*4Fh3(<73Y=|_oyZTR=Gfyzi*(RV at 5ocHRXI%MD%&P`SkCC+OYGB)G9j3<rVzC
zMS1((3sj*HZNL61687!<&m0 at i+Ui!wig*?2WQG^&QC93g at WuYPoZBVd93t{NMW`pH
zLkNIpmU09dHHG`z)MCR{v|#6p+7bemWeat+hb<vm0A at IH1)66tDzaT`-y8`##y^F`
z9wJl;U}&gftIVsIvwd}iDyGUwf?7tYk%1w#Tt`LMau$_<mX;OK2`nL=-=&ujO*d3C
zCY%gu{<TZTq64<(#bWUzclx=nwdY}@x-`Wo(lV~~=prCkWwNfCAcjQS*Y at e7YKl)T
zA!QD<peH>}Tg%@pOT0S%>o6;GFws$#u#OG2xu7Z`y8Ak2EgGm;UHHzVfJN05pn_E`
zc<sAc3`L{YOt$mQlAU|2KogLd9Ap7?fno0YgJT8>L<Nx0BKTI(l0x6p(4l~RGc4|?
zQHJcEF9_ILoEheak}s?R?O&)CQsta^XNc&|gNJv?LPFPBDT(aI_p8^gf7%n4Qu9Wz
z)k$*#N!p{VaJUe=RS6;ZnPvjLHMASZ->%vSE$gl1KcB5vu2$G7{Xbi~MeL3HL$jO1
zk28;fx$>y>u0kE5&F9JbDsNaEkxadU6BI^zqX7dQ3`kaVd*fd|P#R7)d43q at LKj^j
z0@?|mLu$>{UmH`_HzOVW=i1d%6Bu9A$2ZR|m7CgL at m<RKerx}6ps!8}D0Hf}f*bZS
zM12Wa+V<*4s`cV{-u%R#zCz{B)pGo~dLEm7Im5$7K(HU5$NIfFRbE2;czFhb)r59E
zM8wK1zWJC}2kB1}*427L0_^p3DkIJiA$3-R$=NdI-9)<K+P2AFPb4{WJ`fe3?JwIm
z81n3{k|%NG21~gz;Q7-aO?r4z2v#v&p|B?Vwdup8<XNW5k+)vm#iMN23lys*;+pAz
z`wBY`8%ytRqB>OHA0797^NlKy{>0JX;0qxVl4AVb;XxzR_JHT{-;k3_FMJ1IB~w0Y
z?+e-tzjQX|c3<9Wrhon7BU~#gV4gpsOix%ssDLNd>(TB>n0C})EZa~@IO)gPJ4P3&
zW;lujh^k34uh%a7P8Q&>ujr2Vo!#Ay$rAQOvf{hZFSyH{OOz{3Zqa*^){((37d~j!
z at aTN2&ysbHbwJ}nbYs)EJgo)rD2a{STBxre0FTx%szrj0FsyrJ5phA9dgmAS^q`SI
zW;~sGOiuZ at HyF6~y724YU3jywQO+!$oY_NP5TRvMr`_-T7-g24VkpM%BXI}Hk)QUT
z5qMI9@{W~$+38X|MTN1Z`;FJ5NjR*EJXBnEUpk>Pc)F!SxvrkTF6`OzViNm4&G>2|
zSqa*~n>ere&)^b`eihMh_2g+?GPqYB`Pwz;|9B9~2Twv_y7BW|1$!+cka*zo2H$Y>
z!_3reFJmJVJGW}|lI*-ctLbdL{(efYP{qo-gewnz$C=x^6)v9a??JEGZ_d1Sn$2f0
zRx-Jkp)Mu2osm#Se*#Lma$4`T+)nPO)>=!NLGyO&Uy_}VI)p}?^^=JFAdkkiPF<v*
z%RU^A%*H~!g{d!eAHg2~DShd7lIPXmQ=L>X0M(quVj(QTLx at E*!ryg{AmXu^hi|tH
zFHmD*V<x>R^|)t*am4qy{zZx~L*DeEGY8fG3(;vBc0~f1Uu_rMLTUwb4gQk!qIVCa
zK?RVah!jxZt){rz!E~Qa75D>_<5q|R(veT at S?op2ZD*VX{TbYL->FaXElUD8OXVj4
zw&gNE_18NtNPL^Z%rP>hH9pWtg7=z#PRT4xrZHS{UvhOq!5x+T9amp+QN)1Dw<?w9
z`m4FkMSN3i*orXC%ctaD0S0YnvrXMKGMPPU4G>zB_;^G2N=N9&KfE)ACMDZ0-L<$V
zZ3hGl41B`T%&_i>yOewPiSTK2lvjQsy`U?-TCUB1HBs766Y=87;o}CGr2Lwt8q}Wi
zYWT at qy28~NpZKhOS5z3iJ*YWv)l-_K!wuL{I3Y28 at a+JPhXkWiS>c2Y;}>LqZORqX
z)u8H|34b7{=?r|@s2~;mRqE|(#FC(DUOmdqIO4ZvyS#N3$Hnt at 6Eq8w8e^%vvH at Vh
zewdZ&P4RHcRP0J0%`<&s#kp`BNm$`3>B1Sg(|6Z%->i~?a=p_`g0DKOW56hloDZs4
zVtp9<pB>$7$W!Un3*olJM3u2HBzsGT{U&ZJEFr9K2#7`n2Z#|}8&+nwR=Eg4YuP=D
z6S;L7TAEQ3CUPDGmM7^{x9GUGeIc}f*M~^rqgp3|ZFP7PN`?@`JjeQIz%d`>;eK#$
z#Zg&v0*n1~o~M(ypJoz6OON&4(#1$EXQc%2&g-Fa2;($?3W6d-gAhW0QcOKeQ|WJ<
zB4&4rrZ`B0szoPQBnSxTS3L!Omcln?z5WVhdJtw|<9iWh<$HU=)qE}VaR2{Sv7qa0
z_Nm(#CbMTLDDAvc%zhyT@#Gn)YDgag9{aT7X+Udtlh0Fk at IHu$4rQrJiD2O{7LQBF
zj$Kt}xj?&bi^VjsRY&}(pcaA83v-|QeIJ}Mq1XGC$b}$#!G`X#F{&MQDH$(gPJyS&
zp3C368ok605dTRJ=2_U3sD at njcYC~v=3V(!`9M!~^gLEVD=wH<PSk at S$xM%~sZ#oB
z&^V3Tat&e57MW||^2Vn&PBgETG({0<2KS|mZH~SRC<$N`zP&~gjH>wdZnf)V;^vKU
z at T|Np3zVj9GREZ9a>OCXWZxU@?N9midhUJ$K2(H~Z#u*<CEWJgvAW(-?bk=nqy#;~
z&f*t&#AVK&g#e6^k=*kQ5)a?a9Cy@;S7h$Z;xPHmHt_TuPqtCia;??D>oVcePQ2u9
zej>6t)za+w>hZ{hUfryA1ee|`=gWI^ooQ0hEGIGuGf4N_HOpi7r{30W+L28myTsI$
zG23cVp`FXX;U61mFmp!LR6(4)8E0;|7zuI4x#MQ(Ub768wmB%~-*}JkG@($qM#jdT
zCA^Ih6>9Lk^4`sL7nmU0o%B-FJqIXrI=rm at LkR+v#nenP-?6o<wyN}wAu3CUPf}lF
zKm<Fw&!cy3KoB$LUt>(L at kM>TE|Y>M$M}A~`^iH+``&X$yBnG|^P42Bermk2G{Zgg
zm(`69b#*r&1vO_obP46T<{F=$rYyR!JN`yBAtlq#5gad48;52|CeA3@%5j|Ja-bsi
zF3Nq_GuqM30EG^}0=`1ev2v>p9Vw!ywz8v|t*tw-9MoBJ3z*Nr?%pyeb_sg$WzR!8
zQFTZsY7_=_LVphvSrjs(EfOOGsXeC`Jc_X%nRJoeiJ<Y-)~9N6T6ZHsUxP*vuptlE
zGeuF#=&5(ax#T?JVj>ed#t3!J_sez6INAT7fW4AWR0U(F|E^%qj@$wqR{#9rE36}y
z^$R&#kHkm at gjJAM51u%9&7OQdw>2~~Xaf`7yrF=z*<L#J4Hv=d86^p3C4U2&g&YL_
z>HeTN^3>_JDU;<i2}gGI`LWZjVK=@&hFL9zHxuQGBli++lsrZ&cD{Y+da;(_u at gdM
zT166HTsS%mElfzPOdzPBI4!p8y`5g$>p#rz at 8($`hvG`84^!SAqf1cB`!T*lp2Ak5
zN>>4pVWgG3H`}+^d1(DVQ-a16WK{1%q^H;SMQPUHy};(pKKvig_^9WJQ_y&n$6MZR
zXCvR=lD<k(<&0dI%|OVUy^NpUU7G*|<Q_LRuv{73yog>MD)ST}g#GK*z?tKut(?Zx
zYZ48^RCs(g(R*l{fgL%m*cAs#q at zj+ab|dJw1(a+^rR_6#-0O;Rdg0SRD$mf`o)LG
zT(BQypttb-Jx<<_wWXQ^#FR-;(m1?9ym<QT`P|oiU|&yLlC|CXiikJ+iDuK~n#vZu
zaCleOkS!*Oa9G6dRmLVbC`1ghv$L#sALTGVfBJNhl;q-`+;;E1kA8QiOYM2O*8V4n
z=}K_IZDZ*Cd5>6VAcf7u_T*>=Yqz3hQ*N87aP1XByae~t=wsx8yd;5obv?mFiXggO
z3kiLNTqeZ&8AOf}k(1>I#7vN+x@~k#49}89gN|Iz5s}=+k@<+X-%?tcH`ID0f|Kn=
zqn~Z`gN2xNiEMp^&`ffqp10)=9+S`S5@!2n?k%%VVDaF$v<FJmpAyDh66t0$2c6(A
z^cjph2ezwoqY-AOdTkgnHb2y#`EFSfLCa{TmTtUZ5Klna2YKCRmKSxTLKTLT%}yNS
zD<R{&TVHE{=I<BZdrC{~NbTqYU;|CA412n5m(#FDpGYED`YsLmPeyFGpGCA8rSnd}
z?}&r!^WaC$vjusQs|Iuy^>GqgT)+7eLrv#2iOgCVz#f54<bAyiz at py5W(yVNMZKuS
z`Oz1lhJI1qTln?}AaK8LxFWB^vgOM=$NXX|#Sqr&_iNsAilPANiwQ+FOs>l#PYoAQ
z#9l$(y3`l9MpxqK#&Gey^jw5Rg3#>(Aq}-MF;Sbs-`8q;E<vN04yW?n*}Utl?CAQ7
z7z;iJE;8S3 at D1xRjL$1M8wcHPH2ivLr41Z?F~o-DNB<~Y&n%jaDX{yK?^_oF7v-k`
zQiVWIf;0=Qi<8BGvC6JW%I8$X@@&`RFfr?vyfn)6q(&7gflbp>j0fMPp2Z|Zksurw
zfhZ`aZ^7g6k>8tEgu&2GCJ!rH=5#p(&J|^@yEMl`Q+KIYll|$Ya%3 at ZX%L+e5T)~Q
zSP at 3Ivedh;d2d`7=fM-Uv%yPB=@wd$4Lw2U(^~@117>m-M0N*pz!m?g at w4}QK5N<x
zHsjJg^OATTMV6tenw{>*R5rw0ONPMiN)oSx6vEwDt1sHjglyj}f+X5hOA9Xa1k{n#
zdN1^7zda8U>@74HaXj`@OPYizCHJ&XAbn6yDo8NbE<;WE`2s#f6Cv6I|0lFA06K_e
zorhl&f4Z26bP4}}%>$X6Euf}Y`7RA`f)mm)QxEGnZJ*MD=Rmd&i7P}cZKmb7%a<$J
z$d~;H=i at 8zJ0ta)swbbLS>VGTvZB{NINRXG5}!@IjOv+7LMptOoYz^cCTtJrAf}Hf
z(#R>Dy9%-DW4UCj%RZGl*hp*0Vx#naJf`~*^}9)o-7UMu5($()+9$}*U(5s9_xW2F
z+0a>>_eh=I*F(R*Sqx`A<)*kZw~qx0aq)ONr_$1u>~`h$UE}}piFEnJZqI5)NLMK%
z8V5ZM%G<{0^9{^9mNJ;W+SK6j4do?WakcWT^{Hq*opU|$qlmVuC*J&u1KYOJO^k8(
z(1bc}qOl3M-i(T2bcG!+vH5N at PN2IoXq7Sb`jqy?S4)m;kMTudOV(-Mtjz0K2=(IH
zmIr9vH|ze==I8`-2gbno;D9~fPj0>PsFmY-b5 at I?XI;#ADyXo0B<4NzFneztf8A+d
zhiPMrAvI#%b)Gs2!Rh>zz{?5clHhw5whgOYRJ%x-4~|pdS7wpO>vU88L~0EY(R8O;
zyCs=kzi<G$)2)$yo4CksQ#(@qyr!<5ijv%Aejt)sS77ylk`bIr2uK~-5LS>7Q6sO6
zgDhU|X}4_>>aTo<bR9+0uztwpvw<6<zMo~~GIk|b2e&xhg);xtLlfU at HE1ek2hhO_
z2`$P9Sz>C2fWnI-NXfY;nO<?J*r7Cz(qa&W4Tzi%|Nm&ikPZ)IsIRiTQsW(ym~guc
z)Lke!O|%3h#c^+z5&6quv-pnm1s4!dQCo6z0Mq#-D8rgHx0wAmTh`I}>Dos>=C(WN
zOj3+v9KVvpdR(Gx#bko6T}FIB&5n29C*7n8St_p~tg>1Lcu5!Cu!!U&!*dc#2KO{L
zC&SQ3gDnOp#Pn#ED%z$)j<|j{QlIAm5$fr?a#91iQuB6?h2Ow~Q4E=RP0q75<f3I(
zB(pi3Mr_!&HH<J}Q|t>1ttKn;C at j^A(Ns4^WX*MJ3pB(iW?L(hanId$@VRsV6=qKE
z>kqj3_+VF|4d<0R_c0zn_+&kaie>s at hevd&So!VQz)Te00Jw at p&(oDM<bSjgqfCRV
z8X(oUQnuVlD>?)#)$;}IYa at 8@!4uO|2gnu85t{Td|4ZHB*ShW5ijB5BPN>hGQ0_UQ
zgOP7LW6ce#QxAu#`dfb!yOK<v^C at DWV+V5ou$SqkqVQ)sAmv*f6yNMLGO~gGIm*<+
zEG0glNaNwisYE;dC844R?3Zv$Jgi;Q`I%%gLxIrwd+j=J9;ILjeG9hAW9Nv0 at P`))
zgrS)d>zRs%nO|Yb%GKk1(9v3q+)%KJcv=e7&br2g%Cn2IE5|dNo$&u8cA$f}?#tfC
z(dVFRS189%Re9ig!ZrdeL_Hl$kHXOA7fwgnrb>%5AvQ!c!SD7p?jL^WAqP!t0v2W;
z6v!Dq_NeYHay<yJt)9gB9DNXQdC$(>!(dEP{4p1;*G2zx45OW8JI3RArPy$~475;9
zw_@}MOX2zxq?2UfiG&Or0!}OgpJ{~=4zm67-BK0_pwycnQZ+W>)DQjR+}D(eJ3r_B
ztikG|=(PS8=1C<+4K2O){>C6fD@)?%jFPV8Bz|a4<u at xKk>Hv5yb>F<IX^<_4;Kxo
z_%j(G5~)p^b#A-q<sX<UomRX8D!W$AvJWkJa+sPf at Aml34i%Qe!0ZSA1BG<#4I2-H
z<aB*W1O0*&$1~rc&~x><dT4;%FMP1)o_L-eiFig(tJyoopI_=oUVD)6Fg1G}m9)g3
zRj+bxD#nAUzwL}UIFh)%kA8cd3~8I5TZg?4PP at jHn)@aR9_-zYH5Bg7*T+Z at B`P!;
zgFxVC%<i*oV1$0OqmXV}$I1}kvb=Qm%-G=fg74&$!A?+i;3F}+b?=!`M01<Zj^d?c
zoGC3ep_^bo&G&BE)jQz3F^XKv?pDQt1h6H1j+1=+l;}(!cX9mdm5rgC3h!R~j#AOv
zn;=>15AWG~<tj9?D-CkB4o`x)swOXpw`O>pL?dlJUEp(K-i8;ee`)~9x8$h4>w0n;
zg7dqmfw(!vK`(w3gE>DQ_gTD#`Ye3)!g#;&6apWhAE~MR?FlUmNi{KwX5$Rnw8@!7
z%oP7r+qs&|aW!IC)O>pCc1{+(L3Ri6a+XGV)JIC`y*$G`;=1VcpuFyB#XX_Ea<Oy>
z{1D&KxIU>wjcIPYiyU9bo~$Kuraz~{Y$^{=t>N4+e{a?9`jv^stJlF){~%okcCW6l
zxoNKYd8P&;A)33JGkNoM1df~_!Dg<W$Io>v^Lfb-thu9QM*Kwe#0oDgmsft}O(HMA
zSO&xQqwHgg1z~m4G0ak>mgIH^6D1f968Y0b&z567_Lu*bWZpl#QS|>>Xm)-j4vbhl
zxt at 7|$5h`Gh=MrZOw|N&kdRrMn!k`<FH_u9xCGz%&+`-L=EqW(4G~>_Zab36LZv)6
zi4Eb32sXfTx9D`o_8KyjeGA*)-Ff{ooKtZIl`k`TxxS1%By720${?k`o>(}l#iq<x
zalv8w0132Qp_k{_)%urVAv-W at 1XELX-@puNCV*I4=bQU77B!m}MvK6^Z?-|3`Kk$v
zR&%y8Y`EjKJK*loA!Ook3^5(642>WRiTdj3R#6 at 2*G}jAbC|`%ld_I%4`%=?HPWxQ
z0D6tvmSa~a%W)&a;d+a at PR*$4T<*ASkJVA=49<HPla%^J+yKmtNmjx>K7t1umJIwJ
z>ke~X{QUOSv8 at b!NS1zs)ZoGeKz=pS-!IM2EP=TOBi+lag~ulO^^?ZAmKgIxxRuFj
z8(r-M)$Y~!%5)5hBJ|NbIs~xdv`BWfD|q<!gEb%AA{9Z+Y%hoXWTytU{N>r-rhQs1
znHTC${lZOFQ;-hUy5vv-_{k1-UF_1=;7q at l+ik=Z=z>lIz;;k+66zmv+BA=kDk?id
z&{HkxKTeiEOB09j(-0zfVX?m1l4a%9Ngmts1$ZVi^hsENktc0E_EV>PyKQGBp_Y}>
zLl#}A|Eew(Nxt^~7G3rViihy|!9x#U0?gtrv!fgRmq)n}JPI;%ztyS7!K?1{8C;3C
zDKZ8%M5d at bNw-bcAM-urJ>s0UpistSN4>G`c*{q>{Rol-4{_sl?Y(_JDJs`qQ73CC
z+hv<{8g_s(Uiv=iq6{=!%kW+>aGYd-rGJsnWh%dQ6j45sbUg~KOk7vlG`2~V%STI8
zNM=$h%Gb)HJ{0OgS+E^uZ7Gs9-!G0hEsl at Bwy5qW$17X2D^vCblg8={bsRmHsKdwF
z)gUaVw-`?ILmVeKS|WKxKOUs2MserS*$uU0hZP~2JI$v|7&~Cg at 0z8D_M*&QrAv`T
z<fhNR0f>w53_kBicL&KpD=~eS7<4z%so};GEky_%_g`jMo3L|4?_Br$)!s<)^HfrW
z10vU;uGZaIggTzj*jqS|L?=pUjt#5PH_;;zEiy~0JnEowRC0M?>Qfpe+QM=3EfZjk
z?&I=Rp%vPi|5hB>tE1zq^Co9{fJ>~}jrcI{VwX7sSA at k7?>|A|7sQcIkcQQidu0$c
zD)CdtVNGfoWuy%hz0@%tr@?;Fxl{b&7(E`v^Yt9vt5=&jX&|n(f8Y6Km<MLWOH?Ok
z{bt;{<FB5UXv0+C|29{UWnt+BrM3qagk=^DVVRjycAD{Ar1WQ7!OoXhf6gn|lBY7q
zJ#`g638%RFj_OXaR(xT~d}V<RsmTr_gWTM+Ae|MCd1BmrBhOQ-#Z3_k$I~&UdZL{&
z;{f~N$j15r96?nj8(U;P1GPe7rqoGSQ;BCzdaf#Vzc$>k3QKxRbvR!xwjy5*sKo(P
zlDD4=*dp-vH^JbUW1J%fq;XN=XsK(+0jRPV0{0V@@*)IN!4rtBHcoYNtFQc`E+3yu
z&x>?PM3Am?Ul|3ek6)$N2^i4n`$GK*u^eF8ZiWpJaI2YPn!Rvw$LlkY-KuPf(P&T=
z!m6YEcvMd!RPPzefSGJM)dEWx=4<;3Zf_hE=p-S%d%dH}=qyI-Bj=1E0l_Y7k%4>1
zV^8)fMTvH3y3w!M-wbyHBvSfma)hObak8v_(~yNy#@Q6AsuGULd7eBDo**y$a%fs4
z;j!K$LrLWUjTdB>;9O|R7ebMEl6B%_0vz>bks%lr;#aH at bJ2O$3j1KWuCoZWh5jkW
z#Eh=Y!jwlRXOR($uZVS at CO<xVD@!Y|pCk2U^ZI8`Yt%E`%d=?{UbqlC5cJ+F5#Fvt
zwbw?Rcl1Cc5tkISCQ$VL1AK;}Y7Y&VdxWH}a^ibl2E&)%t7j0e$L(x=-cvjYLWwf7
z4zVR<hyXJ+v+hUv-|0-0PpO#+%0ujzHvI0z)}3dq!fX;69P3Kbx*@UqvO}I at 1D|n~
z>4mz7pChWl%9cDK3{pn(iG@${O0~E6w{>rN;9vZ#@oZ~NCxCIqJq-95_9%g<vKiRr
zqJ6L`z-U%SKBMg{V6wtbG9<b#`nRY2J(xKs`cyBo&xv{BK)2YImrxNe1aD5EYWQeo
z at ***@zHeOdi9!oDtw8jY*@C9_+yNLyyK9k#5FE(5j0kHK^np)Ma-hO5Jg<FAPtK0pu;
z7fAj%OV)ID(|bpxYhu#qnnf=pW7o3<fX{Er5dCwB)zo%PgH|qta4dg!`Mi3-;{_jl
zy8;E~B2s)>)717(RTSYS%8=0<#xP;c1Ht0kduQ=F{n1YJ|5Ui$Ft4Jboe}6H2_%PS
zR1dLq-RL*&t=3<A=cwWa(ZV$2E at xglpC_tvISvatZKW)bP*?GqT+9GXi{cZ6zL)wk
zA9DahQDJvco3zlc=yY2&rte)<@=Y#XWePtp6%%DMv<#X{hZm}G`*XR1c7MsV>r(Ku
ztm%a`Va?rsr%ayDVJG0PweA^rlrFpn$5xp&WD_}4L=o5B_x>Fo#6i)@ZW^ioNGi#&
z!{zs at 3`dkNaa1;kg!xbmM^fA3)MSR_QgYp~ja%+?{1OkRzLjq;{iPMOdr`RbRzbsS
zcq8|a;pI|Xo-cjWTS9jz<|<TM*WjMfk<!C$jVPb7OJ)tSMLPzihm~l^=5i{<SwH5m
z22q!jv=fDK_Ldi%bO~})F;;tJ^LLY3V=Lp~gPL{pFEg2#N3lx7Ni&eKb;ArRqo5SY
zxYS%9W(LF!6G<ruQAU=#WoNde_7?chh@|Ea<8;|`(<p*|oq+g!GXR!+ev0xMH%)5w
zw{aoxiwyLN%g*=ZD;XJ6!b!-C8n+O5C<D!w3imLE+O=u)o}qo$FK&KSKk*DD{Q|jZ
z&mPy^RG$3d&?pB<OeVX2zzWNnSD&cgc_r|7;j!WaUmi%U!OmXW at 71;3pqED9Vwd_r
zj|H#dk4c`+jSMkbO7N#>8Hs&WMzf66a-}{^Yc!=-zMxveLNvAzO%)y$Ded*bE!#X`
z0 at r!?@_Q%IDWc5SH_S``YTr3t(&sLrSh)>RX-6xyqJ5`e-9#som8W-Dwp{(ie<Z2S
z&qm at jBp0*#OGw<t2(m2c&$u)F&JNViD!)DJz2W?C(G4;F2>#?v(6Pi7JOPRJQ<ey%
z at Pc&Fr7mqc{ovUC_n)@kOK(#%{-lkn3zMAEluL7syK8K{`^~=-<VLX;naYMh_gL^n
zh4DFam2LQ>E>hU!+dW=POx!#P&r`(xD at _0`@$1L<SJ#Totu`n{Yb!;O)Q^fTShT%K
zuZ^iK=+h>e;l3FwcKD+3(X8M3g9PqtHDq<nQhnm0f1}RL#0Ag_UFZy6WVbjb^3`Rw
z<j*M47B+xeY$iDQiXft8JF>MLg2HVHEr(h~<8$zXl}38EuQO%PgRKhw5t;4w9rXjQ
zNc4w*VC}N**2~0;nTCyPh~1^gd24?SA&Z$dTg#mx_9PV&?|C5kUOQRF`f&(qfo_V!
zHCu~G>vy$stWRDf3U-$$n9<*cgU%c3tx(l|DP-av_tA89TTouD>xD#etM~d&e$Dvq
zQ*sTwwq-V2uq?q_pfQJtD@};Ro}t?Pl0mR28TP)%&(MEp@!mx!pDYF7c<$`@?U|K1
z=-{BHPBl|+Ejtag at 2xV(f#N_7ef=z$2yV at cOi?xgwL)q<S2>Balnr49x5GuWev;a!
zgv9D5Uy$oeMKJv2)@TLhe`GXZ9!u(0OmJ@^*kpYAv4{HhPfztXy#F1B9Vo;+&75^C
zLd>wtLb4$hSI=#ECk|88tPr>%7<VdPHHPqyTXr4QkG*gCI(<T#C`XoVZ2pjGr_(){
zD;<O9mjQMq%Z+ctiR(yeuCV(`R+~)%&oc28=@){}xM|tE&WX+7>O at Jk$McE+O5^$D
zJm1z_{=xfIjn9i;`z!gQ)4a)G<xJm6lB8g5|5h1>jkneAe_~_iS$HIWdL_%_-!B&X
z^Dz-HAFa%Pq|pTtx0&G;K3e0S=@xb8tPZ28P*y)i{-<Te=1uC#YvpFDzkiT30AHfW
zG;4-&l{8k<@4zYPFedtwH0-3H5 at Hn=q{xbn at C}gFeBn{jL-QM;@;zzYw5D=%S`<r8
zh*-e)AmvRy9b;8sgirk_iUoVZsR+W!16^ivk*B)v+&0dU6{a$-$W?(>PYX0|%~(xT
z7`wW9+&L0rE_F{BPQGhsZt?bIU^ETeaVC_2Mxv*9S`0ooX=`{cs!r>UXss4sv>cUw
zMAc_SCErZNGBctj{V}A#dscLc@$!|wX&RB|sjh!0L~Q|VSqKveH^)Y(ahbE|>j1-N
zb&a7MVDK?2RGqRGRh|8MmB(Tvw4PI4)t%FR{;5jjf5~KwheHRmNiH|$F8_TjcO+xM
zZ&G9gE)Pkm+1*&8-p4HAuSf)#DTY(RQ*X;tRY-rSHM5o5KIbZZA1qh5^STu`u0pIM
zjLC%ZTEDB_hAm&^Dbr1Q^#FaPY24ZOe3;-j?DK`H@{a!9>Yti(JtAK!Wf!#xN#Eg_
z$TuSNDG;NSZ<XSm)+Y!=&RNtF%*S2R*h6%-{93}^9h!Sqo`Y7hx6 at QYySH=5d!)hO
z%(%MCcgF@>{}WBlgrntLMJ=;MQ}3Vtc;l(>_~LvQI$JJlowf=6s`n}u^Jb`2awG+*
z$vuJmR0c!fekWB{bfOfd{)8mtRZa2pw9&?kNQT^H-;$=h^1<ad>>LacO24E44z^;U
zm#xQV*^Xja%63niAnD~O8nxzXZZ*oL?XMZaoy4uB6~At>3e3!y6H%le at yGC!&X7~0
zUq+M_91JjjL|dxrGh{S)!?e~X{Up~Ud~u~_S;9o*$R%gU5j9gu at SFLAXx3_XM^6&>
zP<w~)Y|Q_FVvC%7ZEZ(2jfn~oH$X_h9mFW^>R&l395qN!Ir_9cEX+~R7?MoGW at bfo
z^n_yun~UKA#)DMO|Mk-T&)`E=kZ+8-7XqF2r2jkHI+SU^$sp0{^)%87Y+o5axx_;?
zNoO|qxR`m^y+|8=_|i(83y}^J`1X0Ncp=1X_j6X5YuHY%+c%M{rMSi=P{9v9!KyLN
zw#GsfmpP5zZhKz;mU0d at x}W7MOLjL!C)h)@Kb4J&rq+YlqI1iyNhZjyi1NT6j(!s!
z^_Oty1u`LsKc(mLh_9MY(WA9XQm00lEWK?1;-5HJ!iiC;3#}A6Ke1rgJz&l(m;V3L
zb0tR|<@`J%_Dpx3*9w)fTPlcCC78|)js?|@LGpLEm&XI~UW_{J4R#%I1_+uYFK#_l
zvCFc%sb=cECjl&j5q3_dpIQmtFPa-Dwn~jNl#A^_yDRfdz!>g5QS0;y at l4~j$?t{*
z(3R^P#bbf$g^f)>yyE(2SQS12Pqa1JlpsAe0q4ui at a0j}>j_z-V%|0EN`Y1h=>W<o
z|FYt~nQu-|@eHbgyD)2cqN4={Fpa0tJ-DlOW%hV0ZUYW>G!QK8?}_DZ at ***@otS|e&k
zhSs)B7*4d1MUb~ViC at EF>F>F%R#{mgp`yaD)VOTTl4gH&)`k@}`v+^0^CKefGOn4V
zC6&K(X^7XPcOXwjvkffu{9MzYPSlrB!`~AO1?|pVQXDFANfdvuzb*-pN1gvrn__^c
z*-jQqFvPaKi<7$BNp!=7c*VyE%pgVZyFU at S)04VVR3-YPPG+<55VWGKRanJ}FMgK%
zHO8&4Uo>XMw5S-&PBY at 1P{Q^0pwyq5;Jmk6tI>~8jU(kN5g3kgzhZRLGW(vk3XT#S
zU`KqW|Ls}*)i+&2J at v;9Sq5K{Z!UhvOf%JxD!z^zQ97mc at yyiI{|zrxTj~O`SPGNx
zUD2ookXb^|a->Z-wJB_V9$Y!+XEGQuWk-<EvztT4<*a-do}T>_RmLBX4ySsP;I>9N
z^~zh%&G(>GSRdjwq&_ at niiJ&^)2$#j2?|oRS#A16X0|LRpq at iK*Zh}l#bx82M-Au6
zT4<GlF*rOoB?bC}qgu%LpT^ni57xr7gQjz*?US1=>PJ4*aui$lXcEo at Ce791APP7_
zl{zw0=LkZjVLg1A&%&SYfdA?2)$~POSwZC*N?q>|^pM>s_0Tzm at q$GnI>6QRSxR5e
zJjgJ+o^7*{3W;05#^$SamDj?kw!oEa2up;)Gh|gr*aqo&ER?Ow&~Ke@?CBTOzis{`
z>V0LhMv?1bjOMW@)Qk6CT4yHQ`aBYNw~A{0Q?Z{pZ5Pl7efj;BZN#Hf(0xZvw`3-H
zPe}!IOX_|olGP!#Mz=~Ru6z7P{_>5?cw?_`va^{HiRVdOS(5ye>$_bQqoj)=jhOZA
znpCPq7IhLEQ(?KX*MtG9an*2VIKsRVwcNhrMGd0(8&NKe8Acei;P)wS6$+Elubj^^
z+O9hkiF|5ahkQ(m`+TM<hFs1UDe?xHe45$+cb9F5w8IxP^UXdd{sH%FU}?u1tWzdA
z9r#uIhEXiK0d9GB^C8%Z(2h at 1=Bs3x-{rzIIg)!+Pwd at SmKF79L%r0-Mg06U+X{Tx
zQDpv at 8~QtyCS?R6x6usDm71P$VtfKC3pg9G#<O($l3Tb0pK9E1Rh6GUZztLrEi~^}
zaz+_phz-h5hLnJqFukc=sL+CB24p8_i=7&@KjPZEopkd1K|4T=gcuC at laI>6Pa&e@
z)E=2;fJ}bt9j;+v@!g3S9osa`x6$|RkJES;VO6%T0S}oQizv-PF0$*yy5yI8^2CUE
zmK*yQzw`NrRM>5BGmeR`L^ErpoHnjIAq>xVqIykl{BK#5VSKacRmmy9H+>N%_8`AZ
zkP)cGWUnF%UP9;F)~&4!B}a|_JTd~=DTMW(<*RZ;-1Y7FB|RIxY(+&1XS88X&<(aC
zU0u+)KXO6#M|V^))Ia9w?(5UrgwNYhx at 8%u-zt^4&Jq+SY|^JJCb=kEV`zKF=+U~e
z*iakzgNcV9=#1MH@`R16J}Y2st~uChf2-=r7A1b|waf9w)<g>(xCk54XdxpRm@}n3
z5FvFaF|-jfeu(8O3Og7xn2%zbE6BS={HMD)Ye}YXH3HPYKl(7+t&tPeveQp7o#MI#
zt%(o{8uf&I+H;>b>q<=#q90>eFVClz|Bf9yKttvwNp^ze^(*UfZ3amKSeb&kA4nz)
zkIkDcdi8|_lh48hzEZpGeZ0v at ZqJ$c^jne&S#Sx+Vx*w04XFc#UtWqiFOI<gq4^!1
zc<zddaY<VLXir1V;ox;jxRNYVR)aQmVFW{+fSZUTB(CXNHqP^_2+_fGRHeJslCRGj
zuUYLZshc&9t!JMt7g4#>oJ4W*{Ej&)EvsDfe>t;IA5!>Cq50X?2bsF^`3F?kGxZ}C
z#h2T)72=?Q&xHA5c8}NLI?OLDwjZoV<b>)^y;6eLYf+&Vik{R|D6|9P?aDqxa|@mL
zI|aW~qC6JG!A)HO%`qXlsu*LYE3?!Gt*WXP{$VXJUg{8X*G-aNJ4MNm(`7rCuitsi
z8`_p1wA5MiNXzY%*CP6$jQisYu`zoro5dg7^u=rDMe~q-@?oVAA1D4gBjQir<YS!K
zFmfomom~a&sTT1JYN73;_<oE|`8wYh at q<kY4X&?bcx)RJ-o6$^pQ1MVHJGcWq^brv
zM)Nu!nRo}Be7#d$mv83-No5(+5D*3a+<aR{Hj+c`PKw1u87!3yS at _!YhuxIN><dda
zTn6eftoj&iw9esB3`;h>8FuuIWcS6wR?I7R+pmY{pCIXjjJ-%&13bGgA%WxBlD~7e
z3uSJi6J1OW&35uv4_Lh5`EJ*cp6}8X){F#uuQ)@!mvPlk)HXhkDLHB?a8FqXi6jOH
zdGXOU3F-6YMbOgNzo1j+5Cx4}lUP%=It|OpiQJymi5Fj=lZ0rwpl}&Bt+Z&#%bZL?
ztMmL&V<l{o+V<E(aLU)%Y>38@>JXQjEM{!eViP==f~#!R?4_;aB=)bcqnbpb7Av=_
zE60g`d9&@Ex>DQw4>2tGm^ApYeJP~@TG-6;>BqI=I%N37gV?C`d#bmThze_e4&@P2
z+8&CeiKmBq4n9cKnk7>vh$UP`K)`fviK1E7AI{Sx#y>Ed=1E6?JO`%;=!)sSr<!1X
zuj`lMYAvg&CYhR%XVs!0nbwv#`hkDw0?L>`E>+i=CyGAdl4H2Vv9vY}fP;88Jqnid
z%~#~kryN+8%CiK!q2!(&+^vgQGD`cV?uXm=wT>QWf=?{0keDU*ZYKGhYdij#9d;R3
zv8l+Q^h8a)trIn64*x!xL8_B&54yb>{iTU1pbLsvb~tQiAMMXMi-byIK?=<^O%91k
zc^6uX(Xn8+j5W;zb+hq#l41?f5t<}+$AXtKhmMt+o46;q0G`G3P8Wr+5!o8vS_*8V
zWvA&0Eu;}byh^oV at -YLAdEgDnvfQU>0Xq+0S74$>n9QClO?<Sg6lDI{CENe|K$yuF
z`m0HeZ5XFtK_pV0Q6s_Zqr~Bh at 6r34%%O9&f>jX*!Z)v;QPPDs5coQz(HGcbqD_T#
zx+kA>4GD=HttxPLI_EG5I!{15dUf1*mf{XZXoc(-wyU^86-!-t5=7eO>u@&5THD_T
z*WnsvE9`^JgZMiy_Zt5XeFGT~4_^mKf3(N6F%A2Vx$ipVS;c2azw(WFii)s)hB{56
zHFDjNJ1ScM1A?sMAOvfI&CLjfdK2`qm_q~^Z+?Xftf`x$78#CUEctw_Nxk1!#Jx)x
z5?Q at 3x_;YsAxt%AyN59 at 4)1Is;7hI15h0MCTcy1&NqF@*0(sXl_Y~RPn4Z0tCi!L(
z{rdmddds#b*tHE*0Ridm5D<{=8afB*MjAv)y1TojI|u3R?(XjH?#?~B)_R_IAAA1*
zKFr+16=z-Q?5}3(@f{tX=4fAfn&Nd??4^drSf)7F=Z(PO+0XR<K59biPJS9%*pfbE
zE60}%T%Q%e9-RI!?bNwwNUJ;b60(HVYYOyc;48%a!BqPI#`jOSAB;uU4_!OXHPO8w
z4fx7ix4b9j7?P;VyT}L+HVA+1{a7H#QMYy|N`j-UR6;(zVa41ZU}Oo|F#OOpTCGzm
zB(N1%Z)MB{M2kb#Fr&y1z%+^Z^*dnQ6_rJAXo9wf^L>Ox9xc9qb2`A=m*7L);x`9`
z(F|^=m^|dppkT<6QBF}vYWl_4-XAj{>|VwkzL9ajK>?YQz*bQ%Dp)J^1arwnYFgIf
zutNT_T$v!C8twm<!`r!<t8YAu^j><g<L%#_^Z$;wV^6Y({7Lom=y?_0C79M2rJW63
z<sSQ2@}9z>wReU2c_*8ChG{yip$=S~{lZ%avaFYR(LmGZyseh=q}*N|%1gNqYBhV`
zKR7ql*-(uVYejhF(nJl8zfl;VNUL2RRO3qHK1zx;o|^7-LUIZ$6s)%Wph|La%INws
zSWjrc8^Ww3v~b37=iS%)E=Q3Pjt{m^@G!_u6reA?5{2|ZE+Iz|+r(><Ni>yPNK%fE
zCPyainO at +3z<#^s^Uwtq;^jn6`x)k_ABNs{K}7Wlmb1)289j_lw~?fD4Gj*XVF?z~
z22<A_k{0F9aBFa))7Rke?~AVZCvAikd*5I9$&^~%-M_BHTWzpD7||JYjauqa>)QUx
z%2fGqn}}{eh-=trKks)4h64+wDH%$9-ip}Ek-r6;$QD;Tuaf4+-v8<ZE7_S~&d7&*
zi|in1;*jJz$`mK6a1IZxLPIpPm)RGOU8d|+P4}U&Mu>${Vf2SF#2~kztym8O*@rVQ
zCEC{VI99<z40rAuFW+4l919~>BbV{mQ7;mw8k_UFB+}-EkN#yW(oQvGl_t&9O}|&1
zAm}E at C(GMDKBm-?967e6^jMZ&Xw+oYPUkMhcgg=DV0AtrK`OOZX)ySvSb?8a?JoiQ
zi?xKpyh$a3F~J28WjJ$#job~s&m2SchIhG-d3mUHS<LIqQ7;GMj)jwM at z#lV>pir7
zm%EeBk7*f)K+li(!p$O$&utL7&_|NQCFekW7w3740Tx#jG at ***@9D4g4l(m9g32D0*t
zFx at 4{{HPA=4oJ7&=c4||68pq3)ZJ6k5X7$%G at Xa<sjkr1t2ieUkT6{kx`z1=>US?J
zz}5Q5iJ>En_^92n#!WoyKa>0UO2ayib6X?8u8Q=RrJ<#AoAeWeI<idrBt4V38J_p?
zoDd2p`8&#J_wo=jZyC7clS~BUEnEr}tx6z;;(N~%#QFRwABSCnhoIp2E}@eGt5c=s
zrD5KhE815~4X0EM at 2SWHy}lUo at sjE(YW at zCfKott_QbK#u+a{b4R3Dtq(LQ>Ny&&%
zqyD)0958qBq;-aDe$J}+8_)Ez4`{_2M1d^QX8kf at fI-;77)my-29ZXsbTK?jm_#&=
z0<Z2U>=9a;dpr-K(2_Ftc=8>kkZQY-p=9B<^a44honJe)m`d20P-K|rm*CZ^wS(0$
z1hTHT4=lGOif)}fU{W7F;-!~)j&f8n=)c+tFpf(NF08i_N&s2*nBNj{9#~wEXHlwv
z%_5qG+~`1cg9VxN^j9}r9{OT|=cC#$daF9ZtF8*rHvNUWpBIMH^tn#*2t60)vg}F+
zM^^jo)Kk#`ioIJy3>~$zkbR2oD4b;N1o*PKGRAWmnD!!#m0<u|J1usf<I6C5LXb=g
zuBta*1KT$RB}APzAAtP at H{{~~X!1K>i%*^&IHe<Sui7Mz4zLcIjRBFBh2s=2ShoQy
zBD*_B;#>vl?;GaLQ at -|yv&?AX--LHf*2;^!^AAtEIHnv#wm7dMz^pJ;b|apY0rc&v
z$$Z?#vP6m?`eYfUctiAu$>->~+9!q;_{(p8oft3Z!_!wU1YPzX4d>`Wq<QU`;HP?2
zBXENcsk&Ilp~j%^NAvbAt3NTPwO_U$^j{{2P|pqQdWBLi`?0{>E<QzZ-FcY3h;Q<w
zavd|$>bLS3jp{1?beoQSzb^|Mj}yy{u^oZA>4150*&5Mq8J^r=F!@EtiAStQq}~3D
zC!sfa;G9R15-G*8XODGLHsy;#K0eU}M~mWsW7R#_H-!K52x`f!=RcAsz|4FYCoJ~H
zXK;MBgcJPUZ}<QlJclSO^Ak*SZS`HUl5Dl=P#CUs#foU22Xf~rPLtY=xG+yVXUeTL
zLGAR{uwKv6UYs^3chCfYGwMzy*82yO)iOO9zSfPq*$au&Dc?^Smv~JcUz9-`T7$)i
z${BBB>DN=L^ME5w&(AFwe${uKy25GqnX&|m at t=nuIK!hPau*ay2?w+32{UDCzBc(!
zOjnegI*aWcPWGI^{R7vg{<vTHp~tzJjDFeDB`HZdPE!u+UTK+S{vA_>NpsMFTCh9I
zO|eDvsa}~=Ns>F`I!F{l(cA4e1Thn4kS?`VpH0enI|N7dSL@#Lb9k!@p1@)FJXG6l
zKQ6wXb-O6G--gt at -z(M6`qqK8?&vthL}@LWS5pN-UB|GrVa%*@4IdOKbqmNjo98P5
znRH#@`bK)9`v^Hj)%QD8UsNTm3?aTpM(DS4^(tWknw(=B-suO1lhcjY=#LS2!-ee+
zHyh5db>uESjHP-zEU at k5FNc^2vEZ5N at 9Yqi)D>c=H4%wtGWES7if?l-J(Oa$P5d+C
zB->W2W)xax3Q;!J0Kvm+WH87Ib9Bj^*73d|Hlgq#KNDCi<S|(ot)0#5%Ttb+<lW0u
zH6Gi1kjy)GF2RF-=D>K&uh>M84m3l#^QOBT*!m7wMla#WCUa&0<L=Z46krU<V)4}V
z-Y+VR#(*=r(o8z(&;xemw&{Uh`0We7NCZ490Htf(6V*O@%4#TXt?^=SSZt`Y&8!bC
z^@awR;zxa`!sY^ly+wW$1h7AE`WN(pIUv`euzlT$87GDUX!dvhx`wlBc7Zn~vn1_k
z!8kAqNi^N<u&|HkqRKbuu<+evDpO=_=0^ZZfKcvb!70LLzB6(0gg%W5&Cc2Ay(~sy
zZEmyMzrctMA~S%d+-<`{D!H|ffZ2q}3V+dlDeOh5-;^K at PFo|qp27~I=>W=tzN>VM
zF3QWW+}@@Hc&e!=o};`>JMTB*RkX(Xxj|O1nrXnVtI=45WiuInoa=rHAGq;O*ocrq
z!Jou5qR at 61i9N-*R~A1AH3m8n0Lcry1KC!IK-0n8F_AcfUhQBJ#?}s2;8j at HPkCLk
zXn<#<D~Hg37|_zze;;r<;c?n9y`o#tBqTNFhB6+G51hML^eYgoLK_ovpZKC)Lv0gW
zy%Y_jvMmaKnZxZ2N)D~+2Q!~}VQn_JJa-fKDTDW__(V%!LQH8hw0RD5E!y9~;<SR-
zxYT2AIXuFdQnR-2^I*BCPYe}I-jqktm#r;9zVj43uWj%)mxbgeq_xk^xVp^L5CpLC
zYTRt0L^jC_{UuJgh+;hz3nGrz4vvsfvp-yQMEnN^h!9g+H%}3d=+)zgZLXofgA at v7
zVywgCjV at Y8QHtQ%L+d84qJ_86h%%vWq#iaMQEHFZ)4@~po_6%LHt^=ZWuet{8H3ax
zqR&!{hkxwh>SStvFFH(8bs|gBeacBtOJpc+3KU+B{5W-+sAiOgZ7fMy4!VKf?*Aw!
z|GRv3$y`@Qf>J<qHn^r?27ckz?Rq4`^yhq?Y^p!fu=5^_G%)c_X}O*i_jd$(l)E7h
zT0}St<pvKf^U-7!IzBL&(68`URlMHKrKs>o_hKJ-Bf*Gh*3VN<?P$Mv89DTJ!20QT
z%Gg|%6l=<sgRDLtgh|z(c?9wQ_jJ+ehd1!p8#$;toN%fe#}!Xx!oJ1>q|$Q?Qr*&Z
z13{lk;C*v(!5F}WP}3LXNex%3ZkmhX*Is6)lS*)<q+UI(UG#EbeKmxvoj^TdHCQgj
zKJFTgbFiAvUh(LQvVX(~(K^|XT0ji4XRRa<PEudHX>TR9)U3S)!WpEGj(Z~7XCi_x
z$P-Q7TE{&p6g<>}KJ at 3Eaze-BYemZ-!ZGw}n1YU`Th8$QEtWxr0$a-RPPS_I$j~iX
zRZP at X5Gz%M6;!zp1*-<T#}4^OaOVBqC)o&LDaj#7U1&_dHE1DlUU%9E1Lm^?t>DhP
zBDmwpy2z>p#kurj$x_`3<;495bH1B+deO%$H*S7H99NLh4EaJiE+y0clgtJ;`=_nM
zcaZXV7CI+(JpoKe!uJ<n^84*uAzRxMFCXXJ(#+it7_T1L#_gVXKmsvH`WQJk4^n0s
z*-X+1;q&)H?BDkYLDm5q)$!vF^AU{rCUzPTw<!I%#uzF;7_IRLA%rjGW1xlXZ)(Z}
z&}|#@MFNVOZtY%QQ!?BB7kmnCbfyqX|HI7b{=-3IgNx<N=L{=s#Oxh_i9*g+ue>M8
zR0cAL?xB_92|Rj=1iH>f0bwNKH#Ns??#J)Z at yeK+hsk6eW9sM(p0{h9UQwOfbXPqF
zJCX9J&<7~Crl~L*=DWg~@kJND26RykeW+WhNUO9*xD_5g|FkW?D;WF2dMMy}*f~#C
zkUO7;^z1jklVYQDplvXZrsZuh{d+<!ZvQA=D{s`D_#Z&Eoi7)yWEKdDGVex)mYx;U
z`zDSmhB=)n`ABD`J0I)x8^a_oWWC}jxnQsM$Ez|zMxu{{FB)TsA_7FR*r%g3IlpkE
z?gd62vsQgIJSFe`*@Dr1^aEH`Vwi32G`%2?Ni*80&aW4CZOy4(<Y at B|b&cj7>Fg<T
z*BdUe%{8;rzmZ+c$y4V_+p{`<&)-{pj9;FC>ww6w&sXqKLGVoZJly#t&%#9K1R!<G
z-Mo#Xs_&6g<3Jt=Vht&5^^zGFKuuj at 4jBYQbDhCPcyx`>Hi_vi^$3rM;o}y}uCPg%
zCS=JhQvp at eUMdui{?tc1R at Jrrr3N!$Q1ibmM=GZ=a+}p;EA&SGAun!TAO3O?c#jXJ
zkY at S1<hr<k%|DbQn61^r(-Yd`h@}VVZ2K$Xax(xE_VZZu+Bg4bj=Ai_=4#U_)U#i8
zBLn)O7iYN_XDmkSpW!oF`oh5adyWj-ec}yRnn4Q`gM4!S0i~2Sp*|=)H5mC_7P|>b
zd)<3K4D`n{kVXEi=V5_Rj+_y at qGOIQS%G9%S4g<U%x~MZf7Jn2K}8~g;Y`L26qhjm
z6&}us>Q3;GSEihUN_wUOT+H<93hz%2R!#KPFy-D)^uBB|*0{4q<N1?4?V#M>Ah%!0
z5i4@&s`nUNkJ*Y|#fBQAJG>v&-jfsmFeMso0}%pc*Hk>3d{oM{0|NLw!izz;E?J0}
z#N2#wcSU6OXn at OlYep+IRaqBVU_O3cUOYBd^w$e_gTzGqF(Rla25H$l+IfAB3k#nb
zU=uLNmOzP5M!oSR`721Ffr*e7j)$>#IKOG~oS=3Rm+_dd-T~^iq>|HbWGFBR_kKn)
zz~%=&T#CPNMJ(6j<{R|?Wf%WUkv5qVMV7z6yzdqTXGU*)d!9b`cWszc5`mKHq7~!J
zmS&~CbY?#cg at Jo;{6*P^d)YL8FWg^Lw4Eg3lHgg71T!Fcq11dLy at g#?Gjg}k&!E<S
zPmZrTm at mBlf%W(Bqr5}(#v=Fd6ItRNG8`kbOjfZ`Er?0+_N4&QmS2V??}c801LM&M
z5T~2h_IrNMs~Jy<rm%P3>lt8w@&xgZC`;x-dB1`#zF+KRopJIAuXk4|>1nZ!DQrlO
zTFxnJz8H?vY_y}-ppZDxkllUwh%m5wR{o2TOyaEqW3$WsmiRAZ6=e;I4{Y8!Oa3MM
zP^sHc^yy4>1N%PmD|C4 at x!X`mHjQIAT1>TsWp~RVEdY-3WgDk2S35I7kHK`!DogDo
z_FPD->LJnu7sa at U!|Sm5AB6}VOk8jD-TKGx!{?I{1%N2xKshm>TuG3ZUiB{Q<(M=h
znHd@)eMkWI51>(b!l>?^v8{Ek3JUA{yd9B|&NCfeh$h_Jvu_V4|B{5$HJV_S at WaIZ
zj3cRay at cjv&>t-<TS8uDEGG==9Tn>{$9K-d7z!{L#x{|s<}uNFFo8C&%-}D)Xya5;
z$HaqH)?Jk{!rorGLeV98QGJJl_ogIi9cjMZKu{j0gQO;^wVk<>k58`s!*1he#KYpO
z)24Via`WRoSzKjYnBtcs|CY^h-^w|?jBrU7DftDf!vOk}0sZ~97%*m=9ND7cAJyt?
ze>i{lFUO#{!{iuUp^@!rwckR6wbdEI$XtfEg4??guqILrq+%Y!A~E(%AGlGWQ+X&?
zx+X{uN?OrJou at _<Jqt+sS$+z7wr1>tVZWnG at yn5uK7ax!bjY}52-BwtG^VzD3|;7P
zdG}--8^N|DfClNS2^%3tTrGP_Wm4p)ze5(T&TX&beQs%i>o_a+TZ+cyOsYU=;;Ts|
zk$WwI;}8zro!IzB at lnIN+DsJ4m=w{@Wegy7&m*0%g&X9mESweKLM-(P$OBb<rQAn|
z2xE(}P?wk<Zlc(z&dE=5;(|VDdSlQ08;XhlQ_{SUx$IF+2k&6UaX}HpKqm9GTbi>G
zN~TX~lXm$JN{K2B{(l+W%P)f!ug(}&hn_Q_LAgGa=mH=2#d21bN<UGQN4_jabf!u_
zv|G!Ty~Wi&aw at a&ur1**uukq>OR9_tbJ?zEZmbW(j7`&uM=lM!0Z!5gesQBjAc?&o
z7*uB_=4XpDLA-jsiSOdWoet-`Qz$mrU!x1p;<q=_6p5Pn-Dr3G^zX#38f~f9z3PN8
zk9wuq{&|c*YN!Ik{5V?EUzCJn-SMEYVE?dX4-ctyfZ3=8C at mp2*YPoNk`0=Ojx6fQ
z;mc+dOvgzj@$K40?_|@dQobYw+PK38{RXyGqRb~rnf2+f)R8?OjVaU<WTY}0`j+|E
ztnVG{4(l+vxh(_oW}tIeQt6ys=_<9=!V?|MHd?x&_ZS%ZvW|bxyEz7PZM|NUe6ZuR
zgX*~&4+R;x;>l{@$>-H4?ZO>1fjQl1vLa$cx-e)}sjedH-z-+iK|+Ba4L=A5{<L$>
z-9`LvT&}Kypck82y|LuAI>Yg(@*krJ{5;s1pEZ$CerC1#NmB+j&l>zj4%r)ZB%_UA
z)mVeDCO$7JiAh%zeID5>qYb=Mz!zyV4W*5EB$rAkjRtCO&sba*vpDD3tP1x_Dqm~K
ztXfb;_Ly>MbLkGO!x~J4_cAQ>%O4r)m=2n)X<630+>?|Vq1dd!`KyMCOXY<%Ax89x
z4=z8(*nuFmo63^l4Iv8fXFE8?{Y|z6{9ha55|85)^DNxg{+$+BZm at b6$aTBZ=l39b
z3BGp!$j}TME1$M7O_2*Wf4|djM=yAJ0kQ9ZJ%jT6!vX*uDJj<HeUUg$4m~<T_G^L@
zW1`D<-K__?$+UR{Et>TG7F0By%=$Y_hOUP&E)xpMOoK1V>1s9i at AzKlZNlo8^3(QL
zJ at EmKOAs0XRa5|x>ka@$O9eDlxT>{?da&e`%DU1p^RcsT_zgHPT`c>kpVFp!dZ2UF
z1}cddq;_alEuLzCPz;Y~4uyCsH_m#0FD;rmhk>D)6s8V<lqNcy-JFC+mlyFJ;Wo8K
zkic(6{F`e2KYlfzff(-v74O9u{5$}#5S)Twr~1b|po0=mWJn?4>4;w|Y$fMHX_;A5
zy<Ib-nvy?lr))bvqu0&^(fPA>u+ioU?4{Lh-{N)^vFpH6)pmswU0;ge7XO#6JlfCb
z17c)tNKPl&!>K0E6Cj9iS}m|sD@{KvOqtDv&!7~~lbSNauDE at fp(3<#g1r^3C7))C
znTE0FEO{cU(eCI8`k#)|s#?Spj)3p^>9oN+7>LdkC$kQ+i?eF<{{V&{ZmEQ`^eY<V
zwmVgZyt5XnCWl8D%%QvWMe>X}*+T^uU9*DlaA5N!?I7wfKRW4>VoG6)i*GCreY|Hx
zb2^0bK_<}Ock=@ck`(LwG&;qfZuX*p(O?cVpE0GGwf=Es+=6N%Jqt>7wm<@T&)1o4
zaQ8vWSPWUGl5M3wVF5FPbm_y5n8U>rbgqXo;I(8+qiVPiOK=fO(@1^uadA-C2_5X9
zNnRCE1-7npqaMKuE;hX57s(jwzVHSvp!shkPx!xMfb;Wz|7(ydBfXC$$=tc|TCBh_
zqpx$e at O`MPZW}y-e_&qHJqI2mDgp+&z%w^|MM;vB>V$of-?!Hq=H1W%&tPutw=yPS
zYci0iFg;@>**BoBaF0PdbPv2GMaYKhFh}{uhi#V=9 at LWsLXn=lpm4H<w|^O|mVR@(
z289{P&r)Andq|cxthKERF at 4WRm(0gcE9fHD`hD at F-PNr>7D+$!KN06S!*Jg*ymz9<
z=XjL2<@PZBkBO-2UQu%vS at 22qpR*z4(+&FhRLy4HYEEolCZ&cG&AAxHr9vi|pd+M7
ze~peaRRU2`mk*#4k!YKMlvZ2JKm%1)&?Z}Wy_YZ_Qon6QUrkjWs`GrM`ThN4mmRIc
zE=HCGh_IVcMO0MX`iJSVJACnyMz*(v7-VB7^+~vLP%K%ZAaK0~q7Obnk0IP}%1Cnf
zH+CUs4%+<I;BHEka=>gFbY6d^=%N|Rz$~o?mU{Q7&=$C}1adhIjpOEq-74>HoA`Zx
zGZ8;e3%GxS_>ZsAkhsl!<d0^^Owe~uTKrJb{bx>sFdFz_Qc|mP^6*{!uf#T6??@2a
zjB!)la8Ac+1))qZ{-AwFo1;71qGXpj%5CPma*?CzQY2%nd6h{#JYw45*KtZQ^~8JF
zzCi`7VzIvF{&^jy-m)4G20YKRPnrhQj#116V5^bzQ%?$_E&!KWEhBf>zN*^pQ!fZ%
zC?8#`l=*C|#UFRWKhc^eOGfK4OLuhOGn4_}9#Z?!95y433E6IXL?;jPxwDUGhjXH$
z6TC3|&vCHZyh_O8)8?i9zK7!q-539Fb)UO5U%!Y>pvmh{%S;ENesM`V5Lgn>yuRHM
z7Xt$YDI)$y!aXq%t+>wb^Iiz8uA+J2M$^8px<RbEMr<tak{P-d-sX>`={GnOQ+6$?
z5Nxb&ir4u}2oQjU0tD|ZTkB>wVYRc#?&spp3H2cp)^|7+YY-eV)KaFbj&OubcQwh1
zPCH{*<U+<Xpyyc}ks1xh1Yz)gTMV1TGvkNH7;d!qsX2wpcOJ2>&gmO&8sJ at yak<QW
zcsyZi1^qh?{6`S~7(W3<6n?lnW_4IUVM`*6=2_DDO5y;YKe7kpR_hcq7epG<k&ImA
zti*#_owDTHV4OiV$F at m)3-kc56&l=2mbJT8+v(+PO{?43jSIEQ$F#g&24Hc%6!U`g
z0_Ows at fk``_M8yvl^!RwLl8Smd-aqhwLw!nGhYo!Uq8=_9SLdT-B=bqYo3fa2OoWL
zZ}vENeBKZA>&c5jjaI&zo;*A&aD-u`oPrKbebIBL at cwnL*?|V|PI6Y>&oFAxv=drK
zglddS2Ap}gUJYN!j=+J_G!5f}dauKQN>9dMX(L9PpnoNtPgNc<(2%&eK99VUW<Oys
zVD at 0tiE{R19^@Ek^HObh#7OF;p&hbsWYvyPZlQh{X;z&)(V~EUI(VWz at TG1m?o{LA
zYu`vvHWLP$R%E5)Trwns4V3(wA$%JuyVZ at 3ca^9VvIT8VD=-X>h=Iv;&jwl at ***@y#l
zI5;Ak_%_Os5?WoBX_;=oCKza1eY#4&#V?TXb6;V^(&zPd#PRwsJPw}H{ya;yT|sNY
zvKrJ9Oei8anHdL6MV5NgtaB{(j(<`YQKT}Vp$MPIu}3xWNCLeEh6Q!Qr|nLqdx%PH
z#yL57H^a|+5)AaoZUVp>o^<j^{vd1Cxu%<z-Cm_FxOhb at SCeO(@re_ku&!3=q at L=~
zUd}<e%2d{s$|>0od~Q^xCs)Y1$CQdN)vIe~>WGGN9Pxf&+W|NKXIkDgFT_6KU%wtx
zb&#lG7*7N(hb6V(HS%zZZNyz#+nGMl2$kun$b5L*QvrzzVPYw~x2uwS91wCkX)sJ}
z{|WG>BA|N=m+2G{gGk^C5n+jxG7`sKVuDRLSVvmB>R1G(Cu-S$D5Nb45u!VQityJI
zNSx#P0no4 at 2>Cu=I4G3IP82|&I}Vj~2p4AL!EJR+Z}+3WXvsABcHSqF+pLqk1S@~M
z|H)LkBlMU<m1Kig!>_ptO<P#C{if3<Rr*_iev+j1dPGeDZ+R3~EuHY`ZvyX{nQx$q
zLNt>fv!7GNOlGF0O1aajr))I;xWN98mi5oJx!BG(Q+FzXLEkyhW5U%OP{vr_YijsL
zCpm#MVH3xyMPhy>4l*{E2D4EX`dADYBvcBEUx^A{eW)M4Y|nwS&wo3)FmLmy$Mg|0
zr!wV?BUVwD>5d4?l7&iIyapYh{rG_~QofcJ;mQp37?7*fteIC>>9f6KQ{>ZTuFE}6
zp;XEyw%0SXAh#zQ+ZRu3yn^g(WSKbs_A@*X8=1eR`qA}p<-OEPHU2KfSSNKG&Ac5G
zYD#K!27{HfFI~&?^>E65nms(r77Z$vTm*9hT29)10QxtZ8NV>d0)dtTC}@X}-ibVP
z-;XOk>(-OReZp?#71QXprlpCM-wT=6=q^YXnRr(A_q-4Siu{rCM(C;=U5+<v$#NIV
z9m)?xvP#KR)iV|SPXf$=O|KdgVDLY0i$c*zU at j(sO+66bvP|&Rv?xl(H^jUajfBp8
zUD(L#VBSU(R;#yPpDIG+oBo@$>2Z#{g-7%JaDACaJuG;wiqN}A^Z)kE)EWh^;r|1Q
zE(QjIimgN33oYx=hc?JSlwcj>i at Anxkrh4VY4FHwR}|SR&*bMt5&fpDr6fbOPWKCe
z=JEK|E>q;B at 5RYGvOn<1R}G>9Q``y1<H7E{rl>xUB)y)+4W`+rvq=BP_Lo at xP1i$B
z&o2>E^2mmVvnjp&R(7PhR@)rCvPpPb{PJE3gMj5W0^3dMiBJF|?-7Mr*JYT+bO8(h
zC$rXHLB3C^C~W4OL^|_Nf9lwS3_<%fIN+MpmdrsrqKkemb`QxxTc+#qo)iombd0Cs
zeN#jgI)DNnx=aY&|B_Gr at j&yQH5W1&-I(nYQ44q9x_GGg4-b at p>Di9+BeZv}+&X47
zH`x>4;y*qy(wZk7hOslr%wyRRaS`oVZEfOiTYV1Q4ce^%4*ADd>&8s_e0Y*}f3KxO
z4$KUxC4?~(cHHf;Z8Gb9a7bBSuz?gxWWl!jOy_EfcxkMwx~A>ltx_9wT#hDaZni!X
ziKKT1$N7Q2kBcAhA;W<4v<4&a1&0blLw`(lcK+r!DYU8CQ?>=z9Sb}o`jVCP#K87v
zsX4$XCrG$0^P2O*g#D3m$lWnGyAGE0YmitY%oOukw+bxp#XwI?Mv=7|qlbeiPI|AC
zT%{$hX_xtd=}yrcA&D4VaolNwM9y`-JZAVOKb#7=u<5SoN^ja{nHj(=CH$Jjd+{t<
zW<385rz`R66AWLK7pkH>uD73qa!4zo%+kMo8LVq at -k1m7j2#ejv6S`gg-{)|zZNN~
zdKk|i;Xsc0U&)VO)euKQCO$g5(l#)mb9a at tkMiQel;!X_mQylg*ZRjLDyfIQUzqtO
z;18SoU2|{$mq#HApKI9$XPOsWuvA9e&)YB!#4zAkDHG=^HCn@&KgrdME))lH`-5-m
zyyAwr1ENe>{rA%3!^8t0nU6B_V2Dk-b<gUC8RQM0H!{jLQ=q7xY2Llak!es0h6}pv
zA_72p$A&uG(kC4<zWcC`<4%p{><O{y7EP$DbaQ0&2Y_u3_0SN<xy<{KnSOVB%t`Gk
zQ6WVQks9sbaTRu0Gd;*PL-upCHi(3}VlT;i8%+caq`vVTPGSX){XeHN7%a8kk0H at W
z{Y3`MZ=!A+>1 at Cn!`80^a6yvBG4|)A7DhpTMNIy#Mw8&K6C>uv#SLcK?@9p1wO1k7
zS=+%*WJJNLn+trGrDV=uv_tZyXlR?Bx=jPgT48@;dLax7RC0<YU7w;s(g1$a-4tY(
z5!4eja2QbaX$vg`$n}P9QilywYL)d!9JZ(Do7x}tBO?aV|L%O%rOxJ04xWs7yWFyQ
zXPaTy6F{m#a24M7wXAv%*=<q}Th)tg&Qgy#&5PZ0ILP3$zy~UQ52qWYs3h9Sc)b<Q
zVgQ71A0_By9m?*6DAcwDBsckmz_~1t^w9THJ>gwn2Oe>;=XQ_PBB8znT}l8TmlLE`
zO*U)$`O1JO<?wstvTfc-w at SbFmf^rTtL>_L5z at pL+Mxir&>BzO{(CJ$!{!q(*WQtz
zDSB37JZTOO?YM~W<baPllnRhH=?pxQe|iM~{AzOfvM82qw6)A{r;C1Cqbb5DPX#-#
zK}?)Y$UlP}YhxaBO^+0DYlh{BHNV+sYQf+PSgF#75 at _3PfD^6_4*0<$I9Wn5+Mvf1
z2{lFoD?F=1b|twZNE5-?KHV{_m%SN0i{jv=GOeHcLJn+pnTx7(sB>Q*{KbFS^-0r}
z7mA$NZ;QuZB8 at r9tU62b=-FnuZ*FfqY7aM1dvKrLr}8C{`7};+D{oj;@fHRRE{uM<
zfQ+9p)p|%^Jk at 5qTK#p)_ML6(p_e`8l@&8H3eu|y=UKw5X6J>UTQN;h?{=lSUDWq(
zl}`Z&0v|9bd_%}6t&(K~Qv9o3rIhs-5xxo(5mi`O;QJ5uZm@>Q*?P1enZ1+QefaJg
zZZI{@Dh3INSS0D{A&`3z%^{12;Y=J7$K0f*3*vR at +-^=dfMvz|2|g?}ggG3#H?m+V
zp&6N4KNOa^0z47W*c}T$Kv+F)`OtRUikk+o^wEEk{<71rG4BFdsZk817CxUwp4$M}
zp5p~<$FVNrTWVycHZ&kK{DOXwmWvv(2{<2Ho#J at BeS|sswV2q>UN!IV{;7VnmA-PU
z^!SN<^BmgRL<)p$(J5aa at oBVEOB4{d6`I>33v}b+ogi at C_S+D|b&e8EpMT`WA#xYc
zHc_yb^Tr2 at O&0yB($k0U{O6oKKewX(aH3yrstp#xAIxSmVD>|DSxvQ598r~YXMQb;
z-H;w+j_Bq0uRNi}Rh%^)DzfIO$dpNQqHpIQ9NjA=vFW7K)W^65*}V((SVGk>-CK7v
z`?Tyc`B61Pk~1YXGF&OBV5eq3O8CRqd=WEUu0jT_JRdBQYXLrbvyqNl%%pFO41~ne
zGJ<oc!NzMGNETpc$^s9BKZ0<THj-dJ|A)?=QRKj%?&TMXviqYC7X}GTpVlzVC(|xe
zQqgCbs--V&+wG~{7kXIwYxoT);DnKhe7U>y%&GVqPd_=7RO??`zmvpe9{QC#oXL{d
z3=i3RA_9)>7*>N^(U`A)Q)!kaa|7*RHB0$Ee?+``iAb@^e-Vqdv7`T4h5Dd^AJsPj
zNNI2uyJ{3{J4kc$0khP=c`^Ok-|Rb9+D63SwXx9hWCol5C3vd;YZF2Qn5c$#OpD|c
z0+%9itH@>x1nclFJ|#8Ji>C*1s4JYvYKN1J at onU{dGqktjls|ZUr;W~-iQ74p=-9l
z@*diD&*QV+7g7t$mHLdY><(xn51dd=k4pQ215}d<E)(GxbYM1U_O7gzrOsExPKSr>
zZ;!ij4#K&@oy31R>^pg<^4f}zq{I*iRDx*kVosMlha2<Lmv~<rtD=X8nWH0vm^<;&
z32H at Pct;^8jfVXLX<F@$jo;|zJ~$7N4pFys!C99_-9EHKu;>d0N39uNh<n;Z`|7*Y
z;ESG8X3OH{qhK{<RmRG0o6LO0WR~Lm<Jt{uly-TBr59QW6NHC7nIxWXH!w91qD9bo
z>;&vfy7mwjh=>w9WxFFQLz*tg6jDp(VKN*W*Ey)vbF)8v5ERL))bEx;9EQ6}swV=*
zi~F$L`Was=y;n^ZOhX at X>Ds_F<$o8B>AXiGSpvTy&CP1R`Vxu=Kp{=4ESlrQx~RGx
zTf%?8?jye58P;bNuv0eMmxrt$l(aoF=$bySb{ala(RyADFM!~zp8qQY^on}fC_RVM
z_4G<i&NL~`#=Ic8u#c6&I7oe>iTa(2TXxV2+F&7pIc+e?(^d_WJ_idYY3?`t807uE
z0ojj7_im2YsmQhW^KL62o8a>{Dz`A9{C|^iQeQRrwI`a@=VE_1G9fnvTPcQ$1T%7|
z5fEE~V@`jI^Xiy|h~|F}GmM*K7-8H2DgUVMDu=Q=#2iB9z#|$Vi+Yy90r{Z#u^DYw
zbr1vL-O7_5iY9$<<G`3yCy1A8(LU0#(*^*+0r2^OECxkSfH{`I?ucf5r_t}NpW9s%
z-=}o+x~?t;UF$Gk{rpaaVIlH2YvTiJD=uqiFe at 09MKrqSO>C$WvQ870`?e~Ios6)g
zSG)L1H_q(>rWpSxNSyjBNGu}-2RU*spn{V*M`Rmym5s<me2u9{q_gS#S+z+^Xu!tC
zv#(tViWsuFF&uDr9PWqyWIcRVOUIFNmy94aScO$2U!y8<g4q`LZTr5gj{$eYiqOfR
zD5+98_6i`}uU)yYsn~_{ar}KcT!nZRs;LvZ^HNp#@ZzIM?>&glDipgys13-BPa7+3
z&-$ER((hZW%(mU`30lMQ`-_4ihCJv=nE7DRll(a~ZP3|!l*ebbP82Qm<mRPQZ>fcE
zd(f)%`aN~hsXkS7QA{b}5pl46;1wg!c5HL9JH-nfDFOX at vAffin9{wsglqpGoBQFx
z4hp$>xOOH<$w5o at cS&)}0eGmvDK^0v^+wu-D>@&#{jx5u){S~a4U~zaK(6G5K5GGP
z)Ly}kTJnY|vepW-Hm<O?(y?~3v5M_1N#b}EX~qj#OSc|;DREdR at Y=0=-vSQo_!H{z
z$KVt>a{Q-$;5J*K%4l~>2ihw|Yj9$Nf6yp`>dRkaj5WmYo}y>@a at 1V!fhOIQ4BG at 8
zyw{zA0LhC%OVfAJ1Kbykfz8We=?)~8u2Frw14k8#3J7P)1AQKf5mCX0kK|;ogFj&n
zX6fU4WpU~AXpynj{D3N`r06z>u`gHe<mI_wx$Ox%Kzza?pt3h>f_9g?(fJ!O2F{3T
zLAP&c(J_ at 78sbt}J~=up5xTY=(r!v}z7Yp?jI50i*v~`q#}0&Z$DvXNBnc-Cxqj6r
zn?<{5livC<6Bfp#fa{2^Rv9KMOVr@$yRN7yQmBd&-}NdmWQ3%1#WbgIpc|zCX-+zc
zS4Zl at ***@nbrQ6YwYSk8HQ9AV;6uNlSTUA4zJXCWnksS`j2^^iLqK8&%g5R%$;t=B
z+c3e~in0%sx-a?2v9q>lms4|FgD|2>_u!D}$YzrFkNrBI;ijO~ey<h$^>&tcaqe=a
z2?pVZuU^qQ?|O0N{H6gLQd-18sp-Zl`3y$&{xb5T7d{EZZnG at Qlw~&R0XVD9zXBb$
ze}fe%NS`8Wx{aFl3pZLMnyGkWz{Qzz(AY`ogJOsVj`V^#b-ovj0dAVZNPjJT5<kN)
z9BV|9DWXs3D`lt`yBTj41nm(zb{$FVim2|R at VH--`Xz>(OG$iD;<dce$m4KSmGr5*
zkiyHld)Dz`jhvisgqYAGnG%-W5h>Y!q-gxu8~e&JV_=W0mmv7jc!3v7V at Z^(&ID>O
z32VDq7I-d*;${x9jw1kUXLO{A^W*~iB{4ijK;ux~5@@l-h_ELj$PBK;fnguHB5hf7
zbjzxO8oo!8&au>Q*x`w?f{VNsbvQ%37><O#QXIj~vbu)jiZxW at kN|!p>r*LR?HcrT
zDaFaZzgnEzxK1#{kQ&|L&)I`k_i589y`kk)$r#JI0}T8C{xYXK*CJI2Iy_bgm%e9*
z at 48Zsk%bV-F8ixawzc3d%W0e!V!(?m+fZ9n^DGhK$+2W6LMbzEXr@#uRmw*4 at lY{4
z^OE3#zg$4Hfflnz`X?4D>|ksO)cHMlsOHB!PbnCybx%is#k>RYCX67TYcmYPUB0_t
zu^L`2JIdow3TLKl#>txgh8r9k>xzaBaR%wsKju at 6M&pa>gOJciQsWE at k&dvkdlA%-
z?ZO42h36|Nuz<gwBw#l^@Sxgy-dlx$f3wuYX8QL<;UZUsWr^^#Vi-+X3_uBUA9?x7
zIumgQQ6 at Je?np^Nr2Z at JKm<Gu=<w3mUR6OdT0YMZG7=Ef?sB18eo at 6{qOU2;_ijN^
zgg)t&=Qkv~3bE;pt=&ImHnz{SCOZ+jtaaLm;;Hpd_7=A_p1`u-){?cIX1AK_E#|^s
zDy=%oh{gnSL?#&F27LJJl#<|LAO?Rs+$r{}HsL9nzSEquQ})L1h>OCUCa2?a^1fL6
zDQ5GEpLebaSsx50{lJ80uAGYNmnx{iQu-u5OS$$SmMw{o&&JP0ZO>c$wUC^*V=L>c
zrtBg5F;--Ei;)nOm+;n?hM4hjYrR3wOXDxTC17D;@e4#kDM-L*5E<J_WKdr_-M3_j
zC5c6ct!hdF9)Kj-{p7w?QDTdrP_X>l2I?$eW3h-ND39zs1OMHgG1#=X8`@&9`pt6=
zUGmInT|Xiga0p0sw&9OR#}n1a<pRk^qpyb9b~Bim5t`WTnYeu*u&+uo(lMA%+xEZ;
zM(BXoI+pL5-hdXq#E*y{5Ire-0|!zLKKxM)7FLw~(a at _99}Y#iJ2?M52e+(`99o?d
z9Ah)<#U&Hjg4M-y!7VnH!dpGx at ***@repAVl;4WwvoPdvGAB93)84NNH at GV~~x
zoP_pm+IK9FcDbq!W+G0p4E%8NKrE&LZDA_+(|##dj2|P5?Z)iPd)u>mU6^ACfUIBE
zgS%XDlZ#35UHafW#ygEt2zM2wq2$+PfSIUdgTGQ)G{KvNh7AVidy5d}IMEDD$Go)o
zx^_)Dn^jB%DX>N*IsAbz5t3qcSs#sOD3Oi|w)M=jr4lv7fWPi!z%BHn&^^BQdE#c|
z6;UhaV5-v`FGI1Xh*3L_8cam4ie~Trq$G~qdI(VieHc>e1jPyI;`n`WEPeMRipeia
ze;omu-IXVt03#^Cr?>;(Tf)zefKQ`)1li4C-DUi~>uB?zhD5kzJo4W!5!{i^kidZz
zu#`JDia~#rvqwQsrBB+1nB5&i*r!v^sJAYkqQ4dy$D?B)cbeR%^vA at 5e~q8JG8oxr
zijRt1s+<lg(;k?dQ=A+7&jGVl7&73nFz}Y0D4s+>TO@*H at LBDvq5Z(6v+v=u+jc`-
zN7YaacHeu>=4qJs?na>PY;L0Mopt%IuaOW$u^5^4)i`?=D&J4T)e#I?$N6utT$u1U
z(VQTA5+vm}<-)eN;^TbarQmPN2AN$aYeMBDRy?Jc9}&Ka$cjOkHuiQ_nX@*h07-X!
ztu&_yZ_YlD)taC{<iV_8ih6QFJ#C6tMpAvPJ*c2GBX-i&D``p+P?Sg8nHGj$k at 8rH
z3CKtNh99wL#d=!0c>fi9f~Mo+3U0h3nO(TO&>jxZF6edaUp?JP7B}krKPGhCX6g&D
zZoE2r<E3}Z__}8JMA6MEqW);#Ze42kE{AGsMOV|6WqSNjG`U6m32>Q734Ctd{>pzT
z_D5jCav at U?=R}nrQnz_A(Qb3Sk-sKO!y4N`FxZ*SOqFf+8PxdWj;Hgb8Dg7j)el%U
zX8nrY<_d1%3mJBSN2czmOy~N`cFlg2qFncd&FjGTvapyOlI!k8XfV`;Of5OkytaiC
z{1tGNiGeOpu_RM*Chvu(??E5V7xdMbr=dxeK at UG7$Vuh&20Ml=VeTS<kwg{W=1K7O
ziuYlY{XmIi`qnWhKdSRsjERFXzk;ubY#{?Zby6>H<83Rd- at U`E{wgA<)X^bsd0c$n
zNrAUS4S+i0KE3w?ofa1k?GiyM_r&STotD^M;iZ8w!MWq6*=5)5`phRC?^p0mmWWG-
z6V2&=1l_w;e;T>LIX6v<72_a&Ub7oQgzD%ci4|OUdVOd>b}mUk?zhQZ0X*!O+0z_n
zSQBjI^zi#+5zNT$qN)^|;ez3MvUn^06mZLtjp~COI7%nD$+Mkalf`vXz~Z2aVR)5L
z8Dnvi{}$vH2v=|K88*fLLOA+*M668<v;G`Pbna5cAjGE*`*y5!uZ;C-+#a~Dpd2=(
zJjWC>$Z=~(7l4h%TsXl|isnGVu`ycxX=Vpta}qkdi@^mEI1&O|S)o^Oi=4kIklYYo
z_|*T|Zcd6rc)dqUe|<7SUT{cUgqdNsb}qU%tKR}YEaz4*s2tAk4Hn?H^=gH5*`>y>
zLjc-1LB8!RWo9sQJ~j|KQ%2^|vmNW&UJK;}jFnmUE&p`1{m^K*@fUgCMaNok;Fz&j
z{R`M|RGp+9>w5;(9ZaRWbE5{*P(E+)Q at 5{E5L7LG0Bv{4VW2w3DWTJq<_skN$r_?g
z4vccR(7k9b`etd4dodOT+*GE$a=V}(c>wVA4|Q#ucwVaT5UDuf>-S$JDJygSNur7V
zs#WQt-N9W1Wd!XJBK&r#LGZ at k=E+3p)kni?-8%Ix%<8VaiR0>AOnM>`PMfmXtqJPo
zbhR_+5HIYDzQivbU+sgsalTrJCLhc8u_BCtWMZd7SiAauYtzyK8BmIG0z-4iLe&(b
zp#+ at WcKw|dz{mSyf1Vqw%9t@>5lE5>%C)Sr@?(V)9_3~&b`<`#@)@UK#0O=G6D8{m
zroFC+zm(wG*S45=6!_H1H;GNz<!;3qiwc?6^(tU_ywTPa+FX7#)TrlJk>LEFbK(C9
zlTbx^>Zoht7h2nb9cxt#5_Xu<#X!r`+{BU~a8C&!YgYbTigL%5lLcw=SCtf^l2(dw
zlDw=K!2sU%|M+2r(jS<{)`W>_$rxOt^Ik50GDh=Yl|8LA_^S>)&Am!c at IyN_<>IVd
zQdbndBygU;J)ibCynA1E=c8ZuaUTQED`OU8UFQ_*ZGT<oBY%sAkN2I0p4p8#C`Ub_
zQliP9<2!XZ+dlO7nwasPO<1%<ynPBh^UsqmwGJ4C2uTzO%CUCSp8=3*EV at q1Aput&
zXPnK8yuC`~Hs<*L*YT)9c~Ru-aKQJ%M+&<$4`l(Lj%IXoTG0Ib5`0juY{lUD5k>mj
zK9H{K?0<Ttdbi4t?9~VDsYzdo&%^%I^+Z0@^eDDg7 at nB%fph~~F!v87SXw1}lP2Pe
z4USP!Ncn<55>bXScNbJ;btZym$LIOkM8O+rqTb~~S-8r0PK*e1U#T%xc=gBB`PM)Y
z;r0Ul at Ks6TUT6ZDB-i0uqq);F%cVL`nIzU2_cOk=<#Ra%d{KrjaBq#B^BtF0P at QX6
z(Gll$1Z+2rBizMgS2Qu(b(5+AK}Y#f-2_b?^oWARMqIu`F??(Aw=-r<+a`<C%&FSV
zAm4}cdG`^&Ru~nd6qg$sY%R8gxGy|J=Ba{}To;CHobQR5Ej?0tZ<xc2P4|pBZDQ#%
zHw>7DWi0UY=(*@z_zCKaQ#saZIbjIp20;@)OJ4pFN0of9EvTIVQamYSj2<_^{7I7m
zC!hnl=r?GA6nLx!MqLxyeRiT-YLkU2$u+*RJYS~W-L}6HAbRSLOE*htvq`r4r*E&w
zU0M-1b9n{44FQ~9^uZg6HgIZ;`eMK`L-*xmjg`~O65v&j{Mgwx1{L;W{$ce+sQKak
zF%oO_p%~)~?Qx~7v%63|tkGgYWZE0GBQOkBC16<~lLDSWivv5}FoT{|UU1!;r~b6R
z=OBEcTqDgu0m__ZHlNGZfto at _vLh&XV83WzR|H}aIT)DYO<?lWn`Kh=jr9=KH$n?!
zU98V)W0IN_hBc`UBnjSdA_!MOS>i#9Qg?Zx8DG0zs=B+DRzDJ-3Rnbmus4<e<?oGB
z-dh_33H&69H~;vkz%xasJG{wwyw=3F&>{rxgK;(XNH%XM4=e?PN(|*@xYKkfIOU<c
z=@p!-LzO<;b3_c^{8Eom!e7=otmE#D+4iRF3wdt}gYxD<yj%UU!R-Rw7 at G&0Nchd~
zV*HvzAWXd0*$soBXE~=U?u_^-*T4oGr)z~P>Y`c4wSr71G6=G1iO|Fo*`*rN^j7eb
z<i^C^UjJgd&0DKxsM7%_2BS`_ic}IVRw$h*gkuA at NWbJ8)#*j at 5oa*U>67qzD?yy=
z<hLeUzf+0*X%?)Lra8pN{~oP at 0jEcd3x3S~&!vM$r8Vk0-Wc#K1=e8IXvo?UbZUXq
zvT-J31;K0|D|o8ce&r}<f2MGjH*q4R<PzcHb0+^2sN3Du==7xTi>0&L?nfC}aXzQh
zv3u8MVfD_Q%j+8XiL_uyoc7jE>}d>c;*w*B-(~;&2!H>%2!H>61`*-D7_RG7Nxypp
z4}rcpJPV-nOTpk4m3AA}X|;@Cl;}6C6_sEBB(P6048fQ)%fWfvAh)sYbvW0IKrO+)
zrHHx0Toig%O^3~BgKhKB=`u{MpqD8uCHnhh;0AiMbW*YRR<soTDo{D%Z_2FE`uyjs
ze`EoKZOS?{Sh*>!b!dUS-8+odfG+vh&00-cK2kr<K6J;4UtiTBzD|kWDNKF~=vizR
zP7WlGA>Q_OVoK$~RnZ84pP_>LM}elL#q(0(jd`$tv12~$b_o^g`BDT8b6!UvAXD@{
z2#<}B{ncXsA_s-=P3{#LQp?j5a>dgXy(?Wwj{sPIF;j!1rEY3i_oUh4-x{pEkEiUt
zz>4AufaKtUjEG-|7>)u9X5$`gjwjsw2#0;wT1~Ci;v{{CnELeWiL{5nyQAVmCE_fu
zAxro!dOTfy2>I32$d?wchx;|C|CczWWTJ?{6+n99?#~IEAh(I(`gu)hb!LEPgFt*)
zw2Nypd&yBmW35}_8nYzFnYGL9LYLMV{7L`#>KmQz^!;UW^5#_8aPA)T-JZ9Hz#njp
z%gc1+DXaeG-4BEmKei6lasEbFUNWxl&ya!{K`Hw~<Bn$Sbi?P(;a^MZF642 at e9UrT
z8fNxoAP?e|f^P}P^8!}<6a~0^nupdmJO~9Xz$c8qg+*V9vQ`V_WYFr$q(xfc>Apjp
zu$^PmTum}n!6B&IO=Q%3s54x~jQ7MJ|69`$u_F!>lG=*QJ^y9~KaP_B!2v&VMACFm
z6d_;-Uxk(92Lznvh_VLPl5nxze_0l)GX85!&Y{<S$tMZ6<IMuOUgIe8KcU&CyUnb>
zYYm62UoGS>TtpHepYpaZd(^$>*XqlByW8dejNk#c)wkS9yQeONSkO~nuO8Oyu%xM%
z3o0>Bq+m5ne})FiVNzPdH+q{z6c*UQRUj1UD}&a*f0P)*Cd&X>jvkQyU{n|9)eh<g
zeK3?ExkMp at X|jZgg1H(IBlyQTPZsIkQ!zGA^ILr4lES({Dpko(n3FxCh?Uck{4`td
z$EtZ)Xx%vbR1Fq- at 7kkd<I&~-Kh$#$1Y{sfNy7tIFQ41w`ny+3q;-ovZ>M?tFSV`5
zk=AdPRAMh>A=nTU$VI(80N+T^neI<!;qB)ooKBvGxtgDLqmBNv2g=6Ln!%1+H0M9B
zrR@;f-UqJRU_2&}E#)Don#58ew4fVjG9{Ff1!UDDjVn!Bwf$c?XVZ8a0`|PB(QQHN
z+Ml~Roc5%D2p>434ZalCVcVjf*r*x%$;U`ovbP!tVd$Am&j)>krYBKwfpjHk-zxPz
z&*_6Da2`TudAk8nyxQ*Y^GH2%bdKG>WvG6iUB{#4afG?*I at 2{|M5Ib4+pkgI9kYQ`
zSI!sXz|*G0(_Px8t`^T1L62xZW4ZQ70bLv+l;B(cSS56UeCSw1y8Zbz;vdx5LQ-E<
zM{5C$(o2C+dOw~`EX7dVZflQuLRubAn5uvooIf04Vd$(UE6!UeH3GgnK5q!0 at Y~@S
zK7oKcr`OswLD-n9OuG-VCgaXtPvS)k^{|_u?(9$<;}fsYmPX>&#I7iVi4Jwz%SPXZ
zQ-lJBneUZD=3#gB;Y?I at OojEcVeN1&u6whYt`0RHdtlJSn30L&J>Z4^Q>f&i)8N+T
z{<~H1QpCA4If7H)G&pHL(}yC>d>{RV=li!cwa_QO%Ih8CZ*PIsw*9gbEt^b_bKth?
zV*AeXlp6}tRaUUfP$uy~0(JLo6N~Rb^adUVUc0Qfb9d(3bikYCNE_;|#>HAI+qdQ#
ztk4x4y83ZO2Igmn#&FySgr2drUX0EkFcH&xKN(NWR{oEEr{qEE>-6pBNzHu at _-di-
zEgb<C8hC+R4}WXF67_lTTR3C7NpgfSM<>d1e=yqDURZwzR?=MKaAK6*WQ4qy5HP)k
z3(>moV8yp6ti1E#D5_`{MT~dM?_d^u!lQMEn>~4jjIS<wO*tQN%y2KOh5B=@r3_&0
z^j?o at BL*3lgs$Fqw*q-0dwU98iL?M-8AyZy9Dy?3=MFO89xYH+Y^T+(T%;jc+wYKy
z)-rv~Jn*})Ry&?PBA*L(fWUtOe!>JGQeP8sc&}ds{kN5U0DGIFFWuR)g%|Yws_s=&
zT}9!Jd04V1HbWk7drAW`K0*84!Mjx=7Ks0+xNHAPI@{uqqgaZMykVI_>fC9%W|oT5
zh|p5gx~bG^rko6M#@1Dn6muGU!Iu;tiAFioSZSb3M=hNg9Uu4 at K@{z!beGR56p%)I
z0?JY`zrbbYpSb6 at z0TSDoW1vFeb!!Qopm<qF6vG)kr<!ypyUQ>R;ad5O_1!g!{0(=
zZvM{-h_A1#EMI1^5mK?BZf5x0Be<Oqi)UIS1uuGj#|c2_J`#oMOJdA;9ipgGn#{0j
z1d_60n{Jvz<VCm4FqzmC&7U%p&^G8`S3U9J!UBfo|8ewTX+i#Ki-3rWZf_JXBB%$e
zp-b at 5wq6!1SmTlYCs7LTwvgz1^gy|bs}RVhpMkwi*o at d8kYe>y8K$h3cr(2(%G)(o
zmS*;@r~m0HjlU&eeVCw9hI<g)@IVaX3ohy%)b?SZRf1}CaOp$?CI0;J(OW)@*rFi5
z)JQi6(gZAIqT&o1_iHX?z^dDqS<;~f1>8<9$mPIb$G=s?M8;v<GMpvij+ciO<36xi
zqFU5BmT#5BNV6xR4pF9q2YF9V&x&1s?2!#Uk(+Z6$W at 7<rJcy4MX#ZRzSV0hPttd(
zEp!f2B{HN3Pc|P_Q=<xHmhsvA_VyQjxi;e2iAF6inF2A*=z32wx|%+Vf7yKp<Ez5-
zhX3qNmPdtcb+M=8*e=yjqfhao&icQhNRMof2;;5xGZ{@GcXP}{Gbzz6LCAs8qM=_d
zQodjNhRGfcU1z|~teTR|P6|R_F$j+MO?QvUnegfDJ%hw%vUxjzt9lQO98%x#Q?!A{
zMfDM$$>bBQg}76r)e;xEWnps-*S(++<;OZQ*X^R`K1(v|jH$AykRWPwzk--S`Mv?&
zJLMX_RND0U{tbwD0H4NicGwe+3tw+D!}ns at xg9TgR`V`;Vp;%(VOrEBP$00)XmNT^
zGCw}h`F7>Xy$+1+wx8}iZWEe%*Vqe<gM4mSIN at 854I7vCXk#*LR9h9wxt5z(Pu{BS
zhl0Tp_Dg70kS{znLM7BJ>>XUiGRiHVHa^liv?mCX7(hH9ZOo_}$!4&;ywbmmJrJ$-
z&NtMwTEWhvB<v9=zv`i##Lv$mGc};xex<)`-x}YK_YZbGR at CqV$6ttdkXC}0|E{N%
z)ScW)pX}Hh)bSu*re4N$3)=djSc6Gs0At)vF$N;TFe4#(%j6GF-rdb<Dqq_^yib39
zK2bl>=5tUUVap}t<h?q;zW;>^YIjVqyK+Mu)7kaO`;I^iB-jiso~v-;HOf<xVfQcB
zPB{yHC$qP1uQ&tgnK*eFuJz1I`K at no<7 at VPks~lx?wi}&>cG0>jK(ko+2(#opBj(Z
z=5US<aCiuXJPo0o);KHQpep1cRp_h3#|nn;{j5FMXWL)<ljqGhdj{F0+v8^gUOa9!
zx6izB!S^*HP}LkV0#5J+6gV!n)r#aD%aZY8iUiZo2TIV(C$bGzrLs21iyf(h&8wBi
zfvNu-{iDay%Z}XtI5f6pZ6Sb+Z-M6!(uQk(3!=<{(bGX{X07fRziYK{_(8B%C(U=@
z{$9K;V==2~XW%pJ=3>JOHjYsq6C{nq6u&=Pw03CCe_hnuqJDED@}&N~mEN(xDxdW2
zYsHmmw_ikkKYaCT(8Yp;#3sr-=v_s9R>(SsmikNxrwjpky{Vp}PDBfode1c%cA$ou
z?mdSrsnyhC)wtAu;)F9l7U}&Bj+|?IZ{kje%qH%?s@?Bdf=VDSsvhPlZQeBI=5<XF
zer?=5cT}*o?-Cx|a}c+)uY<Ohva-D%h|w?0<a!OA<wr8vsZa*w^GQL`upBQ;o1U^p
zZlgW$A3f)W4ZEK at 8B3dA0^!CsLG`uyv~-=)ukmZ_E>a;e>w5CWmiZ56{RkH*hyc3T
z5kOxNVK>+CClcw at r{4(1cG2ufmt+H%(OYnEX_E#%)>gjT(R(YXRJC%8iI at J)=4o(3
zlqOinwFdf35Wt;5G4)%FJEY=si?4{DMA)ZSP&8vjd_t!7k5KHV*zCw}g6T{N4qy(G
zup$-H$C|*wiYl1AzFa1Wwta+dcwkA_H4)ZgMH;%{2%VrGNW+Pzn0Vv7AGkS1lFur6
z7YvJBGiE>O#2cK{z$O|=+k`C*pc?G~VIp&w3q%q1E(B{5u0?p6M318BA9rif^icgO
z&sZ#Tq?=M~Kt&)>hXe0_)JA}doq2f0lwil{*>1GJ<do`k-K0G%b(b1G68MMpN^Uw=
z%g|~GKs^zB6tI?<8=eVP;FUVO(UK(HvEh7avLsD{1p#Z$?*>UpPC!l6-vam?(RRmt
zy-7tXmvhkiF&+o|_Z!v;s6Q4?7|<!RU0hEMjA?s?gnWynOc#!`-b|){&FsR%?Wz^Y
znQ`)l{=XJWY(R4rQP`l!y3MtMz18|-eY9h8hzqAsWl8^k8(FacflL~7-t!eU24Ws(
MPe+G64~ftF9|U`lMgRZ+

literal 0
HcmV?d00001

diff --git a/data/icon_ivi_smoke.png b/data/icon_ivi_smoke.png
new file mode 100644
index 0000000000000000000000000000000000000000..0dbe20ea0198b8d45e6b13e3b15470a0120faf45
GIT binary patch
literal 46577
zcmWh!Wn7bQ7v5kZ2uLY{bc1vVNKHaI^smw|q!kcQN at Al_21qx;04YUEI)^xzGzdsb
zDjlOXmM`yz=l4A4+kKw<KIb~;T-ObMXl}rG?e;YQ0KjNusP`WL0KEJJ0%&P2U-qvm
z-T!aB{?9-MP&3NCeQAI^w9T{ufcj*5;<GE4Hl3fL&1(SQ`j7uVK(ueAD*({+&PY%D
zNr>Y<>1qeJN>(-97y{w@&m8Lm`SUrkQzb+1unYSq%pzXl>2yTqawza?9FL)1-Vfc>
zFJEdl_ZeaU%v at p8{DLPBDKopZNHPgM!xv5&B8ed>$<l;w%2+i4Nx7&ITBZb`iw|M-
zgr8XCe3%qwfm%!*8hn(YN+Nl^S3rWp^*@>+V5+Zz;={Fc-_!&;Am?C$(-wB%g*RIS
z%6v0~G)o{Medb9dr1$IviQ<S{C%_zANCcQ|$3B5_I8^PtfTipvNb^t*H}mQ3x+$>V
z-g#>j>|B3*_#TBE at Z+^M4`nQGQJGW%JDo;pZ9 at Nbj~?<xg#95)zaqV8Y`8tV`=e at p
zEC_MT at q7I?wgTNbO7}S1%VB{pdB%LxCL(c{9I+5}NU2r%6XJ5b{o#H3GS5Agi at yh-
z(johrS{I~Z#q^o$g at wdNXh(360OsGo5RY#`yTThTbBI~z>wojn4-0pX&!%)Ee7TW1
z^Cct8d+MopOhdtYG4NcFli=e#BH>?GI&7&m>{ym7$c&7|7tqmpA6s}SD!fHe at XlWE
zQOfs$m9t8-mH>lU>j{Y1qlzHPo28 at y<QHE`^Ydi<ozn~7V&s8WN3tDj8 at S#g_ZfJH
zjI($6_g?gTpmA`-`A;Bb(YmeOR5;5n<8MthS|-W2A6-7y*ZH$e+q_j~Q@=nc-&nK0
z2HNqoViixBh5Ds2uKfEkfDqP;rM&;)A?7P^%9bs9Xt;P-&{c?AA&v|X)?(;eMEQQ(
zcWPdUGh=tZ*&nL?SFriA6#qOynG$dszJvC~B0dsr-A at x73`D_bhAEqBb2Z)j-j7`A
z=rD)`2_jp0QNA)IA at T+{00*Ov`To_9v!>$Z{Kc&%_$<YQgr7^&{al-4HRHj_u}O|0
zf2qv@&5V!L)P9jXzk4pvf;Rx$Mtp2Rig&-<n-9 at a*bUd%+|R at 3SvLntv5pzI7bphu
z{HcY{m}WAruh%EM*~C<%-|U4;={k%)Zc&^KP6F9R7zW;K|JL5E7&+z&@O|;lT~wb)
zdrT4xjg3zMcL#`J2L5*FszUD}s_N;6d;23<I;*tm6pHvbfbORq)D^$JtXPF5i98c%
zM0{CipMecBGv|0L34dc$7g5q{)*R_(p9ix!T><`=a?Lx~{7Vl}7Iu5zixWZhe05Tk
zbpI&lW_jP8f5`@YsSVHXp4egS-0$1u10(h=>ArXk-`MiF-7{{1*Ij;L*iUI07uf_`
z2XechHLuD1{XMU7FGPb<Cde~$(QZl<wn+EX{1=r&FQJl!IvdAE0XrpGy2XG{Ke9gS
z-SE)Ae>NJbuxws6f5*mZUYTxjZ-V<kHLi*r at mlnRPlA40>H!Dq{~fHG<UT3939JHY
z-sudCe at d&*uU%%4_Ly~^uKHS%QGkIf&3iYRt76~<=zaH;4=Z4i8p>ktj#CS&$;6%C
z|B52+)-XV5oS!tA-RjHRNRfrxMMd41EmW$!gTBi!iZp4Ylr`t9vf%ixBXT<>e)P6l
z_l;wNPvd^n&&bQ4k%F&Uk5n%A^+0tHZZuQ62#N#g3f>gf;VKSK!+#VfF-DmFb2a>#
zkt6JBVXK_hvsbY(f*9G5`MVwzT*G}5)ajn_P&so(-Zywg<vc>_U`)`Ful59k?`-jM
z&c)GDOd<|NL8<5{BEO2Tr(U)Fk8#QegI*SLQ;t^p)6jrDt-wV4r<zN~MYLICFsk|W
zkfH_Idzv_@&BvVk72LNtdSLq0xQ7imG1iR=JaKJ4W?++*xH-dT+AUtk$f2zq;|)TH
zVq7 at 7Qo!v+nK6kVxf|;)_j8k<X6^2HNf5|$Ug^Pato)ACP^hrDljrUvQt_nGL*!Dh
z27Jd#AqFzY0OcKCK{g+xx1PUfb}Qc>iCl4}O1UbPFi3pN8Xo1MW?@r9Vw%=n;ut%0
z)#G5(si;MHn|Y+=lvv(x&t at 8Ru)rQ=CGG`gQgpWozEfDp{=Gbg)m!RJWl+jg1QUrI
ze3oD8=iIui95dyS`XOG}-`QQN_hW0WdCpzoH at hL<XMzG_kI&k0xjBzohWbgr>rdz4
zejzn76phwy_9U-tz6Ur{xkQ%r2Zh9nekK<WDMq%(_^EsS!I73R_M4b<j!AuXU*2Vy
zdq?6MSdE&p&hSkOZi>Xn4eAi3iyPnRQQZf>*9X*iVw&E{%2SO#HaF_l at 1>Z+$r4mD
zy`;*xe3U`Yp_g(vlW=rw^S!L`H-jRI%(VYpOpAN!pCk`<S55b*_tE}INg)dh;bJU7
z$m|@bm^{f+|HzB;du==m(cT%Ki#nZj21#sPJA#S#P#i&LzPB4aY3V?|jTUVbJ=~Yg
zTVJw+$d#Ok?s4SZc<TB&Kf-|PdO-#JY~HaJ=l{|A8O^|yoYE57?k{iUCbs?kjH at WJ
zn4$o}Q%pE}$AV8u6gv1Paz&UQ#blY%bjl_4X^hgr5a4lL#Gh68rO`@kdT6Z8rXvSJ
zB`J3n+cOm*-J7W9upG&%i_Q#T3+s=<IN5Uu^~cM*?EU;6ds4r#G1ly5&uN$JEAaQZ
z0x&mX;6eXu_Rq59Qlj8YhW!c|#>(h4atS+4R1 at hxh0pK{$&VFkJ4C2kQyHC%iP_ep
zCUv)jt at W1ZD8|M(;XjYF(>yzU<*p3AVvIJfER1aiX8;4vK1&7i7pXMe4sj4YG8n1M
z>G8U1F6>Ws_mvd{nXJ4{Nr>~?^aS1R0dgHjQvGes3WW;!|GK{a>(&96?qbobcRL~A
zn+WEqb3^kpHhC0nynjtwsER{&Vs*~<1zS#rgTF-w58fRuL~!URH$o2Xyt}`aBCdEK
z#HHiweAZ)7p7yacj>>fbXYD%i&1G|E-K}G~7IiDX;@}x)USPcC+->x at zsP9Qk#y+s
zTcXP%2NJSBda?D9*f**(Fy?x_Jxh)J`n7!InIeOe4><tR at 98K;z8GSm#@X}Zl=3B_
zR2C&@_`Lzbq|KRlpnWRPzJ_7NUY6_%sA#|~Ykl_ExGe%xxRR;87)SLT7NQjitQ>Wv
z@`$1PC@$*vr1xI9t%=u2sY2B9KDf}drwT|_z at w5A8BOHNZ+xPwaV;qN`;`1BX@;G#
za!^ohr`U1681XfryA=wN*TGq&9ku)+y!f^cWg^r)a20Y2JQ8+DUo&KwbcyB-YgAa_
zh1)2A`u>irZ#MPbOFy93T`4RP at Ut+_bA9Rd?}+5&Ed0=erjPj}z?_Pe>(MkrEa!8&
zV0ITbkEw~BWTS}dQ}Cr?m%ur_b*Or()!)v2d|KrV^vmB?9|vw8$ND>&rmcts_0#>-
zO;1WqSMwG3eavt0If45WH{loz`w+I at ulyf=dmn#$rMngD3fKu&h#bqzfrx9fKvAOi
z*J`>h<Z7veBVDP6Ju`v)^TJccMB3jeEB=U+3={pL-BvAlxAPZAcZ=z>etBNH(E!m%
z>tDu2ptgKXA1YSWm|I3NHLo*@HD&}g+}-eo1P(_>9wQt!bk+BkI at O-8LaZ~5-BV}-
zL(FvaNMtMPV`rl!)P(4urrOIz$RxuQ+LdO<H^NsqZA4l$!(UMEg?}RmFIc(ow%wOG
zeHNRVSX0tHmS=PJ8x{0xhk13#8{Y8x3X9!QBBKkaFh#@t>%)S4Uhr|ce5uUNM}<gz
zL=P#?VAu8_mxGP)ocdvjC?<Q%6W}7clG#%t8tM5VxyiKX-Fm(Gj2pEl90jZ~>#1Y<
z_=$VQPc!h5%D#Z<L2$uA!5p`|(4IK4;O1lZaZYVzY6etQj4O>mGin+WAQgd>Zm1e5
zQtrs&Y-AmduI#g>4{D0 at Y4u?vxNX%EuCu!`qIU_2jXOL-&FeP>{R6w1gXs|%z^ifG
zY!7WTT}ZTZXXOGZm=FlrJZmWr>_X?r)6yJ;9G9i}r?ax90pl3+n&hG$B=%HAy%A+*
z1b73Kfm~4|J%O!-?J`-L><_%M5=EV&01N)ipN^g<5LUW>{|OaW<Q~OSPk=*|=WaTI
z9}Sx2M$KOPlAxxp2=GDQw6f<>EkE^nq!_2qY(>LvSRl^sbfY5O?Jhj9MUO9iR;QWy
z69>A|Yz*sVdp3hpYf;HL%Y2N=%Sl(+;8|yei;gP*HbvWha!mNnm-t|%`%9CC1gB=u
z7&mS;YFvpzq$d^6SB5W7fkwAIYC`WaXCIuH_UH*!V$N!)S*8ww+$)}!POJkPkJ_@@
zD-q<--w>F=7``1VOcq?>VPYmV9tB$wQifW?yMw|6GzDiFP+0^8swQe)>Upuz(>~GN
z%aemQ;pV31Dq<VfUlGoC1G&Ii;ew8IHR!XLg+w^l15W|F(?x2mGqc-=!%VNl!x=31
zg6E?aqpl|0fQqyEp3nry8}NuYQOU`L%?#R3UuQ-O_j^2AJ7Y#?U~mI9&H#w<xR;2x
zm{UQVbk0p58f6eyRQmLgwb)k=jO|YrKE4<QcBm%7fZDG}h+X4v>pQQ{$yyU=b6k7&
z2UfnZeLIoi;v=N-n*I^|y->!9?qiNTZJj_StE*p?zHJ|su*BV!@AvjnJo*xu(`<P~
z`TK(p{G#SJUYLG#I|^jp{Y1|B%KqsJ-xZDrKQ#eZ7sXB92*ku`2`3I3F;@RU-gYhd
zUhFJ97)3LlN3vV1fHmqucKkyeHIn=_)>X*?g}~twMQX9nAnGPg)YI=%pQ6&v_xbm-
z=uqpzt$oYaaECXKW;i~w2K>11_ou|7p=$?f5m97;5DY&H<Qa-s(sex8wL#KOt{L<c
z;Ot6#SC0n(<sbO-w3VpxwXr!5ox243RBOBAYF)S>ysVP7*StZ(2)4sb_V;N7By&z0
zX*n~TQod33p(px-P7)R3eQo_#R6FJAIPZQh%n)!IL*`eD1+sTt`KdWO+$Nh`+sA%*
z_ckN~$<uhtX}LF;fRcnm_S5WO4`osfP_y^8I}<Oqh*f=u(95`VQm&GQ`gM+&Qd^5r
z`+XasdKU8T%Qizvjt+h&!2tB<rsr?G=>Q&{cINVj?I?s_=zi?sH<Z=dJad|a6X>nV
zP5Y3T$g7SX%yLv8TaOH`fP3Ez{+IlK5 at i~vHO_}`KKK_iP#$$O^i?)=6*f)xCONi?
zwS+Tr_ilkeMst|%N}mf~@ESdrD=6vk_Me+h-$ZIqX<`5Vz^VV?)LB!7pHPv%aeN=k
zhy}Z431c$jXzLZJS?Ru~-RA)6Tqm+oA)<!-t9RkO71H!f{=b;;x=5%%6o6EUJSDWS
zvQTX}rqSO0!wcDrdEJ90c+u4aB3Y8A(JtUcEg$uYkNNVDfk&flBqf&2oDRMzD|A=V
z#f!Dp8JC|p;#XxrLKv^P;bR0}PBiP?YKF!;_dT09!%I1HN*`n>$9U4Zl&?g#tZ at Hr
z%Ti+j`B<Mq>^szLs%~D3=&jsZ&kD2n)fLeDUT|1^KC3QU<hO at AXVi$(AgxZgoqkUj
z8 at 2NqN?3yBzk(EDAwlolNVd<)QMN}c+4VRF3(W;PZ{{n$6BAZ?QzM<Mt&9a>LRPI7
zo7d5*2AqR}dOLNP2SD46)DVq$gx0v0zi?sW`uUQ~J at ma6J9Ox90MG6N#vZrL)nj_j
z9y}*a3aji$ybZtf at vF9szj;(MzS>TLnlj=xxoy8CpUvEPW)oW5_A0DSt>=c;opJ!}
zY}H$=N3lW%C56*5Fg$vtsj~t)Zxa@?N$4E5D7m#w21T^YhOUAsU%?5UfO0nwoOP3X
zcNOO+ONuuUH8F*I*gR)Z5!>7yPBGq?$rwjUD?T<Iewk};y0UB}D#iy_LW9Vh0Yn(}
z+AVtvo&O+W;Y}xs at W>z-d_4YW`*Gg(G*WdE`Tc7Z`8D66kzeB7dpg}ID(@Brt}=_b
zby4l0tYhO^eN=h=TC2%yF<~wWYCg%H{#dhUvp(LZK7LFH%tuy?u)5?Y_koAJy-F(0
zZs+&HZmh}okIXCp)@IE(0kWr|sTTBIYzD%@m56kQ{=Y6f7jw;DuV>Wdi=alCtpz+S
z-Pwhrz%!=$tki<!Co%MhX at r`G_)s9k^KDey!(|%Bt<TW;0mUx8Pg((E*l4K1ssKv!
zVQf40$}i671u0kEIy$#@>+Ei<zqG!jT=WMHVEq$rIK8`JS~<w=FKVw6M2bmMlYW$0
zWW- at Sj!@Sg+KXi=-4MhWR;HL5Z3y`lezX5^Hgy8|GS*9Z8=JiK{8lQzf}RCJP8|P!
zYg;k`YE`1^nxo#|AC|B5o1>$DUhaH?*y at o;y{?ODTql@$=95CC=pd!Jd>E6Tr|-Kv
zg`zt6a?BL?wG;2XyEg&Bzx-78@*wm7p(b5l>0<W-1H9u^|GK)k<_Scgx-RxZ&)HlL
zCto6da{>@D>8(AbH(^jb{DW at S%K?Jur1fw8uTH`{!%xMt`Q2IGw0rsx|Ec+&^X`&;
ztw%`9!jjc?#T9qV{#*WE5o6k4Jp_yi6Ab62-DjjdXS;(>31#cz+`4*E59Nj$zc`ow
z$BHa-HLn7~*RaOFmL=w3y2pytgCMAAagyj4)@?|pq3|S<|2)r_NGaR>oS^nOUzwT1
zM|8r(Demu?U?~1w95YvRZ>N^!GB|Twu2ELx*!#eCL?T%8PmdP5?a&p(DjFSe^-&ff
z!mNZ`t(Pk<SRwoTOq;tGBMd$J0G$xSuiq3+AHOYHNJSFr|EzgNGBYh|H1JlB5owNN
zFBbGfeOM7v>&JlHKyF?WY%>yrZK^M)=04>2Z^4ED&}Y=vCd?w;<{VKDqQXw7fw>YH
zb-8!{As0-I5+7cHcbbu+s!hfntajkhhX)d;KS-f0y(;zHZ~Y<0NOw-4i(;G$91?0!
zWX=CBkd?Z`=9BOPW<KMGhnV3nxh#)TR$N4n9*aFO`kiBFUQUZvwYZm-y<7QXjnd?<
z6Z>AA8OnOg#0%7ad^`2CFUQSGya#9JNQawhY4uK*qRn!F=~Odvx{vt+T@)Hk2=BtK
z9*Vi#L9 at t_eq_j*@4zGQI{%EhdV&(=|F+2<q~g=)JZ~PouBPI);=1ocRe*cI+RdLe
zV9L^6lw^2YcH*|m3?JHO5TKTNLyA~z{bEO$$0ej-SMep9&gbK70&{Il`{6iN09(bb
z*%(XIm^za+-G)de#k6J;0=d^-0E+o@&NNsPb0X8Hdifu*yikf#OI`C;5QPrDmZq~<
zdn~s0t&aKA+hl9o-U=iwJ)6sem^%5EKO1j?Cy_`a$u7Uc9KcLPCLo!b_1od}_^lsW
zq!WKE%gG8pS&3jr^g6?7Bjc)9Irht at 0m&ed{wdwA2`3kOo&|O-KE_C|D2zPn-mlvo
zsxQr`4NKmqxR$dssT$o9aa@?3acH4qKfWxz`rDTrXAu0&S$<Xtv!lOa$-gnjn&n|L
zIgF-7al)f<Tp^f2!cCD{wv1BIwoi14)u4}tg=K5TJ!@CRq~U{2g%{G$`AbA%V%OAh
zd%iS+W91<IvF|Sb2TjApZ291%**0$H1J2MkoKYum)$eEqLiHTq;}Tz5t=zOzT}tFW
zhsOcBifQLnIGQ1dA%V}9#%bblMLk`Jh};XnZYxlP&PYkLunYc7r#UUcW=HKA|F4?;
zXRsH}ZPr$$UW$#71{h8Cv21iZtUAnJL&N;C#MNe{){%%dQWPBfX*?P@{9jIF+KCX|
zVMHw`qo`JLn`PTe#0XZFOSmO`3;spVm~LP=mhQ%PN<M46&x-0MtR$9@%X*p}2hl%P
zmnKk(LO)Za>5d%SpEQ{e_!O(Y$a)Ef<D1x5tCG2d>qZ967!tz_dv6Wn77>Rk|GX1{
ze_KU!5j%MMUJ|qXyD&2<E7<IN6*=l8#gpvU8Nm>6y8kZ&yn)mbc+HEb<(xh&(4W`b
z=DR}@(l5$k=5pS^v8tRvXdx(<44`uY(2qw>pKiJ at C)Zjf at XaFm?ri|_&$=i#%GR2Y
z;Ya-iR3MV{ps&I39_w;M4m+yO8x@#5%{Mky5@@EuZnNDc-ySBlL0Yvg!{{;>&<eAQ
zY&hL5vWZ7MaHTz98}StW7nZjwl?Z-*PS70deHxt>U~Ve*A8Kt=gU&$5mN<2*j{+Qe
zPB++V at DcKDO18J9b*rIotZR0$<fx#+fkDrM>aQ(mK=U<nvFgFt=0az{4K4P*G5^6y
zNMd~Vudy at RTz<cVW%-)9G*hg0`(?zPe at +***@wR<YwcC1_z$ebuH`Wxn^;xp_
zO|pYhBt)NjMI?{<`A2VfN}@R#R)<HaGR3((igUSg*$NoN*BLso=EjQF8yUwMIST^Z
z#Vvut6;?oVQxLBeP#Tk-V~^#k7GwsOM^{Qg$MA8zigzM*+ at EsZytfUtBO2kN!>Ui3
zZeGm?1U{2mthEBNt42^I&C#yiV~F%(mYs1Cb}X2RNW`hS$wixWrc at _JD%)Z7hf#~~
z9=fdB5!tmcG&{g%AE`uo7bRzaMF+rK#LlR9JC at Y$zlR2qV2`kM;a$|<4R$cJQ*gd?
zzWOQA6pymbYjH!5!Pgosf%0%ety(H?sz=0+pBUgqI<GVb%nGJ_Fkup1=Xr%?2}ik)
zr0?K4-#$%%Nm;o_;WO{oc%1ATga&Oo^i03(qxQ~s1)<$Q=+U6ftp+Q}xa`&m$l4ZE
zf3?N1{xGqK<QchLcPGwY?42^`2Ncz7aAbdL)!P0_$Z&|a*X{c}55=BIK3gz4a1o*k
znNrOvA|996T$|@@tUc$|4*a?xqeRfCs{NQB2+fOH@!FB6Q(Y}Mod9 at KDM!k%T!FW0
zn at paH`xzxuZJvqy=_gZ($(C+dH2eZ~-yHwi*daWj?06^hX^+06Ip$mKrdU31(6{x}
z18(9FM;8NMGXR|mNS96X#ai%|!~7n!j-A3-F!>xz=*ZAY80iBceN5)KsmM}8?07G!
zheZH!h-lAocADMfF8>|~v44cD9ReujGZFF at ifVH^@kda6xy~jW?1$uFm87$DMxjJM
zT0VPkA;KmKP1I&>=ofh8j*UIPhu#6M7j-^Ec)^5<DX%&h!gmWbEES at nfJbcqr8)2Y
zwU&Gq=KL)z?00><aF2XI#0icg19E=5p(n7KEPDmxIT=q73|MBrL9FV<O|Ib$bhl+0
zMQGA;Ttz<{y-fQU>p>HKLW^WtG0+K at ***@zpO7KG|c8^!*F3D&z%y^BbCUHD2^bml*_
zoxzx}d_;g{!`9o~g19uCNVHTqa%(6e5xM+x`5?phKCkg&JK9o8&_N@>Cq8PY7&=cN
z9#>D at I=D+`-;dU+`*4o~@q=I9*pfLXj<7^2QHtws<opaHtc7vs)LZH{epj6>l5^=_
zJJS_=EG7RJytnB!$Ux}1H<)9cRgas#uGv4(<FiO<W~WwFQi at cItJZTU%wo2 at Z<10=
zRoy-6s-_>fnEf68M?~YvWeHtptdXWNb|2exZRM(zN)z|rw<{te at tySJub#k94MfJh
z6e5>jH2blVK0duK55zqefeuG|8TP2$O at AgXtR$!tF04j3meA&i%j49gyugT2i(_Zw
zb<J)iGhf}&^InvVFrvD}C*%iDa*318)n at 4)ix6G^Lf|Frk(*KAw?kRG)+}{-MZOoB
zK=7Txa?^#Jal%(aB^js&Ffr4g%J+nBLWv_`+0ztSR)1kM1i)Pgo8(Ymn@#w;JN<x4
zW40(Te9v0L at sMD>nA|vemvFD>W;TO6GkDjffkPO{`o|T>z$Po^AP*E-q#5al+*$oC
zK464nQj+Yh(hExvb{3s5CFi-bh)u{Q(B(iPQDgT8iRNx?|I9>II*gy}5cJNVHL;Fj
zm}hEsu3GHOq;1fXqT18k%UP}jw!ceFnT0P|9*7pI20amT{uF`l?dtUyK4{0 at ReLus
z-)kYFp%roP+8x&C+2#D!u*LZ6f`~0v{miNqU8`eTpSYr+d?lG)&DB0`Oq7#xzxrv%
zX*P6R*7-u7<|)ITZeKPBwLUO$dEqvgA*bHS6e>hb;VhSC!!dCJz~}?U`ya5tf`Uq)
z9X*);R7u#h=UH3D&5nyHxP#&t;J<H~!hzq)vj4kH_`nM46&^5 at W8IB#=W=ItXQ`%w
z*4k_Y+g?f0L-vDm_UVyn0)C0FGcIBZ)gd!`7F7Q+4HzFoKXcw__#WV?E)u?-{Q0dO
zr7hWJExB>+SD*ITFW%k~*|>Z{nJ>g}MKo7CD#tJJ7!_wNa#BLkz*cEt)oY&|cU+~{
zOnQrHGlkWX)bs6qLm_O#k<Bw+fsq229kiRvieoq!#r3!+oRhjg8q)wIW<2d_uXdrS
z^ZeGYfXTaMV&YdTSl!L^dHs2KjqGEwz>!8Al2<sNZFnu7t~nD at D?ce-FLjM|i`tzf
zD>qNukl#IZ9>h$pZGJw$hqB;g_|X7{<F?zpj4eR{RzC7!|7u6Sg%mQzGSLdqODxCq
zG5x^x?W<W{_<K14zN9xZ-*9gBV`jm=d}d>RI)|Pdd^-oJcRp{4>LaU<o-p*ZCe}yw
z_<j6l^TYD_P3k6r at e0pt2uP<*|Iy%vW;GQ at j7np?i#@bz+D19DKq1mcA at ***@09W=z
z8E{o;#kB_P<t`G at 86+~3koD6su>2s#rCiI3ZO{y9ur+6uib81VrWt`Q?pc?{Mr5&>
z)G;iF at 20YDce5HM16hBFd7Lf2*-2yF>U2+0l!ziXQg9ng+m9mkdO_EPCr*r<r`J5r
zQamV<pUqK749%K0(e2+8SUK7M>6x_V;jPwN2MJ+3D3SiUy^5SC2nW+jyWSGb;j0+_
zqr2N&bb3%Rx&i(WJj3oqb2J~>FktDE$vW at 1NJ4i7xkbF()%nd&(Ujd+_TMHv7pG)M
zn-~|aL&h`#&$m6FJ|4g?$BA0&yAOEjlxTd9Vm@^lOtzA|Cu_U`yKaEnL&d<1`=g&S
z_ZmE>>zNs3JUgBqCPy9c4n_>SmhP>TxjeW5Gd at rH=(%0yBo7d~K{phls{}}U at 8M7w
z at rJIyVM9GnJ0!{UkV^Q#mFg?#)bzRB+vUT1X{OPxKa}K{3N1d<M`5IfOwi<9qyRY*
zf(xW63i}}c{1KW4pL2?}Akex?Cu>R_-VOT&2BB)tBYl2o{oMwSZN^~P%SLBm=tY;5
zaZD24{`(B)jK^Y<*?W#(?@ufFx9rH%t4ocnJ>g*0H}W6&*839{5kCL2V;|F`WGhw|
zHK*YpOuSfb9Hdx#E{!QPvM%Uhumjz3z>N(7{}93+O8aXk?fPG9qW%iw$j$@^TDuwk
zLklhOBSF{ke%URU2E^+eGStwplf0HI1}&m2rXM!l%r{J=XK+c|EtQ@(819B}MZR^^
zwQ<&?z;DeEc*FTzNPG&KT6epfMSmaWw2?+>W6^10#>@Pk3_gIIvr6Dm=Y+B2YfqzJ
zfywU!0}^>4pc;oYyyddxm9t_k<!SQkMGwjELJlR8xu(V;JVS6uA*?{pIO8+u4t%(w
z49U1+leP&#nyxtj#?m at X*CH;vkxn+J&rIIbL(sv}7IOPLm1zx^$9!ks0^G}u$A-#C
zIa4uie%ryU$RkaQJ_%H?r8hSdJ-ke53<JFwNJH$8wD6TfU&-i%|N7PuhX^Z53gHV}
z{(u%(?>>$A0-yOE!u`P|8?BJM*&KFJCV<_*-b=K at i+YR|4~)41I<MknIRTWTfefIj
zh%#ZVu34zwRE>QQwd>q=oyX%ye<-m)65S4xtNzyDnaLQ4(-Isxu3l%E;oPZtzBDvd
zuVZ?AU4&J2j!=p)uk-{-yfJds^nGdd%e(7GzWX1A<=n4kvgx=%cx^r|kB&`M(*KfU
z7D`1{$A<3Kfod&QI5xG$U#to_;*E$1G0bvW9WxBNi$K-tnZdd6)Mvj!5U`xGuvM+c
z3~^@gvKEj2%6Nl#pbtH?RTrsjZ$J!hvMM|j!R_x<!QSS;mOLhy`h0;p!F&hEiHMMe
zh+O5$hrF%*Q=57(Vw#Qf4|Ji(m|~Zg*k2sbSLfdnFEWPnvRmJaB3H1t6(SKo0l4=z
zYSb$uRczDF2hDw{I*T>_a}rNxRuos1*`_Z-78jN<e%^`Nno~SG$(soJ85{hM=EF}5
zzTO7T&Mk59m+}m(4k-^MR)?CGBZKLLG}QYjj at tO^x7i;4@=m2ymhk^ZcXX4 at ci`er
zZf&NFr#l$@22usg2O^HhbkY}r*Bg42TCZb-Wc2ixh}_L#ZBOwNXGZARB%@JT#R%U;
zUrCv}^7?nDvYm^YJzr;Ejx3d5k12Fl7bAKuhy(E=Y>?5po?n_uc!ap%0o3g_8r_&A
zavVrHd#kUWBt$AgaHwHjsY5omwp{_W`&z0Oee9e)?wma|oIQn}fOa{NZ*kE{RA4-g
zD*~FXWrzBfu%-;7-3eMJb5whw{n~Ig>#haCQoI)868!MuaDBs9u>Mj$MJh3db at N|)
zD~Ja(cK~d&;;S{t&<@3 at yL})nt%yg8#J8yTteq|Q$e%}D*ddifwFF3@$fM6MK at Y-S
zb{w!RT<msy-0J45D;_OLdNdNnOh3Qgy=~R*VJVImrqQiuG9syz at ***@7hfvxNQIx+`x
z=fBxF?uHs#1wWVUPldkX%TEBx$sBrKIZ~4ZaQ4W$0gyd_- at ayG%mG7WzF>-cak0qh
zgU`FR8KHhw`Ih;zX_kEK#cqI9%Mx9L;SXVXbN2qlfe#$sRKgZYKt0mMTd(vnr4DK%
zw^=m5D&=n(ml4t4glFpS+!WQTg?jJ`^qg*anF+fbZ&8}`DDkTBqs->;!_$PY{!$IX
z*iBd)^q=PaV7?1S%WV7Fg;#`Ac=tSjqa_PS44+IY1|B8f_InLVi}itDY^4{vJPV8e
z-Ng7Jb-09gZ at PT?UqaFJx!|xuwAw_$UbWum^gbN`YlS1-k!qcGGPN=l=(;jUYi`p%
z at 9b%oS9>m)7Cf3GdOl<=*PR`J5V_vq*;kPS_b^)qlhz8iJ*1)NvQPFdYZ0bP^!pjJ
z1gI^FEN$GW^@nM^))SC8Ar>kXMmQQ6;KTA3b~f+c&m&bZ7JUVLtfa1Ie<p;tVK4<a
z^9bqrOX*4i3*TFE$;Mj}62?VTJ&(|=5o(W&b<%PKY(B~fH>Y<h0}B(3N<Bf5vy6m~
zCtvvxWuGPE#hRDkBCM!2f+5!0SuR;kYZCKwKLE>nFxRV+WE5{9;rsuknZU6L%wUw7
zJ14-Ue=rf<&~m*XhxqI=LmdVk at X1GZTwElAc;cSuyo5*ag7p<Wr%5HAP2gmiHtiUQ
zqPmSvbe5}s at BJYVv!4=`dtiRlGd at +1)z>3V|86yTIz!Z=oz^r<36k>Gv1(fNH8<Y#
z=LH<Dc3<sPDYK7YO2uofbxonjUt_Ijrn+bkqWpVO-e|1zjO1TU7Nf at PCq)<$!3(Vs
zo&chRpo+<>>#-7;W>7cnV^Ki;!M&-HTmwl?OXDi?<=!1=WZeb)9Qcnl9VCqc1x2fG
zOVc3f45oxLM=tryrXzKMx9v-od%C?5Z038jlmM6j%}J%pjolsR;-K{|LbtlA<>)l2
z_W6>D39+7UO!uo|lNElI;55v^X6Y_P0jv7IJnoNj*}i~H0dQvWx6*S8XhmkT>TbCi
z6Gh{~d7C`{O&G^zj(;IM7=IDQ?(iyxmH(G9`xaZdaAkUvaFTyX#fGfTR^omBmoc-_
zAx9?N<~Zh^0IvG|Sc0%rUOQ!*JV=t&k<_p6wpGRaxs3Opvt6Br7+r|(vNEX{fhzES
z_Mm^AbBKaXMwrP0-jFFH=UqZHe#x-wd%1eqj71__Pv0uvd4aLeT`qr4xBFmn$6(}A
z;8yeCxkwnEQRn-BqoQeHT9I+qDrA%~U0tO6_&Zo>0Jfx at U_ZLNX)u9OE+PzdnM>u)
zj^TM*XDm%$*kV5K4*D|}TVVbO)i2*oSbYDPP{+EX_BgCe_Vg}SWELflq_T_g-Y?@y
zPc|<^bOxWEZk$CJh}LdjP*fJqO`!tRxHg8B3IzbU{F6eYRCCt-k%t+RjWsqImJySU
zZ{2L+7(vgbF7awS`?EXWwFl~KMOR#3=>%FYI`f|!N~nt#W?mCr%0Fnhnao~|L*XNp
z-TR!_CA*S0i)&^gf)T$$o- at cr`h+SigzS%QB+$=@@*Txg3ss21Hm($9QILPy)!`Hm
zu4Xgnx0gfS)Ex1njcn}>L3y at ***@b*<qn$;+4AKQHy-Kx>cA9W!`9r+ogAdu>;
z^FSah%;{Q`HSZ3-&_GEU;MrHw$FKZwnsebbgRMWusiwjvFMl)ka#Y%mJV2n`g5TU&
zcy&T{?aHEfjXD at LP!__edrpv96h+2JnAurQ^xYe7=9aLe)Y{#lKGL&@Wz(dqwuHM4
zql^pN3rP`n($1v7F#oW<988;a`2)%Nh|Z_|qJE{}&2dJVV8r%gqpzSm<5$mss&lre
zlkUrcuA=36RmEWpJYqxf&-=p(>?JD=-rWZlYsL8llj2Dqwz&OwI31a46q}zdDkEIh
zCwCBF0kk9*?f=fT-R*oi5Q}kbaHj;`s<qIXJfVaUyDranI(X}X(qc=dyn_G-0Z<ug
z+-HVJ81fkk at K0<@!<k3&6FWi5b|!gp=TNY5$JWf&XY`Z#abC`oexsY|p?9|F<>%Zd
z+S#4Ca%Z6(u*cX(2Z3dc&TI=@=g*-C0mtQ%m%hB!YWywPgw-6ie>pE%!LrXT%K!b2
z8K8l-eV(JNvu%nVa%*V4aXDNaIBX&s5Rrd6Umw%MDVw2WN-o0+lMl70m}}J}&qrC5
zS61=MFnMSQTcl+~)q|?8Hz-_7zlTQsJ397s at 4Inl*B897bme%+0p`u~zVb`Bb1`%1
zF0X-c?zH2B-mm|cfS{0pYs=rQ8dMI-=3tDl?{D^oH>ybnVzs*$l)KUt`ACS*{Dd-q
zJbLf;eM!&2t6pm(t;DaS*ah+Z4=h&{MwY+PNu7^Uw_7)_Nv&BwaE=akmL6#4wk_XD
z_v#2$d$-?+2R<grV5i!bGsojCs`!Tfn`x7(uhBBU7bM@`gu`MO8OF%Acp<Wxm9N)1
zQte`6<Lv;!z`SgZVsYtkK^A40jGQ_~J_is-6f=Y9DzBH0K35NxVkjLnW0XQ?04^H5
zD_)nG28aKA_ApnXoW at H$T09Gt?kkFBgWL-7EwcDg-?$%qty at NJHaj-}V)gEIePXhh
z^F_GXa`vyFMGF#r#8mw=Qhkj*WZ8Z0(34Y7{(4^xmq}j=a>FzLtsoD4A7ZLe$oqKm
z5dF=i5u{pr_*(E!LQcF9b`I^_ipagm<+tz|rlzuF;q2ZCso|SqoPzL3x^>_KhJ8 at D
zQtKf6&v&-;Fc=H;21OZKJYdl%i`g67gINwy*o=s<m0hG9K`4BM2LR)H$a(*|jLM_n
zak_`dPB>a|=hO-2k1riWtpsSZ@#<l3eFNTS$x)q1O|D<co(z233hr8(*>u4)1e!&J
zb2{@>zs3~Wp;}eV-EkF*_wMmb;(jj at 0;6T(cey|Ls$d6D-Th&hO;vVSe*Nwe`_#T{
z{4Qse`pZoMcfa#IXk6#F_OG{zJv1x6*1ur*;kB99l&sz0$p%U`aZZ`yPEGMNd2 at k2
zrpzcrLYx8N)J1d4l9AwjO$8r7+ouS$RKM-lgOAzJ16TT;a}VLd7;C1p4xc#f65msK
zF^t^NBe^ah1KbUoh$0lcPp=&r2f1HT){TQnE9dhO+s~KK2_ at 4|v)%RwoWF0b70>p4
zEc|7|+<lg|jAQbEUN*gh)dTbNGrt-r2H{xP7HVT8!r<2)xS5FX0qjJo|GnO(7+CS*
z*RdW?qshdaCblrZ_l{jF!~a=s=Yq!U#PU;#+d2sAA3X-&zh==TPE!=(B687kbaopY
zK?7~^tuK=&q--N7@{`MUaYjEKHeXH6<s4OuoPJA3B3F_daFV9vI}M$<p$5w5)8pj7
z;0B6s%Ype2C6}fLDWo40kY|1!1yQ?k<@weVd~Myk(N)s`<`6|A1IDCj!K~HWHD!fM
z4-<i&iuu}(f`Ov^&S`G|?@BH#d#^I|ApR|U{`P~Exci}Ta2lm-xA}oEsb)2~L!U@;
zFR|#Ce?@H9bGU++A22x$>d0+J4xRY4Xp%cp`QDMcbu^3%-KlZ<7xZ06UK0%?dO5L>
zfVaxy^s+=|@DS9UJT~TNzD9}UBYSR-4I#lVF2?o_Hz{p2_dm6r=mzJ7(h2AqLcm*j
znzr}&e>nsThoX{-rrWA*vwGMAU!6=Zq?^5xn613-+ZpclZS|L#|0f~7v4=@s%8;&4
zY6oTbpr0I-Fswr@>lEbdyS~$<oT#TOK$et-dohumI at GK;Gi{YVO1Q11Sl=xWn18}~
zN^MKpdPs0n7yT!w3e~K3Ntk@$!tR2_Xf)2l8*8=~{=LRPTg{g#4{_|srp&XOcimSj
z%Cvet6wKy-fkJgn$R!eu-!45mUd$ZusE{$&QVViFCa<Qax1947bdC;z$tGrbB-p3F
zlv;TJoN`NpVuCAIi45Za at VH-4%w`5=>;HT>B?^51kz^NvW|k~y7;k9xHUE7AdAkaU
z(}YQ5{<c*K*>4wd&wQQv)lc(Gx2UV2g-=AW$l|nGC3-RVKw$LFbAZ7Wj%0%X2l|;A
zV+MzrA7r9(Ij4Hz?(XM#-kvsc=XxE3KfB$>Acqr<b4`U^-VcX&e<6IEJe=F`?bp%m
zsE8NbIyN)AA$qHJr at x=pO1r}>zPxE}Im*SYmB!O3W5&Lku*Fg6M~GhLUfVF81~5h8
zL|c<!G6h?F<8++oPFX%)=YvzME`>idN9~sgd!cmu{(<WOM at aLSVpk!UreuugWcUv&
z at fJ~W!b3)E%MXNov3l}<ZeF*mQJdLw#=TA~7pOe~Y^Ku_`Wa(G at 2AyOME`i;cagtC
z)q&gd=>>13i`qSih%-f at I?S4`t=lr+-92BRyV^hU+1~2{WwXscPM>QR6Z4EAn?_b7
z<J%J+5%TrF at ***@i%_-{4ibZeBOtz2QU27%AGf#S7r{^A at B2r?#eMDhZE at 3J`Yh^D-W
zIGnhkiLBdlT9OaGa}7Lt)U>s|S0N at VycMvqzP_oy+F9Empr=^GcM2!(KLy+A%gF&5
zt-bDhu&_C+9w~a-&wL5vv<*~VIEaI5-RK!AKd|edND9o%yqHXEwsD at 1k1*pS*n8Zd
z<Q%bRM!&Z`IxBtQV*@FCQZ0EJtEF**9D(INPc9@)?jfy)V49RmPP{4gFN~dHN<E8>
z{A+v=zUP;BF>R#QQqA72hjiqzLwiH$mK8%xa7{nKYC%DOB=(D+TikyysW9Y2^~QvY
zaWTB%L-}ax9m4Wky2g1PW;UpJY<6FrMYUFKZ1<>TzG&8NjdZ<tU&jMJto>%r(ZF}&
zkAkm4mR}m&FG9;L=I``U{%aRpp1Gk}9K$3+#tsfA<0vRtQ6Qn)oH$ITznqsmN+I<D
z_$k+n8o=gd*AG+FeV&T7jBDE)@qA<j^GFpCKjyZ_A+E#TIVI4A4<;tDY|#v(X%}dm
zR(Jos&{7S*<GZVInH58y59!z002ga|ejO4^>T>RLic@<2#nOyZhkgqW((vIs)SH>F
z=)RUF?DPH@^SWt!Ub3{iY%F~2$Hw863H)hLutTL#;o)HB{;5mZ!_iGO`()3vdrKyB
z=9}W{uU0<}mA@`FKVm9(?wE|&-jz!X)>&uTR$ag}q|DzrJ72?kBi at eb>G3K=l?WWC
z8BN&=TCGbh!@E7Nm6WI9a_?snwpJp at lEZly%NaOGHjZMQMMf_44uLr%Q54B63ab`T
zr{pSXY?G at AI6H7W!>Ryqhh>Si-ry+|fU0NoAs)VuN~%qL_<?a%afu=Ph2s6GHJ345
zoI{BLu7?rk6wmqaT_iKdyloZK`w4|sA!?Ji6>%yZbx`X at b=D)+>(7L at -zojVx_9+i
z>4<oWIq0k&cQ3)({dZvXtGA!Eev^0;c+eltT?!sgML0vI0#(q+sG$xm6f9$)Z|xT0
zjSckBh?Q*q+~aDAmCVabXtUu_oR)bBSE*2Aqob{@m^APnv8?g*!9<GKgpy6x01IQM
zBnH`q{kg%Yi4`J)J<nlgmk=XDUiLiaQv at i=0YGEOx%Y;xoLRDAIiw**?|)Sqe-0pf
z>Lvy=$N$J*3x}px<y%wP3$$lBN-m>DT>q#$Oa16i)H>ZE^`^wo*_0Wdyc8a3Wl~Fh
zJBM7=t01%meN&ZB6Cwrt$n7HapZnX7YbW<E<;8^q*s!(d-wCo*GvMjb03;1b#vhAm
z_b#t_{pd^3;O6IhxZ68*sigz|m8uYjaT at xH>xv6u<+3Hq!u5(00_Vaw{&R6$<;`8e
zo$qQ+bG{g)1P0l?+q1!xcL9^dP%e{qHHyLor_8WYYK6mbWgy7OJ6;|dnx5gG$?U(b
z-H)D&*nE^nYB^pKf*d+H|Kp2CDn>d{ZQC=ttydWS9SUp`IF*d~1M<`4>gl+eRK}l!
zy*|i%-A#z!dP<uM#7n*I=;uM{Uoz35IV(+5644P7XpbmRj1i6w`P#p^naQKBQcGqR
z@;SqPA^dwxC{QhrZRdBHX=8+Ct+(;@k`hP(NTITD88*DeZ<!~X$ALAU_^g}=r?jKM
z{>6UX(b8OG9HRE*++bDF=Ea)!DSMdav!FJ}arY?678giPCp;p;7VCYF2|i(>wa>Q^
zDCFljn63!<?8lf2_7?T55cU024!|<xl?z7?Z+F6mx*;^@(;Q4_d1wgm8-Z at CN$kBS
z<ObB3T(4AnrP(IKwrel>c+381>Mb)ZcZvbP6tK!y(AjWkn0zjOmFmIVnEA)YDY9kw
zmH|{NB8JI^ZUY9GPNou$yV{Wn at +Y{h#X3l^Q-(^XYi)3ac7f8y4j$YP)ybaCaK<xX
zYUb at W$i<IgWb)yjucqO}TYY5=Av<mCP00x=Zd_LM+pKKB*LwqlSo^idW+6udms|WE
ztX5*Mlyb6xTL at z^Azl@$JzNA|te<z~k+7cU%hJ?N=gY-&u&}im1pqD+v>c6K at Sska
z^`h>XD*^hsTv9D1EtL{uf%pBK5-eF+_=1m|x$cE<XkTZI;#34iAO9}Y-A;Eo^m=gr
zUX8%k)N?k&Wa at T{gC-aQhe}l35YZam8^YO$SJL0byM5mMihgZ_*(`(o{z>MCzM5(0
zh>s8taQQw{;!B6H4=PMwXQv>PP7E-VmnWl{oB-q|qJ^qXRr=Mk_YEy;96RiW<{9(X
z+euvcI^JX2B5 at NSTGLm3&H&Imzyl%v$c#<fosthrEqvzJ7h!ocX~1eTeo;euvHs)_
z;)&TtRlcde?@AWewD6*{aNjqVvg>nUV#pyYt<;J~IO&NN5Z_yiq~_Q|qfxd+4a@@I
zADk~5s9{$RM3Gc?TVjzU{L&LhEPsE*;Ovc7<z{tvs_V?(;mmTwQ3 at Fz{FP`?zlYeL
zk=G%#<o&$+H_$`n(_qg`2Z{PWp+wu>tB7ET?b>qfKuo6yc;JHgbDkc_9)6?C<HGio
zz58|OT@<C45kMRHxsUIyFNRGu%Z#?}%BJ@<d$tcf-$j3dGFL7h_0Syk*HB9s_5>*b
zqwVtn%OQGfIcHi${ePiSQ&bmr<=t4-mqvS#r?DqVPo>F?d%kf<_O8C}xGm}M<JQ8n
z^-t9&?IPs*GRkYt`=slDM?y#9xSvuOgG-IYR2TMO{gJA#?n>xRiR1jUzftR~_Ed)B
zwAMW0`GEfW{B+(vRE<BnUM(-e?5|A0AFnH17A~reyr(WV at x2_mzu&MNY9`sJELg1}
z6ado&DA}KkqSubUUEYf$R*8fsEH{t^*C0XX??(Z+t5 at IA^wa{+KK@`-WHSke$}9&w
zk_0CFu_iiKMK_rBuI2Htf at ***@8xJ!18792d#maql%+P0Yqp;7$XKJM}qgZN&C1hAQ
zFOu)7H`U=v7U(Nzs8i;TR28sWWJU63&0pSTNJswsD%Af1*=G=C%YAb3jB)+R`mA`O
zS?QyGtV8nC$HYE>eLqI<YA9yY4V<3ZhrEt?pNkYBTNt1aS$J)nO9PY@`HB-W<4dqJ
zp=>GuxL>|#6MDw)7 at JtvV&5*2Iz%gcKX$A_n`r0Cy1q7(2s7wKCLD=`c86w+v+#05
za}c#J#C5 at PR6G6<&&inkMd1G)E(=A1uA}vc*Ye&_vpwXOhhyES5Zs!I7ssa}OX$F}
z6X*^bgy|J!0H9}DBJ-xV{(+x at j7gQu(dFIG&Y(Q0Z#J&0r-+lSx5^PR>#q|oN1GC>
zx5|gEuT%N&jT#^6c5@|4&YajqnbQx_iAsnHSQd|VG=-Z<V`@`ztBP>mpASypdQ5z`
zRx2zLASD)txWj~uj=_- at Y~0fOcKGlcq5+)3#7a372 at m-&2kBKoX5v;=xW3U5Y1mSJ
zdSHT-03bx+n}A6u!_kMs&YGt^)9PK9TD}zV2Cd%ZP at 5rWLB-<rkuUZQCcVaM$i88U
zDjjFB$m(uA^+dz`iXx>@tz{v7>>23P4LR&mn;07^pQps(amvu2EP7*$2^Tf)C|wYg
zxgr3)a(xyW5#~tO`ALC~TccQ8EuZF90=}E at FJ?;iV5thg`o+8`M=BxZiriw&^UT`Z
zz?Zyj2gMIxMf`BlY#8Ot_E&$ifSu5_!?YKYTX(l|SwjU5JyL(4waK*X*Q<GzqsA@{
z17z~=zf_ at YUB#R*vb- at KmB*y)a-D9qo)4D|WQS*uB?m?0yr}ubz;wO7 at esjqUqlvZ
zaG>Sxo36LGOr$@nE)m8Z2SF%A&M+hO__T4N^j#{^%K?7gc0+(~C;sc*Z}i^BrPKWc
zwm7sE^f`i<;^aq&afnN?tm28u6Ob>21uUrV+W2;55}CF$_RBrtKrDM_49H1)_6Vi`
z99fAA8Ns}k=s7$Dmp|=Um5G!H0h&evkX2>B-zxxX>|p1{UlP!4^V@%}lnOsqNEO#7
z at L)oszEQW54c<M#89(fIdeI>_4eQfLx~kZD at 77WM%f*1|K3_&TOp4crVmfz~qdP_R
zY;kN*u?Fz-lPgW$6RqhT*7iAY+%ipydqixlhN&Vf_iSL{Ic9SXR!21(3-r8M$HK-@
zLj|pR3gAEWq`iAs$ut1KRdnN?CHiWC39b_Ys<EpEQLa=Ej#69q-b4S5jS-ar(RmC-
zv|&$hr^Tl~gxSQafIDS8H13+RSMKtIG^(jWqW;Tz2paz$1NNC*kNm%QhhhBIt5-DH
z<VlP9!Kz5Dft}KL!d<XCTjiDWFN#|*cnkWwph^=?;DgoYgkZi=7*xi*P#&JT{8f3N
zL7Z&3D<2vD_3bho(%>sbRyy&(r00*rk<5JvE1*K;j=Yl-RUfTwuZkJ<mLoJyV;4HD
z2 at _J)a~6uz!?>`AJ<)<AIU+q^pgowVM104mMl(J^?uKVad^d`<=4XqWRVoakOeAo8
z662ukqT^u%Pa{Vp6*?$Xtmt*dGdT`%nk<n&FV70_&y!t`EFQhqdC-4}LeG?dmW<}V
zTf10kBvW;&7L6;fSo+Smg?s<Lh#N}EOxWxn<j6LQZPmRI;mQxy)=YdI3KE^kaM_T!
z$Ul~pAteCASx|`P$vZ3Fy=%3I3u&UB2)QNaA~SuMc;Vlq0<dtTMR3!g#$0-&s8>=~
zT3ADcZv$YD<>VqeLGcintJwc&y6$MI|NsBK!_DO?d+%{cHreAULUulx*|U(9Lb%tc
z$X+2c6lG_nj7!&^p%5V>vbT$i- at ETQzjN*%_uN0Y at 7H~e=ku{%8lOVh5@^<MEJksB
zV+uw=1a?YA=4TU#*GoB_4qcBEK2ZnZhpddZ_urs%t~pCmufA*c3_?woKpZ3j{>)Db
zH>3FT;dk0}(MI9vdYG^S-L@;&<x$f?qFeQS8}HLk-wlw&xCPA(KFk1390^LtuZ^@i
zxWlyEtj7!dHxi<+s*8s?uKQGVTOj~WwXOjKCSLNe44&Ct|8d{!VG^6Wz`3|UC}y9A
z4e$DUQcdN;5$GrN>f|2nNng;Y>~R?=oIIvh6aUbLm^(7_KZnlCHBm|&D24q5cyl1z
zSD42TiK;R3qrTb at b!Kw5Fh1p&nf8SF2FTcau~^K^Cytoujd2Y+V6~8{63Wbtz~SiZ
zplg^P5T`uQ{w4zJz&so&1deWE6W&+W>iWv}XutMD3YzGB=8@!SwvPFMlz%+EyehR5
z5F(aa+0Z=u*@aQecHC;*glq5o0o at e5i)A-saYtb`&SYlu=yWGv)kaL}2T8Dr`RQ&(
z4=#8j|1Fjt+Xq^h>WCIew_xU`q!?z5OqeqYSIMaan=4go_2D3|h>FYScG3gBO_D#b
zl*YOrK5525_-|)DY<<?}%@Lu=M$TB=`IZG9uId6 at W}adfTtUGjzRpPwTh%TusK%GH
z)<#Pz{ypJeqr1j-1N)Fs^8UrEXonD*v5gMq<(+OvN09VZ%RaLRly6}6^G&~7?uz9U
zcV)r2ALa?1y8%(Hvba~^mKW8?PL(ek_G(+-6(G at yvEuZ(qsyb{t9k4Q>)&y4U_rPo
zdamh$jhep{6B0Wi{^fcCME-h2(hN*!;v0zXRT~;9bO91Vq4fEjrVN+9V@)B1uYIGc
zJtt1Rs1)y5MV|}C=o=x%W1gMNLvpxKk&?b+&b{c#yt at L85`927$bg!YB+#Kl=dw79
z8gSGcR4YG2<b_1(v`Zlb>sW4DutHk+aL>IhVoh)U#fT|=5aCQRbt!1IGk{v;;XwXe
z3p|Ir7%z(gHI(q2HoHXTraIPXQPyBudk+TclzttCXru)lT|?)rMZ;iu<mZa-WnZ2-
zI=%VPuPB!gP(BrLq7<5-V?`RRY4wX?7btEn(CfpN3o~8EJv^=?oqqb~;A((q?2IEM
z`rxa<4_WXTNRq)L#GKq7W9UT$CDi1VmSzbYN!@Ah^4N#`4Y=HdOk!H;f`7w{9tTYy
zicA+j9IkbmDubNfiD(Cc^YdH3(v~vgxsa>{g60&-4GM#Sz0IX<$42TFe1fiXPuv*g
zxlIalUP1H(Cx+pAdV`l&1K$XJ%j#khe7XLeZ`wBc{epFZZV?-ubvg>Oa9dTfb8%g@
z+=b-{8mHexN+FKxkn||7FaBg=#t{q$gV8WzEi+!L|GZaVcRNI1WXm4t75ClsL~_kI
z9GcBE^L*3l?&{9tKVjXK{ZqTAxci!LC90WBEyflPP*5alW)Vmw8DXZEN%v?yE^{cl
z{yv(&s4sO5+*xi5pDy+qrBz`CU|+doSum(XDjbfM*zkD65Y_=med2GMsiNSv&{j=$
z6`2ff669iwnoa%87!ipLH5NCR{ZUJ_VbA^TS-&99c|#JN8y~2GPHKV@#jNwFxR;an
z+=d2DQ#OLK`O{?|9ILqii&}kv@~I=R$lXti^#m8!8%DJW;Es)#1r;pOJOwyb5Xj at 8
z&4H%Di#Im&UW?t>Y<<o4Ql(A7zOC5(Hpj88i|7qRo$gd^+Ro#1J>5ET|Du+aM*V9E
zzbxxLTjaX{`jS~MPQ-iZFwZY_>{IC#zkd$J=ls~qGlh)TQhX}Di#yS_)n=vql;*+M
zl%Az>=C5Ml;MtI`_w#WhMMZ*tAlB%LbDyh-v{2>H<@C3)zm@#>cKn at qED|}Y?<p?t
zIY0HzJ_{cB8%daz{E|CnmL?hhlr_fntB+*%(V4`nMcTke|FPQDX>odv?sCEGNaK0s
zsJTaf`b;(^XXg!TE+8$3ARw0T_M&YNNG7Ja|B2(E#r{6n7)1b!u8Rp)fx#Or8GwSA
z%~WkF#3}46#*MdG;F<4?dH*Cmzc*pVI7fWUpZ|uHsM{=I;hwJ53(oDBatDAl+c06*
z3OJXDYA8GXjPplOx4|D}?|BIk0~x%vhkOOE&smb)b71gREBBseN){B%=KdxetW1g3
z)|+@{JR+CS3K#hSVGI#Ge_6foOoY^5=IF2DKg+%lq^uXKcA%Ko-N$#O_4Rt|srI!V
zrIhmYhai*pzzc8{bD<NO-$Kpt4_%OmT8MmPMD{VU3N=SPblyyyy{noO<F(~-IGg8N
zCU72xtS!--Gt?yAq>E}4g=wR?+vMiBM)VQ*7?n_Szk4<EHx6mbZVs|)W`w4Q?j{E-
z1aIW4{(ijrxcIP7vf_>ENiY$j+wdi&Tngu3JOmPpnBai9?nMr0IllRgU2_F+hJ52S
zDS2ENKKdpk9=0?y0yGtdooItRF~Ywv*{;|WatV~`COvzcnUuV(BkQ9+B|6_Pt=-w_
zBe*40F2yeG=&Wa5?_Z(XLVGV^jo!GZv?E`X#_=aB<y>}OO*nT#H;-w)mQ3{emovMM
zx{l5I?^-nxRXUEXJL_+I5G+7h`u2EUW1_D|4r)#}`T`^t_ZEsx21A5*u)I6i;BE8X
z)+>ixKlUzo^o1 at 7ZV4B6YXv+VZ|Rw$Rcm}TVWCRtwK<WpE8D)fXt=u{w-MeX*0 at 13
zP~h}Ey^_^nc+O3SM}>-id*bo)RcOux3+99`=hSfIP6^#xGBczXhUO7{;OjSi%NcWg
zFrW0tE}N7Uh3Ae5d4FkeZ>Mr(+}sUwM(?a^P at JbiJVX(8bldgZ-j!ZcX}!|&T-}W<
zMypdne}6iGE2WE`Z8PRDC$fh2@@K-o5CLVILzD0a*wxWbdLhcRef`(u9*fv;y&vju
zXB%s`7G14(6tP+WuC|;ko;U%lTAe9fhUlb_hONGJufH_h%y<PB{N!y?c#}55dp?#E
zV&IR!5!Dm}YNc`f=PH+IK|_&XkgEPPmn1X=h3DrJLSy1zOdBAEGck-UNW`}Pc|?xV
z6`4_$UMQnZw)!LV%O`JZSFPzQo^U0op4=XKcx4ptsfZ2SUFxYxF}%!WICwhv(5ANP
z(Y!v^8DIb{1Q2InW;8i2jPUFIlktP8t2!B?D>oY`$dR(Q1b4}zqt6_R88_uaXN^XM
zv!XW$!~s^=QS^=@d(WE%!(CzDt at 5YMkb9{Rw`nC<BC!~SX}lH650ej)TKd)X;v)p*
zf at Q<)R?}TT`C%FAGGQ4D_Zf_KKT89W4*)GEfYga?NM>hZC;y&`^C$Sl&{k~OY>Grr
z4WhT>OhpU at ***@M;t9<kj5y@(G#bMe)lPQpu!CfsD{ZFxKAD+(iKn$oRZ
zpPNdfzvPtI#ks^l8)DD+68WT>7i~u=xU at Gy+xDQ!tyydw{)REx?OKp}10nBy<zMoR
zPvYhBZ0T<XQ*{Lr;@uen%}cvOIsoQ1a1{+m;q;||-3JkbD~nL at H)$PPzj(I0;l~1$
z4mts}7h12+)CfRoL?Q|^FIWutv~rXj at hv*UI6-?oQ_z)AFx^Lsh!r8J7bI*eJp+M)
zzYDUW{!gv~q0&PQfas2_Pb14xVWJs at zw6EstU;>}donmzmP98_zIAm4?#%)NdVQ$I
zr2 at t}xKmKIej3tbK5xYN at 92GYrUJ54)gBixU#g9?qUlh*wWioWbNcONwU63+ at jrKD
zfL&|_#O=_Q4TZ~gEFfyoT{#XXstqrypC`VEQe(x?6M1V<KmkO4$Q=g!^Q<*Plur~d
zc6H?X2I#2ecZh5B+!=zK+VtxW<`4f4Aw{R+t4ZT!{rQsSsNP~<`+wzTktxPSU7_N)
z<!ZhdA|uQ-&BrK#ttp_0>#C%#Ly}z`grt&*>yX#f{S+p&tC{iPrY9k^cAm02Z)_ph
zvJ>bIa|3eE(j{@P at XIuswxd#z<u87qW<?uoQpvXP4vC;<Zl%nSg52bW)w!8P{P*O3
zLTJFD+M_LFxl?Iv6nO+ at 4*3|RExIqsE?*%)9MjDCboPqU4E at w=Mn8dLKcXcmQgY|q
zM&FM6L|b&?rR7|VL`h*S-Ko^ImejZLsb&Is1(0oK<vw6o+Y^Y&i+-WJ1D;42k}NK5
z at O+pyv`7{gG-A~ajBt&txO`GbW;frI8r_w*qr(}Hp4%Y`0`iy|e%Jqv=`iHVOj9{s
zAfWKK(=VRy-qZ4CQC=;2NNd0RJ?p(^D at qS(k&HUGp#nrYA;x74#$$a_CAu4g(EgW|
zQ~nQ=Ok{x>0efJPK850WYb=C#+?snPdd}nw7_njcPa8p8iAapN#2(AW3-BxUxx0LE
zbnbMIo^9=26>1B4_ at CJ?#-W+6y7dODQ7uGt*qhn?yg9l@;U8&tBEUjL%5AI%kY4FW
z)rQ>A0X2VUESYngErkXjb75MQ#H)Ts`5vn-tErm!0maMN?#40Irw?ihn0(O>$H$gW
z&hB9Emwq48UbTJDI#jLvJ~#)hw41{q5a<ls7PebI#<IXN1Xcqo-ib}MBdGPc|Ac}T
ziVg>`#;(YGODWeL2Yc8p?e%&mbsI;1JZ|Rh(~c*{huK7WTU&db-~X6<?5wfhG4voR
zDa at XGr6KQZ_Nuzodk9V+2iX?JwYkXVd(xtR)tngINU~#mB!gSN9%hyqHf&{{uOFmd
znSC#virMl^Ci}@$MwDONv_pZC5X|mw577azVv at iSNrv&YxfkxRl8!H|wWxe&Xdwc>
z^?KIqMPoG8XXA+q?)5ajO%tQbx&c~g`~7%kb&_C)Rl&gyBkB1URmQ$9MYrY1pBkhL
z8d&5_zVkTN)H>Fv>#Vqh?_MW)P<^A at -0Zk<rXmmu(9Pj`V5FAPQ)ULGPKQ~F<^DIl
zB97Dy=UKEQy<-fHQM9*SHqSiCW>ISBuA}ZNPjv%C3lfLqqL%qaoj;bW9d>QLmj$@H
zMivXee4QtKz~g%@s*~^7r{<4<-s>{exmq{}K##l!NM*|F1-jc3oPfpKGPoycYIwq8
z&wZNih1Vy+(+TKp7iVDcumr+x!ix=E*IQk at v`S3>TrIxzFiU1?!|3DI7++f`+4G`=
zTi&#MiBF|&p3Y*Q7`5?MB*b~1&PI17y=N=5w~H?sh<Na{(v)9Gd^W>F1?$XxZb%<+
zqJM#;kh?%b#pE^(y}HgUjJmAAFb_#4M8<@N>5X;cWa<~ApPvY#qZu`^frF}J<AkDt
zuJbZa=G;@Bs>FhPks{N~t1l;tlk8t*d>`YjOsK2B-{slpdF1uM>upFy2RtLTTV?k+
zic_ at 52i<J_+DYQXvkWRT<7Q8X=7yPz!_2!VFpb-RlK*ni7VV{grTI%wod8Wz)cLP=
zrCxy;mU-2wcdD}|u}g~lp=dR2bUyoI)r;sZ0C`~;K4e$`3HI54^dZr}Pul&FiTp3d
zUnJAUxrby<Lv>S9;ZJp9Uo5 at qBEG{wRap7~^$aJJBlqFQ9Q`7uvz-^V0zMYROHQif
zm!%8D*(_fE#_N!@7`AV|pM@)u*=0QpEq!PsXTA5wPA!Wd!=6rLXljrIz8~izXk9Nz
z+tEFpCd<wm<D<zti-oQ!ez)^eqXd3ai#ZID6g*t#11Yhbl5c+9IxnMYpIUhLtzzgv
zL!PO at RhpWW-rgXED&G@&+!W_<LfrRnthjfiDYPMXYPQ-2j6A at pNsJJao-9uD#Jx9z
z#O at q^qyQ^M826C}pqFgR{#_WOurv8);VP5bOl23a#D~~E--PwDW#SFW0a_`@{r>rl
zHs+5CwO}w^x`3IqB|`wOUW&bJxSHqBToj<nQ3k|kzizr&P at 0mrEry#kkZbt8s36ev
zs at b=lgQ-&gv2`2yL;b at Zfh(&P**Fg8yEqo*07V6!9p0Dlcln>E7WZ`arIHpXRG){h
zT$vqcpRJU2b5D0U+hD3NklmAg<tmYFrhf4s<ic(CH~q?D#q=k_#VbNWfT)|stjqG4
zYFKZVB(RzU5lS2z$`5_KJ>m3gM>@sR^4a>AP{Ch&7MbP-!y;lBq8VYSa&I}!SA-J#
zliqUi^ZE35g~)}P>VU3FE~Oa+jd5q*Ogt*`1v8BCy{3FK*L at DQk(k-YLkG1R*n8p&
z&M-R$yc5BxlkgZ5IPk!)!L&tBu?$)duC!KtWlljDbuUb2w-McU{k6<D6ar%qT5|6g
z6L{Q$np25ZOQEu3jn8UI=yuGs*{&}0;ZPK(a&kiSTIm6z5<JPHm0mv{VCMfZ1oo5&
zT)?NqL2Qw8KWiha+^53~&PxWi86K*B#$lhbW9^pTu2BpR^w^k^$?XT^r?tJAx`KYO
zrJT*4giDxtDx%K!Kt)WOpC;aiQ>gFyy{FrZ1+7`&Df1IUv>IGx(W?=IT+Da(j8*c7
zW;3SW_1>ehA|1QrF^!Xr4cUd3wY|MUh)^B5FuBi=m=dFLQ$!YbjTz$#Jtlq}yAj+N
z8-t~or|F)zVhPlgD7t(3vn<=04@*S?0)IPICuW+TspqST*=f&<Cc!H#PkfW2lY%wa
z26fOc48g^y-3PpTcIv=wre7W{mkjYRM4{{key6;rW*WXPs3g}h;8U}<6g1rwhr<`$
z4GVXYwll5e;dZ-e6qjK99L#H|yDaZ7^;L1MRySW|O$opMO|I$Zyj(@f35$kaS1GWW
z_f)$S5TMo3Oy;4FX^_S(%Rn+17y9O2$l-)e7|Y#P>*I#}ti6C^NnF}h$DT;Sr{olW
z)#OuA7`I$cOhz6^`0<t}sEJoJyp4GW*-n{t11h4}xPLeD=;5*!T^e^tZixdpJT*5P
zR9bF=+0y&6P}lXkK1F<BbXr8rmrjdWIo-UF!aAH;1T)jmcU*+9r^`0xWZB<PH*UOL
zG}*PPjR4JyVM43UZj`$(T%19vLwTg-wy5QJ$KjePQIQR222pO8%GEQ{(~GS%D_9hC
z+$8N2YH49nym4J-l;h2bkZu1Tt}hH8^_+|4&~BBEaydXhXBwvMSKX33e)jNCHx?t;
zYQy`h#LlA~MV}#Bc6qRunqH)a!>?pcen|+VGF8|D>hCnW)3oTlICML5MCOGC<5wf?
zd?Uzh&#rrYyI=zRM;SdwR72i)?LR5*UrS70DxxiZilQd}A$@)qISVF1(a-y|J&m|3
z-y%{T#9QvJCnV<r)Rc6LNBW}K6K>?3Nf~>q8jW9fE6k1=&l}H>eAv|8K`^YL7<R;i
zmcPpn7^)Jwj7=e6wfrhuz^vzqZyHI^>>IrC1eA@^v0!p4w{s)!msP(u{}bqwV=U;^
z3(Un`g$+{?oGuCbEH|>u{rRNxkdbBrMIKHSh6kXMa8%QlRO+%~KIdwo&CjUzt|)fG
z$-4(_E#z)pFb&%kwj;e8iTqugDnCS$Z4t?CQDi&Zn{Gf4oROQNs*v{2hbl}?A1g-m
zQ=4n^Mo8hA!TwCe(PYJt8EUn1rT6{iN~i>Ge+n>#1fk?V+yy#YY)f$}W#$%SsnIby
zrOtq3pgUd3GX=`@5YBt!C6JO<69gcOn_zheZQ`9nNWvbz%Bs+B>$D at M4VZNXe}vq>
zg-;a&sJ(j6PTvr&)M{qMlZ6y*@rRi~it~bVXrmWzkVkce+x&n(plK0#K5rWaDZ?4$
z59yRXT<M(vC}aVf)sGbN!KZDDfcV?WnN?GWO=FPM9{iSpQhFDP+rTbnF5C8Mh2W}l
z3uOCO0|l$?dL>_pe6;Tq*@&Oi4@{!|P#;}&L=?=LK<nKV?f#;PHk at M(mPOLvLarxd
zDJ*kPo~XBe@;U+i?ZG)c!Z-r&H)?8!iViPOD`y<z%XqEPg&wIoLi at C9{Og(JBbOfv
zbehUc9f}nQOaJeu9G@#>fzE_3-2Xr#z*Z~$E^upT{C6m7Zf$2j%`VXCY+gHe*ukJn
z$HM|9!MOjC804P84q|U!9u+7Ym-Hi~Ey0cs<9!|~>F-v|O081_mDYaFy#ux7VGU25
zNRM9TMz-ABI=P3H%2`ElA5=1WxVNg-qrM+J%nGHxchYyZ%^@M(HmE!PZ(B6lRn}FD
zXcki6wpMk}3%__bcZOixig|bSkTDH1)@oAn7ln5*$_zg$<fc<p_4j}jB=VJi6urku
z*L^Dy%l+uNZQ<_T-f6;U#_rA9=J8(PxdKzja-c;HmJWw3Q)_F0SpMQ1C<V~+p}M2`
z59}F+qiYrqKbo__Zs&0PW*+C?U_474wSjCeyqy6SZLCL_K2ORf>gAUqMqcJWYM;N(
zc);u*I8L`#|M%0zXRMmc&iP;IKL?X-g(?1BhK9s9-7RYkf~5Rti%2-%Z<-N?7%W6+
zDl*74>1wq&{7Bk>mI&o<8!DiE5YwhNlkcz3|LTB?HV6CTLL-CgLv_KLDTE}nAv|ld
z6Nfprr*1{<gU5X$3YSNAO>iV3yf<=L=b^}uS@>G!i#{u@#cDHv6xk>Zgqof{);oOp
zMEjhVzz>h$eksITKB%#}JC+2uUG-;ssCHQTy{q~xpvm7_dHm<m^|_YgP!=P^F{LTw
zc4R2S_TBVIe&z6+)8nAiL7d`wV*UFD>W=312kp>=)183lr`==ia*P3M>>9ABsdq}t
z6AT63uHR@|5;_bQ&Srq;rJ#7^rkd~3??~HbhwThtLD?B<NmjNejI%``=!l=B!j8V-
zcDoXF4<3_Zm%Dn46e)eCEOnPs8y0<nP~bM{cLAaWs1ZaJicuqmKbfVr;(pzZFwJSN
z3iV2YOchEtqE#PRZL8yZL&tBkG?W47M(ykgT(28ux^W=(lB`AQ4;x-t<fM_hfx_XK
zH|qJ^T|iCJ0F9q5c4P34%_~lC)tOA^BqMIz4yB*?pcOWtOyS00N7uat4OsT)SD^@Q
zzl{mpeS-qJvwp&JnZ_sEox3e|<@Md9!k8WaeIp+(?h?)fGT>>Dv;QKp!9feRE`z3u
zxXL_D{EuI}Cn1X3LzkFzHB21pFOIJ*N&kIJxT0U(AmkHMOE_)P*hyf)zt^(WkKdCM
zww&Y`5e6b={g!UAE^}Ct*_~L`QcV133Ryc4sxmDFcEh51GBFlp6L3|bQk>A>vH(R(
zr?Ur8C5+hq_#3UKd~PriN&^aPE-S<OFbn7X<o&e#RM8p*Nn>ChSiOd=w7|CJn>YnM
z%BRM;vw+?0bw}!kmzMaUo1*8hAd6n`Tq-jN>6Dq(R_`A!I0X`<h(u1ZB0)V|lU;Zf
zQp5qsz4xla{|7-T*W(fblo5aQP?xWi^5Wa4v0SpHj{>!Fh*cOFk<SzY8vZ|e(SfIU
zr~LrqeTIAu-awiw(Aw at wxhV9u@>qc_67*%GL}BL49UiMw&sb_TT2Re2i>)FA_?$>7
z=xjr>oEU>1=<$dQ0Lxja1?dd>VhXXUqnIcIV<O6-vUcD!3cebaMCa}V&9jF};S#P}
zB#LwO!n-*FxONcT*GdwGz8=(hv+TZNza`yNN;GE0D=pPbd8NiRP07nr_6~jSL;(LA
zDe3Jgb21 at y?bmxt)__i2qR1UMwlMeyqKegJn6|Fb)GbGP=vt_>z`7=n%d=N=?hn+(
zb^Cxp9Wajf{&{oEB|~&q9R+xx;Caq{*i|UjzYE(naFRXV70Q>KEw~HN0q825Qe52#
zJ$k#5lPnooMPZc7{}LI at Ot|j>^u5N2p0M`DvI4q{g3V+`3x3u8WxGbUqaVH!{Gx(s
zEd4W1?l}#cPTHg%(QE9rApXM04*96iFw$FgY)!IVgUfS1X9i4oQa3sDx8}ETG_`uS
z&zCwix;lnun`f_uNU~)%L7x&%{8*@o6Nfn31~>QtD7}d)I1IJ!Bz(jX#Toy>&equ}
zknHcwxyg|1)HhtMrxI~%Jm49>Vr*Aw3W+_qtU}>2Dx5D3DTn at WmomSWlth;YYRA9`
zr1z$fJbD<ns|1h*1f~*VxA~Ut#RS9$Q3sJ?jb3HzD~NAwM at cyY;t at hC&TiiiZW^-z
z5Er9yw?r1A=k3Ul*E|MpKjbg=*HXRt6~b?1GfMp<q+BEgh>W#zFYdRE at 6U66<+Y)5
z$;9Z3t~!@c0Xtf-Dx at 7ye86l6R`TBFrML)7vh`(SOexM9d^22#k%E9<cmCf87HAw~
z0xsfUl7$Ir(WHM$*=uAb1^HVn4YcezHSTgoTWjlpM4QA1M<2CaF{llX4$0xe-~%jU
z`T0peNLj~eRBHzQ62<BZip?&tIsIh&pr=7c8ZS0L@#4Bkw()MFH>ng8MfQ!yE=G+u
zL94nFj^g$lwbAs1BH9eOiia{SiHP6z@#A9-d6&?b=?9iBMkbW1;d3v#0?bmV<{Tt&
zlp~#i|0_ragfY)U*9Rkd{!RO-e~*;@ZR?vbZfE9=7Nj2=V+zS~hO$XQ?z?lK^P7lJ
zy5ZYN%EuaX2n84y&m9d9$-U at pN|WVY*XeihfksS$F`)s<ItcvKpnn>qNxLA!>~`r4
z7cCo(rwX2-?u=vEFMo|ZeDGMlB9bRs`*t#`F;Bk`$-;d2-{hg#xUPLxayS*shM%am
z7|*a=FBE!c7X6F;l_c(d(2iCC#BQ;;mO{R*^~L+U|0 at RXGkAl;9TG(EmI=_cA<CiM
zFY3S at 44UW8V3dW|QhI?-jQk~mv(R{xP>qAQnU*Gp__)|w#RM$Xu6gY#A4z9{woy1@
z&qQ>K*=;({iCf3unvdAkH`-1bVRIteSq!Qzto_nqnk8hvTpl-qB%<^}(oLVfl_ob9
z-1|5?&fGIPRz7JNoa-dO*$r%}=)Ie%gzgsNXZps`U&L)P*OjsNKc1~W>-jOdJR;1U
ziLXx4am>Iofv(-Dr$S4&g9NK$o<J>%>Z+LDGCl?K`jlUzsO++6zdUyuCqoLhCUl)u
z1Yb=*?DPM5n0)%HoVH4>IPw>Fnp{TI6!}?ZbYJIg`C47xX0 at u=NXWCH8;oj at j<+?A
zbWR{s at ***@r!c=*`^OKxHrK=8YD!<{pFmLm*rzaHq%_oEL5nH;a?Oqdln0CL;%d+b~
z#?^(l@$agXEa#6TH7d_8qww&ZHC8UR5bUr#m<N#klytC&N`PGH>%%MAGZ@*BZ+<Db
zi+@|1gY;1HQ!R%EUR_TQUnvXa0-DrL0_3*fAC0V_hU;ajl*WsmCk%+d+vgQ3cThMc
zj^L2*l#l)Yc3cG4u7+lgi9f(COWLf at t$$LEXt6HE!NwoHTjJ}}Pfjd4lvZqSKHiX#
z({m;7lX8Gx%cnc~=$#i92F3#ZHcK1juTGGZz{xfVZpUCi;2&A!1>am^3h#kGoP_TS
zano(z#-)dYvE~_oIKmT*U66pZsC;PU&~~tfwi<aP4G6HIoO_IS(~m+YftC{*X1twd
zHHC*4dsc_`@hb?m6LhnZERe6?%3+2*MY~^&UkD27&&$+_rS8yt+1lO=cc}2Fve>)G
zX4JI1rtWax9m*C>6VffHZ8c<D3@;8Z^&%r4x*9HIg;`vKWZ^m<?A%Iv;+AH_6%$_h
zmx_CQN)}KlEaLYP_?!?I?Xv#bSNWwp&9jY#@(pr?QNw~P<C_+-&4k~+{wnrLNNg8%
z77*X^2mf1U!m5sax^yzk;;T4Z#{nL`-H8GaXzC+Z$-A;y7~N^)pyr1?lLDKo(|&L0
zYU1UvKki{WKRUP4eTf%X_54P!=7vg!xG6=ehQ1sGiW2+`odLs_AV!@yL#BLtAsRw#
zfXIgJp8_hE!3nHT4s^9}>TSVD@>P|#Wc=0dw8ClV$R9ZrHz7~Cwv0oJz$B{fUv|JO
z8Wv!ybEeGw@{bSUG`n^+geLaaS7t8$Hp8zq?79_(N1WObO*_Q*`}YF2Ps;ygCqZuC
z(MY1gJ%LzkH&A?oo3;-FL3HMkfzKsCd0r)N4zfRAIxI at VdQ=ASEeo){6q*v+=VO5I
zKJ*E_g73qp9C3j^_Y*ERfkZB{%d-UdL-40B>Vjn9<NY%5$31^cTvL#VSJo18hZpf)
z at ***@iLjfN$ZZ20Qv~^|Nu`t-DtdEBfYK|Lh|j3gds>?ncTY<n0HFV^8Ej5%$t>qD
z*^E%Tg%9E at RQko?Lq)DPlb5n-qc!*}Xix<;-e!G3znUI*eulUMv<5ZTUs$~4JU0x)
z&$OhY=7!^@{)PZ(BdjzI>7j%6{wxjgg at Li%r5&33z<i?x=__C(QG>$aq%%-r5d)Mw
zv=M~H5&|zo#|{2`MdT-wD|GY**MipwfRU_Zkq&dF;%=pGQZXmn9>7;nrYq5Pi<1rU
z({<Zk;pEBy5LHoN;B5_fP<2mTg%L5A)c6A_*9`@p5 at mc^#l9||l7C`+M2uawnu at +N
z%ltlPb%NQy@#JT9(7g&V%Bwa!kE0!+dBWT7GWqUxV^jR&vu`!z%lH)v`FX!-o5CYj
zM9kSRedL|-;!t#A%VUv6*%$3{vTq+|sUjY<C4|{ob;W5~bCnJSPMNQOTe)onl2FOk
zg~D%tVx*e$ki?lt;Zmdkc^<kdNC1O(Rq(YcL$C?{w^b`sco^DV$<6U-gQs3$d)s`F
zfmtw~t9g#hFl0U5VGiu73-0vnO)Q1M%x5KVj0PlUmZ(4-%Y)_zwGIa~2yRs|^tM6*
zl+_858>!t&Wpu~dI6SE~ibC>Mn7FR)zGo1fgfXcwHS~wZPK&n4xwBg)=Ei(Hdf1YN
zcm!c`0%92w9x?-etl98BAgF-jlLAoZi6A`<*1$t%|IWiCh~2qT9Yu-0T?FBi0a#H<
z;lyhxxXm(TB!DV!SNk_Zyeuz!lk?Ur5yQ9tB+%aevl>8;8F)dZTJlWghDb`UkEh*-
z8O)kFf8N^Z=I+6D$F8oGh4w4bC(K~TOFs4;gm?qiXO{w8N at XriRZg!Z at FR7+HJ)Q=
z_BL*a?rM5-_{=UkG7osrxxI#lco<P0oXBBy@>I>zw_0+`n19f`X=z18Zh$%I=I=W0
zpuyGHRY&>vlKM?h^f2cn3FvXq$-hK)1LkDx1UUFqW_orF`g65<7(|t30yL|rl?v>P
z#L?RV|L||Vwi|-;zi#qzS7uu^>It#UH4Q9Er}4;vb$3no3tEIz+qfMt30D-d>K?!R
zY}CohMd&05tKIUr?c@^iwR5F)OS$?zD3>EJp90ROt?z|+un`^bJ^QsRrXTP2PQI at Y
z*NI!yWG26o^b>ecP{m|VdR>p~?`&VH5uHCLP8=_-bo`<v)j}}3#6s<rU*oa&r_e?-
zOxxe{JC}L?Rp<&}g2Cg at QaCy(+=3L&5#&#&zK%cCzYG at Rr?3p1X=o3)^;hko(B2O}
zQqdWydL(npIY2E1&~y{nfZdLkn^#?bm=nl<7RV_w4vl*c-r5a3QI<b8Z|qTe5B7W<
zGObn(843z<w1J2o_TGbLiQQ02wl;a%(BFJ;#!9LwmNfCjk4Y{44vV{!@YS_@<1#f4
zhe&W9rXkCcPNhoNE_03J^X}fbm&4xb at 8$b at r)K|GfGkdA*pgV<GYp>(<!96IqCFFC
zM at W#6(u<DGxXGbgM(NT0vN0{q7E6}5s)Tj~`_6`5c~W2v5FvlTN|&{GPYUNJg_Azw
zGBlWdnkp{<lV?HAP3ULhsWR~g;M0NY=v3S~YrUD9PQJ1$tmfb5cWAPVwld7l^mv7k
z<M at 6X(^zegLih=*LuxnGRbBF)+3%uh?(zRCi8=1REyDtMDW*V#?$cS{0h4zlGRy01
zRSV@^zA<9e3l{vm^;c&7jDM}|NkwVGOo96hRqnRF4zB{(t^-P`z@^G*Z5 at qp0XiYx
zn~^zgt&~$Uay!I=)HTIw_g1EJ8DkO>>GSf(&dEgC8s%s>(`T2LAM|u5`sTQVGTnf`
zTa at NxE0S|0zH%t%sw5sng6AqsAx}W~N0ct{&DUDwv|d6;2GBX1g)@bA!0Xw^7eEyB
z;KjZ?wVs_DeAIie$g#Jk%}3?VCo$ioyI3#4GW<~ic>wZ at jKEF`=3XAz!p81obV#H+
z=vU5ET>ZG76`-8W6{kMYfSj8_bt;M;1kg{sUE=Q3On$k1CpihO6_8`z!69_&aT?%`
zeQ9K<Pm8s;qhMg%nvnD=4naz7it9C9wqL7x?svXlA8l*3JIIS&&0eGMf9xF9pwAu5
zOWMCWq6C>CvjdhS=lWrwmupKaY!IlWU{<EE1IC?!r4UdVSOI^WtqNX*wCWKgh%t~*
z0FNd1zj}79dKis2SBwn&-CC^<Uo7Y;k4Z`ZHon{F5nZ!nMKR~*$eaTHecT5<sjyo)
zbB;Mxifvb-o!2&;E%two<*iQW1-J6$J?{c?XU$(rGK14mH)62nH&S4rLvZL0^yA{K
z|H!3~w$q{kQ(a7uHx2POWg=>Af0kFTG;<^jK$GG(o=!Q)mOH-lzpQ>bN;rGm$i7VU
z^&3NJNa2cY*Cgjk_nEy-5#G1vUySwuo5hkcU89AVKqhY3iXMIoCT5+p{{7RQm{2Rd
z$QH~X`^N&l#|hd*-;ef|U+PQmfVU)OxEBmBv@|phiZl19w}h^vfbsk2`Y0s3PS14y
z-TJ#;F|UZW{$Ro!r30alEw_W&+~$0JcrJxmS=Z)!Kw>1nFmH{KCqR>Dr7uF%tj at 4S
zFdpvxKBB(KC&3JC`)|Cp12dPZkYk{X!V}PP2E5^Pi4bB4&X!_x!-is46$5S~n6o?H
zIgwd<7+wRk5m>+7(^A2lzd3$}0y=2}L9E}>|03i5uLWgxt}Fo7j!S{_Qy at EIgp!l_
zwVW82uh>KD at Jw$Q|6I|u8op)^@~m`o9dk>SEjp#Opcr&k98ySRlEj^rL7jl7gSI1u
z_-A117gQpwmLd^Sb-NY<nol%!N%!2P?a6+!0E3-_WtmS*d4~#HDk at I9^g_I1s2wAa
z5*QQ;wxtE3jpOH6pvmZ%lmeolHdGJ7h6)7+xx(-B47rd#AD7~O0`u#$QUIYf3Nls-
zm`2o?LSk6e>D9ccTy9wVQQ6VZMMWzooc#Q}$#v}@MD*oCI7EUO70*ScO`Y5a`lm#A
zYvi%yFr4LLO;wc*V$|WG^u^EbazIS0GXVarQ2MA++$-c*zceu3(d$<M0UIKrZOy3h
z8`eh&aVMd#I((u_aYP|JEghZrF0V}Fu`nwzHvc;2Cv$N9plG*I_o$vV-Rf2!2=fd%
z0_BsSD#V=u2O-?Wkiw`7tO;;NNdON7Oir-jqw66Vrt?}p;<xE>(f$|AZoj_X=0V$#
zNob>_V1{=RjnZ>fb-mu}j1kcnn|a02^VU at J4KSU>14)w{-FYcRxrw~4k4rG)?W76=
ztSPEbmjoIP<_i$i9bT|1P at h|cBy<6l(1L&eTqf+bg$t0{rUy7q`1(FWP-_}dPA87N
z^H+Tdte)6jUp=ot6C&h0yvQ>CjZ`caC!L8)W(eaMd<DUX&Vw-6Q-Lvur{7Q=(_*6q
ztuBEubC*LeaAq+}tg%7ZaGB0vXzIEjr!*v<3`VTD4{(j2QmF at 9(tdKGs<E7_xt00I
zvt&8N96MoyY{?xmwRY?Z8O-B&n at 4lh{A|nfjnqrB9eV~436n8GDI?WySl?;4PDdu@
zNA=EouwZyoqnGBZoufQ&frBMl|D(Ek0lf2zvlJF2*)Vj|+7LT143HEgfEEPG7UBRD
zI{|`BGPtj_sv0nP>VIPXU(O6wV7KMDWQ}><Y|&mrOOD30WH`ZPA(7$}mwF!>tKiRn
zn7F=#taR3Q1JuEbDM78YWId-AIu5k*y9&~l9j`y={X9BY+A|sF_-TQx&i(fU3youW
zEW^u;2cQ95TX-Qr=$7qvT|UCI1`#AE4o~BDts^v at ***@WW^NZZjSUln;pPl-fBIS%t
zy)(r8uq$uop?d3s&cOlUSw+T#r(f>MQYha^kNBMXUp+HUofQ1;F0ciW0JkASu^vFo
z4%9`l#0}hM!Go`>|FAo}Pc&D&JwU6<p0usR9}IHyJ1Rmjc_G+ at IBY@?Hc@;R&&h%p
zi at Ug74lc%Wax+9#V+J0biNA&X{7xFCkw7GyVtW+3mw~KmRbj=OvH;<R1+(>j6nPN_
z-0eE?8PXOjqA-b&NzQRt^*Pt;i3E$<O`eg at E}ZwYf?HDmt=JQr0Yq1tHdEbV)A>Qe
z?U8z98S}Vt)v&AjR3$Cr0T`;1S;2k{(a~_RQ2Y@(M-$6{bGhiVjFV(szJ8kb6$mF9
z-X;lBw{}v-^MoR2%!xS=ZIZV(0?5Eaz>*FBX$t<>0ZML`0L`K4hNE2Us1+Jv<Z3VT
zJ}Nn($FwGMTn9m>`F;c>_~j=Wh49L4g*_Gr9U&hbn;iutJMl)(^t at lD#yjyfMQ&t4
zDV8y{v`;Lk{OXeKmufE93MfWs*0fgr_MstS at A#+qfe=^;v+^U>^ONWMb1tQnz79!-
z2pQANH*cN4es+y#R$LDmOmoM2uiNvxi$q>)yhnq2V)?@Lx+tc%l at ***@e{Zqoe!ZOm
zv>l)JEQL1TxD#OJ1f)9wOcKDrxhoi4z-7<_82kkIL*>!GzZxS|eHSV28M413{st+A
z>KR*8$Wv$F3;5!n;E=*?{4b5NTnf;$i-A-1kf&a&dS3>Yb$~|MR>jRVKL0F{RvU5{
zEQ1 at Rt$&4|dH at 5j*BBRJiE{Ac)uPdhu^syK%!h8}nH2SkP_|t8UeaGMEeKjm&g6Qc
zda~g2<t}>0Z&tS2vQHQj(Pg)#;Af-r$lcet&j3tpE=ieeZ at O4+eLStZa!=FtojtR)
zbxo%D{0V8|x~l4}Qqs0GW%|&Y#IBXK&9#JOPr!l{%1_j#y*O|M+v1k8rHhUimXK+z
z$c|d7<m{FCaf-R;s5wPMqJF;Uxd>?nU<Ir1i7sJ`V*+x0OhZB@%mLm3SCke)C&q&C
z#Z=buo}aZ=$kV}l!-wzp+pDF4TuPC{8L*smsfUaqAO6ea3$iz74^mzsB(Awf*U!c;
z&mVv8e>6GqoaM0iSzm0Lb<yPv+bfb*4O at 1s%82v1j?&w;rzzJA^WGBrOL5$T2Gif*
zcwVmDA;jEJuqs7J?3*Z&BBBLX!YP`QOUlFXu|)|O(Oyu(_tpJZ`gyPy_=t6o#Yr_b
zeB;xEmyjyxFdtr21^ORCBKvI5HTzgPh+Z3fzPVum6$-bqEBA&AaVWd3$rvfz-s?t5
zh$+-HIUp_$?=sAW<Gf^kvX?NVO|pv5P7KU8%}I9>OE<A at dbDl^_`Wiv3E%<akM^Vq
zUeu|P8YA_QPSseJ$f5e<aH(gHsK(9s+blovjXArddDa;pISv<tpsN_uk<}CpSLINR
zp~sI675T}4Ic-+uds%k at -***@pF-hn!}KteDW{nWxoTI<?iNwzMWGO^-hA4 at I&#k
zabo#iP1N|IzdYJvBHj?&qVI}$dDTZB>noa!++Oany$JL at y9V-+9>A4cy+II^2lt$d
z`_UJvgexF-x%z2tFN1KU2hJaWA<o<)X?cJ=!A&V#gcJ@&yQ<29w~0FgjSt|xJ4*bE
z8y&z%u^vz_Y*^3zI1J)3->StkQ7kfUB7R^ZzQvIY*?yeDgkr>6Za!7o{NIgE?JtoW
zWJ7x!fF6zk>O6Xz$E)izEi-CE!u^G;(ufCV{ny6#pEbr^^#6X%AG-c_*6)2^-JxbF
zSN5``oyrzeCIh7yq1A3ZdPio!?e?%t&9&&Zc^j%bIp-d23g61vn>IpBwi at E&td%I!
zIhw^{)Fg{H!yqft<p|7a)J3PX%7xnZy^96cW at 6tS_K2K&Coh#~nEF<2eh87+kq3I7
zj}~zCG@(V(z`!6ge$E)68<uVY-KOwpVklVhIsweErN-R5mqK{b186|XK1c?)Up5;P
zQf13AbPe~0rpQ^8*O7%SSpgj!V?a{Rs3?9%_mn<ZQ<x2Yr9zJ8XV#Qjo_pHWt{<BU
ziSVhATdR)WL(L4oUtSJC*<J0L+r1N2G%rBkqf?N)@~gjm=sSUT3%)h<(!g#H<6U#O
zwov`6{l7`_W%mzKCI at a)2nlL65V=~M%v-+L-!&XMU*4)AU724#o}Jesey7CmGaJR&
zK1zV3L275n2u$J3cs#twnr at bo*umX+^Eg#)mFetlh>a;4Hpe2!f)U*(+m=2`B@!@B
z{D<rgfeW7>I6S>xzFYoTzf`=By2Im}SVX1!_rBv=ieZdY)G=Gw>HU6fQ(8HJdbem|
zVDybVO~I18Mc?D^r)^ac3x_F9#uLEqA#Vn<eWqr6 at irZ6__^T%)NT%dSMecV&tEB!
zJ5$2(9Q5H~OuNFs&dIa6R3teY;8010Tex>qWk2(&_8DUbaNgtq!+i(&m+=gtKbrTy
z!^&lu+HRD;CyTRdv;7+T+qY%#;QNNpLy#j1-?{O!;X5b-Bp9r}iUM^#DltMIm*3vS
z#{8(OakEkS3XH7JHk0~5y@%^XFW?g0Dsa-R40Fo_?M(=3E*No<ecV_O-T44Pw{S#R
z>Ht*zL<2jY(?&itJnN_zVl0miH=O<QuF~csEFo$3$D!@G#?6wcdF6;6d<r-JZz_R*
z;rQ#XaCzxM*%lhr<*BC4VCL>OhyBmAt&%%WbT77>v7(`D_`R2055RhkC<*$lg09<v
zZ?}6CD&Ah1zH;=OW}9;Kt~3xpgRc6iVK3UJNDiLk;AH?S_A!L!Iylyf1%+_=vfXm2
z+d#zyUaitQx7$z7&mJ*Z4!!Nr04Ft#&1Y%~mN5)}@B*2z at 3Gd>vZqhfNLO_)e)My>
zUIgl1yqd5A3n_XOcMD||gg+c?Htghw4)(9?_+icZhBB34+||iZqJQucJ6EZ(zx at c}
zEf^Bm`;?*VJc%*~EeQh!VrnV3hs)3S_djwRja$V+e|x2x%RQUq{Kn at U*>ZDd`aNXw
z?sTTQcEsI71uYiscSbA_|Iu6H=#9Vf&N{fl+l;i*Ap#{uOC6^48(*uMSA4)#p)TX|
zG*(F7OUtrr;UH-u^w(xtsK_0xVwV!MV-P`|2S&gQjo3;W=wj85bV<bm!SWs82d$uM
z)q5Ik2P at G~MYOBkLCsa6fMg{7|5r^`;3 at 0`3@@em3acQ5w3NRk#xRrl51VbqJ#99g
zad(0xUYq08H?9P-K!gzB!@a{iBRl$lBiE-t|06YJwa=&wYsX6%p_pMze-YIvJGp>Q
za;4DkI=^b|`Mkem7b?SoOp$@supZpW6i(#Tg+ZPukJ^|*ObF*O>uT>oUCFb9rrMv~
zAhoc&hqWQ&2c^>^&;--q??DR92iR1CVVUT;P;kTwRl8hND<Vn!h9~q=IFfleNgs!N
zrYyB?@?3F6?nt|0S}Z}n2QX(Wdk4YqWngq8#lc3CMv&W-G7nNU$0CG?&6mcNhs8zo
zUY8ATdzmi<Y0zh>;6YjxBscL(>f~rjx&TpXQlclX>mjHkcl+{GbJs8WAn56A=^vlu
zdf@^5O^?(hm6cFqEl<+_IpV?l_vURqVHwWQJrpizMd at hu^p9D54rE=~$7NR`T(hYZ
ze$d7gWgCo)YOOLwR9&VH=?EemeN^AS1)cs6{wdAE7W(V`+@|U9kxtVk8KD<47%h4?
zM5YtBLbgaT^s0|GGi_wp55VtCbvipN^$pl1f4e0UHr7(#(8nzi>-b<fIhkJ0)hH0v
z-Cq8zMLt2;(ixy}i3p(4YmkePyvfX$iJ`tB1p!S3uA0w?(QBH~7umU|L%gBUmz19i
zvP?<E({#$TGix$$Y4W7w(U?$<RFK#_)FokN)}0yh at 9_)v<V4nIW=kMf-&{-=Z{>7_
zIRWysVk~&3D28vmGk4ql(K}2(c+YQ0;o5^D)!Grr-4{-U8eXzGq%47!a$3Fu{!d at L
zO`{KR;ZL<;zW+f~-$2yf7ReW4@=Qju$NPQMks7=#hYF#lHOPMgv at V&s7d`=qv55DN
z>q}Kot}#Dncz0l3kKOGg<M%#nb(+l at fV=RbX5h5E%Y)y6X%aC)O+SwBzniis69-qb
z_Ns0)gQPBcyBvj^w4HB7 at 7RjXyJj<Mb^fi@@M4yhzuGn~@hWM7HYC!=2C+*K?^f1x
z#dm-`6`3f0Y7r>x+O4%4-o&FeIa8=y!0w;qmyzR$V|j$AIwfNPz`ocy7GJCJ<#jC~
zVVhh`U0}|b$dBl`F`tMr<5bn at d34rOL!c79cDy)oSH-H6-_gzkj*>Z$DyjX7*&L2-
z)kkBvl94-{m at XFc<P=4)h;;M(78|x=RoiRnF%w#Jm at iPTxqZ+WZ+{j;eLC_%dR!@T
zu>r{)^|b#yh|?vQxj~a~agzm at 06^MW2Jrogz)SXilRb)<RJc41-hMeXOLC5fD7Rh(
zzo{D#lZmnVRH{jP5hk&x`-o9(p1%ZjIU0w{oTRz#pt0T{lQnI6=hwH7yA>$Li9gIe
zw^(`=e>1bw#unM*Ste>}h2rCnC*VW^{mLbsCwKj)NAbyHC=UbD{pwmbB$y~}ILbKb
zVd>!c{Y-h^zpK8GI4TT|`9gbuU4Qzf+KBld at HSX5r|-Mv6ws8TA3P20-uAMX7si9l
zLR2Zh23QUv at EUKIv1xD5_C5=0TvRP0Q#xxQ>mm-b_B$VE3z(j?Rt`O~K5bfiA^xNX
zPB95T1aAasZZ*mZ&+RKjYM1<F&f{Pgr!Qo_x9mRellH5s(jItyX5nk)4Nu3=86lqY
z%RgDR39`}X7vb^3mM{AVe7EkPACWRSRZ%=I at 1M)s+V79136^d=kr(9j&uIx%66mEl
z=U$wC`w(;|%|)T+yk!AYnBRVc`~8?m7w;6{{0?QofMc3&mGw8_yjA~S-yhRIHVi3a
z#5StZu89_ at 9tZeWD9QQ<fBv;egUJi at I4|%yt&h6!p=mXBz7Gb6QJ;JNaaD^x52DAS
zTPZ&!u`pw1;@b_j$mY+T55HDlJ8J~Hr;m{RYmgZb&>v)gY14IP?i0J0b5mSnAop}O
zYCinFk{bo7=Cuui4Qn1dThsUmF5a+Y8B3K??JCwe9iwY-hV}rxy6Q-^O#I**$fH}_
zK4`uPlX|M>)JK#iw<M at PCtUjMc>Ht!qhTJ~5l62sHac(FEB6 at bLVMA%{!WA{^Po~W
zD7nRCiRB}m$_>HBKZ)ljv95;Y<P|F4Y6NE$+^=Kib3O%0X9D7vXcWbt)N_FXadaZp
zoQ7pwB0Xx|bHD+$60!A>`cimF!`JFT0Mm8J==sOzXDqcHoC!x$zfc2pin6BIbzS}(
zFYATRBaQZIq>tMzs?iKPt!L|Bdi)2 at uO3F_X-N@=*7Ih*ai5dsx5nZ`LR-n#Z4lt<
z_kvpxq0-bj!!%ez*M4T-Np|0!gV8mJJ>MLMQK)2wE%}LnuM|*yG}ict9mbt^qI|6T
zlEH@@;ayMn2h&{|J0)?@0KG2yCP9+=h+>=VA})=HbfGAM4$dVqlc(95 at XYMHHmXlx
z!s|-<Ame+8lh?WGIvO_X-w>YP(4KsU9w5^kUp!=O$+B&l;pBXveij;`DiBNaz`pLE
zrJsoyY&kw&dqR8P+JtVZACX9x_i2w7wdZo!+I at 8P@)Sc-U#Z!agI+r}&F?TjK4A-=
z0mP_UG^NVO<qa%OI?s|^7m?M0R}nzyrK%F-7=QKnd|r*Mv~Vbm?a4-RH+h+Dk;Gn#
zh{!P#t*cGhNEf8@(fCH7ZQpG?8qY at --JLHvfvTFlWT(xHYkls73%s>N#u#ET28iTa
z{#R47Rub)?8&Y!kWg*U;ue`p?&Dv}AaUn5mQX;crKJLxa!v^B0ZYyG7p$(3>7RLR@
za at diu%b_|e0d6T}jC8$Bre&dKnt6fagwtYU*h=Kpq!zd7SD6Plyje!1&%(!sNC$pu
z;<M!MT5svhn^DuS^?Z$KHrQ{M?&l?}ffa0Ni45OctuUplVF5Fa5}^90iCXUun4jT~
zY4-thoWi1CnVV)=dPk3(3*9|7ZT{0kUj8wu;(WwK2Ix}lRBR<a9d0I;&XUA$2OCNR
zhzv8oCaK!VRtFQ7_Z%bja7Q2x%kS%(%5GmEvH08;@HJ%S2<%g$p1&!Q45^}@XL%xe
zLnD#=Q6&G2K!(|j=WBmvjGanB{U at d(>4<g&VTL;sHvs}lgnq7$N`XTg<Ys=jcD|vz
zk+`r<h5H}DsNA+NjA9RCTl9+DNa!{FoQz&7mVO2ofdTE>r+OP)?Z5lL{PwxGb7CQz
z<C2Jsw&qHoqR?bco?1c;Ipavv8M at Xw=>+yxPc(S^%bj~#WuqIHQTYVcnx!e`&i^av
ztmB&c{y)C4(L-S%CDH>FkdlTCkZuf0N{|LAk<kNDK at gBe8dOwTy2HWfkW{)PrDN3g
zyPxlG|L*ZPcaPn3?mg%Ie!ZSA@!(rUUWkcEVsQkCBk%gPlQkn<%zikKpohv#LJv?v
ztv;w)N7~ENQ{u=RZ0I#bpw(1{rR?#PHc+=jiOj-l{WO(7 at n|F67~^LkNmoBA<ks?d
z2(@+XwM8ZudQ%SF+)lEohsd8^InfszrlKG_$W;Dkq7+NpwSm&cbW22O0oBfJ(n}KX
z*r9AxV#*&xdddyd3$nJBP0S$lfp<uO25dkV$YY7&C41GsV5{AT2!c at oWw#qtQA%c|
zpF<K_8GEAJY>Q5XFTuX);bphhLir3xbJC5|xt@!#D!ucI665QeteQ-_x=|YqM_GT!
z5+w7~pQ6x}GqIVr=aGVCD2a#LlC043a*?;!M&$IKH?a2Z(Yz{sI+M=UJ;DPVvpYeU
zsIBr?qc>ZkGO#!{E<S7&niojuV$hlO4MM!lr6GBLQS^F?=6Lkwv#aOPp=GM9syqMe
zzm`tdF^$~BhH?%NB11103*Zx!lv^<*Xd{TX<*Q&v at 5d6PT0XneP1`vkea#Onm>ia%
ztAWnhdVmLU_X}8|w=$c|HwR`D*B^y!$l-1O9C-a#b+)Cv@};C(?eJM4wP<a&3WMLL
z$2A2mf;@}TEGe$Xf;Bn{Y->k1a_bI{YZEix?T){V<4 at h~1MSSED(!qWm6#Zv(OYx*
zL3gw|IM<Zbt?nu4b$&je3m5IEq2oNy-m%DQEVXzt`BRd=)FQFX9t2qVnC|LbbM4~S
z_<@(a=wlYW858;V+9{h)L>h3H4(<7eQ?W^4Xg+YbastXX{e-s(ct3VU<Zqv)q;RxV
zM?(S`o!2ZnJdhxZFk~#Ica>bH;miQEpTHA8ArUD$1=}QyIzA-kgX2L-I at Y^iTf!Dt
zNmyvH_oCOtFvj)WF9L-ZHO_zdw%RuG2DpP_g_q54V)Sen?N(g?Jv1#$X^fjg0)rl4
z)`J*^u*sQVhbG5AGJlP0 at ywZ#7E2QcrI40|gWJ-;#a}3^U^ZLrKL>v2w5vz<v+ at pY
zMsvI&16BDcDv~K^Lb`1vx&f(%nv#*BU6Ux}>mO(8mM<dKr-C)p(K#9zp%7z}+Lm*<
z&Xae>rquw-Bo+rmEsP3=x!mB)AAVAoSymEtJOxVo+70$*>`r_JlG89d$2JoLU?8ii
z|1Levm3<Yr at tgQ5J8#gp5=E)fQS5f&cjiC2ddS#HpKL}2u>pzkkfpTzQ}l0e2042^
zw&rhmqa at c`FYv|x-j=fsxMpx1HtiJEtQI<u296mZjDVU*IJ>ZAQY3r(VitElVrYP^
z&WL%PU7aq2LKW=w!HO#2rsa7D#E%zR&j_Aodw;@4);0Yi+soI at l>(&@nL*(y7D5FS
z>|sxSZ*!>4+cq`nwUH@>0}?h<cD*i`jSJ~8t)_-7Q|G<7kp@<wXQ0Pd?iID`Wl_gw
zmq3m+?goUjCZ at y$JOWKYd<5Cu(BpjfG6jrRz_WTP_A!GlimwUW|IhBQsa5O at YO=I?
zi?^bi;30I7sajXiah1jEQCPdF1GC1QusgQhs!>T)b_gXsj0q1i)AHKdsO)*gO&FOk
z^{dnE%9lDm`)GQ?9`(JZOh9(XmDa$yd}ES}r47jf3Z4~)OoeXh%IRBg at V|;?&JKUQ
zbfrl<^5D_2D)_F7pZnLtA}mozx2a|a*9Psallg*uTQ at iI0RIKH(4gw2C$aoE9puIL
zrq5GrNt#Iv%mNa%^1Qaly+k5wug?=e7Z=v&?XFk+*0m=p5q?gY4m1U_6&4bM2aRG0
zz at hcD1%{CUVhcN80w~Q`lL63zS~@V{w#O?aNq8_YPD*c+%GN|jfs>EUbhVM;Wl^jD
zYfmx1NZ5NUjcKpW8%*hTq$?}A5OoLrtm7tuVWw(yZCLW at Z2n6tZ&RTE>Xj~VZW_0h
z at 74!`0ePTi=c?BA*0==?I}m_q$wln>n_iYD*AmSMfl`X!5e)5ihNIio7823-s9GG-
zoGQx~c=nqdzpKF(+BPb0g9UKa>@#8AO&n3&=5M}d3$&QQN~w>9<uC5frcUYehd9Mh
zS9C%}U*2qgk25d<`Zs|3l=ijje$AeLD)}Vc7PuFvAUTF^F3FvDD$Y*W#n}zt1GQK`
zr`&sNQ*8qF`j1!3hWv=d9^`Psn~GR%;455}-$_UxqMqNzU%Irn*?{^Dd08ROklZ-t
zHmhSl4r>z^V%6Y>rlaKcYSABc(CK}&Lak6<cCzT~OUC0$*(0)H>nD?nqG2B at w74Vr
zIG=tR$LKDoivd~g^^8cGGjKJfg-Z!k$O>u|F-M8a7f;f||554#{nrZ6KBBB4UHkS5
z8IPK|Ucb#OqwnTNR?Y#LdJLV+^;KZcsQ!0_R>+Q<u4syLSGs)to-yPpefZrMBp$SJ
z9 at ogqE&GU;<^-NEKi38em8=ZQwcZ43(~`e`7VzK$y?dI?cHFHDjixs>9z7sUaWeW3
z9HX1i_Fa^(+_7J4%)(wh^=*I61r1gWvX|OUb8%2Ewd@<_Yw*>8+Nb-~vACh<jbn+^
zPSMS3)-`236V&?K5xB2dsePtS#wvGu&Otv!?6f#|X}|?j(Rz0Tv=o&yyKe(E;SH$+
z@&>Bl at p#&W*VBFvkiH#^%?pw`Z<m#RU$cHvuAFH<&IxIQc2nzufP<FrDAGZdqn>|f
z#LF|bJPU at gr|X+P7RQ(*(=?iapGoaJ{mb#gxeVLPnQ{6r6 at Oi~2B64yKZ{EtlK(m&
z=98c;pAQ}oi>fa9oo(VRpdufJ(vvKFzLrJR!T!zppZIF4o~z_%Hgy;vMK<YjncK7m
zfCbIbh`x>J{a2R#?HWyS#E3{q>d&Pz=j34a^M>fJMEOJCHXK}dpQ!-{uIOe?XK<xl
zX!i?Ep$jS;Z<D_LS1LTiAp2!eIAa!_!Vy&%j>MScH}vjovxzapkG?q#vGgu%fpkeP
z$+a^5Xfgq)jF%q5#WFx|+QhI1mPcWP8T2LZ>}YU_K=3a14Z0!=29gdMrvY{8+Kj^a
zY=AUA8MM=nLka*T|Iuv7<t)^!??;BSsMedep$=NJ<nC#vKUaRBX(m;I*_M3i2E7KF
zJzDg_`RX-!&lzZdRV2{^okDt at X=}@s?zc^Fn?+aw;S{}PNiB2So18~qz(N9qZ#OV$
z_Mincgii^UNGWjA#v32QiOKCh)({7O&{cxzD)G|OX2rWhX>3{cs`mqW0qIsIpgo^<
zR?9m~`V63(0~fMI<>qS-BmT8h*+96Ts3ka=e0WcR!tA+9 at f@(YeE_>9<7?T64~VpV
z#Dc_Te*KrW+!$!=GxR4c`T>a)4Nl^kkf)yZ9a6R_=?V*KYd?d^5n;r%Bw`Ff^H&z8
z6f7S==vXN~_ctWNP_m8i^s$tfmKL>IXtWB&S~-cN2y_Fwg$36rIXcyOUS>?x at srB|
z9H{dJ3^((p9}ld-uGyk6dFC)^M5JyXEP?J3pXcW^rF$e at zidkvEf}s=mE<&J`?-rr
z^66eInXvr%#34N<5))%Fc=lm8ONLH<r!kOx!2 at jG5ty9j2pWdBRDj(Q!Q1iRZDfG%
z(67RTG=1k31V&o&D>MeQnmZmf&Yw!(qlNXoelJ5+#sR`CK at tn0)Larn^U__(3cf|<
zjYrWe#2X6+u}>Zlo5<KJBO%mAq9X8GY4t5u=#_ZqbvwH@(+XA_HqoWVP6{`&9$E$u
zP6OETYf4_8czh`%y=XO{C0TH_cw at 1y3u-5qNx_yKROzACc}|tCd550O=`=CO$Lg_Q
zoTGLhKg|X-WtWCG+p_I&iD1ssQIoRIO7wNf%$QDt166Z%!=GNg at t(Xaz|KOv?ufc#
z8YC)sn!2*YdVcVoMX4x=FS_w|z{CGiyJn3pkJGBU_{6u^&_el?F)Ye`P{4=KmPQvN
zW-Rp|^UHSM=T>ko>gYqD=iq8x40GGmB*v=CLkR1>8+Xf9tSB>Xe64vtO9LngOFh|B
z21pRXuj_8n*sLw`BsK$GqJV7Vmo?XvQE0rfdU3G$vDV*+z&}}nS_KE!@Bf;){wes@
zTF at PSb_oH}o8+s^_sHU~PlwG2)1X+bqc=C&{j(aseOfj@$KKo*NGtpK^8L_0OVpZ!
z`(!^;bD7A}T@@nVJLHcD{9#SkQrQ*y(-7Pmx=<l*ncgL}nkR829xKeV=hEhYp`3{a
z0U4(KlJ5}~G)q#)V!MawHFVYQG0B*SYa_7kMEy&bxXii|;H_#P2Owj(jW;srJL3cY
z0c18XoxC;am$C)C(DY5Jj4BVIZgjE3+?m*B!&ZP4&!sI%(DM%qt~J`*!Zkgh8URJW
zu5j-+urC0Xdhyx at y-;EGSW9VGLs=Ww7=tJxx%K&`CgnQjj=v@|qW6B30;SdD{KIgN
zZv{~a7bf0ALFHDs)hk(>u9v2EFD-Rt`)DJET~GgeDF3quZBn>Wr-j{3)<2Fm at _AQ&
z?bE9gS<!WwePg)hTd|*|SaA*BnIbvJ-Q{$vqagLAit~oCyGeLI2g5FbC~GgYZijr$
zyDi9~%wf+NTUn50$F#kIo_PENj$<@T(b&_3&r^f5?g?w7s#w at fcmY=##>*0lop;xn
zc_Y?pp^Nz!5&JOqWp|eRCUtN@*^DbZw0 at GIHvVTbxc`EYGfjnIxvzuIhEX!iJsG@>
z3gKn}<u~NAjFZJDV8PVNI$?tCyqMc<+=wU=c6vyYLDmAVc8^(&Y&JZK*OuiQQnZ|@
z`Vv+6xM!o!1V~i_b~$2G76zzw6aGQ}uQLyDsZZ5!%`@x+%A&!g-7b|EcASwY6$E3f
zVg*(=%sq~@g6|}$cG%96l7p!<V_#4GLD%~Lg_;s67L6`)K#E8KVC^U|rv-TDjFw at I
z^NfSK8M_#c{S~x0hWt*|_9W(5=<0suA2LsE9T!zKPRhB&)<<Ntkv&V$sLHy;_VQim
zJ+UyEwNH7$WXZod?#mUeqQVP9+oXy}dOc?gc3Za2J98(N{FDFNCO0{J!AC2(xA?LZ
zL;|nDHGxT%_MD64IZ*5kCmvStWOWQCpn$SYL at N9btczJ9OiaLWe>B9;L#p1}K<o_!
zvarP;Lb2?)lPoG4F-!VilxoiFvK*fQ1qg=sGFWl?gd8H1K(o-DUilmJ+}SwzNPx6V
z0)%)9V|$@RLdC7M at +?g|oS!wRaMWSp>aNz<&M`R<?OR;vD4$NJVnF7(svT}mtlyd(
z_3!0>Yl2eDMVUkJIU({X*6NoO at o4i)3P|F!dbX#3SJ=YyE?;@vd)TWA<Z~fvmTMv<
z?Pl+VIf{e5P6gi!FAFmV)*a)$!o?({*?|=x3R+dxxEFT8l2agb+OC+Wv2w#pbIAm?
z75L7}!WSZX6JgFADU&b$u&OtmWmS6j177c5ShJ$hWfqt%9?T|p at 3+s<`bt|=Viwq<
zAy}Sf at TZ3$<m-9 at gh3T9z?VmkycTjV0@@*>)!rtN8%gZ7v^sJ+Y4w+gy4tRGO_VSx
z`(gmJn9LG{2dqBF30+y+Lzp8KDUj^ZtD{#8T}#=<R;)!A){bCqq;0eSZLG<I9$k+a
z%{RUL7tCP5k6b;LsQR!=u?8T04f+*<-^))v<)*z5>!VQEv8&SMqKh>e^fi+HHyq;V
zG^4RmxdBu&k`J4~PAoI<Bkgo&sNB3l3oishYlNr1*`~$PX2#OC>IQ;VQFAI&Q##oi
zh8;lXU$K)<zuLS)&%BDt^?HfTaR at C@)dWDWQ-z^P1 at Cd6<8~4|;c7>BMkqrgOeaoB
zDwkqyz;x!36u_R#dTA3q;joFeZAh};u4{27p%GX<NtFa<kxQmTWp3tcgPT>3`*E}P
zV-OXqrT|l>0roWD_U>xXjCDl2(5+K7IqN8yAO56n%J|nM6fJ-Tg@>#hKn at b<1E5aK
zZ6;I;mGG)>5i4kr*dNf2_%Mw371m~PBJ9cQ4539{hq_YUCZNsm_=lA-$KBgcMO;X2
zrdsotlbQ>ZLq9z$usoln6x#boQK2hj!V$e at jy(|mQu?9I5#H+^d at r1N_a1v#(pXT!
zHfh%q9ru{2=rw7EHNlM!+JbkYh%sGfN1t^z60f4gNtOoDwA19Q8k>9gxW$up2c<bx
z2~K`DvJu+++c2eJZdSGENBXP6L4VMuSOaU$F3JZvI=YP(6BW-uaWC52CB#9Lcj#WT
zLT7G0S+R)z;4S=A1Yo~7k<jV3xut@)%fW22`5GAd!~${5s5S*w;};Ch33U^dm;DOO
z3=`4viwnbMAqdlqO$mbD4^^b3c?nx^q9lUL;xR|5=3XjYvrW#Sg`WY$Kz?ZK at 1#rM
zBTwoB%RD6GkeY41KddylTjRF<Qgut&Acb~uy`u-t4w;SA3W?hP*0lo8{|QA`JrEKp
zCyB=!Sk}eM1n)1c6nAAUV`W*2dr at P)2E4YL-o;O_A at SsUNxx0pQ4_~)=%;rmvF3Fe
zr3 at 09Du3yX;^Lv#KfA$Oa;>mA#t}2M=eBk+S30zPw3CA%_M&A71Wj3mZKf!42lfBy
zFR$))vE`2UjFY6`9So*{t294^0fj&86KW34{yzX4GsrvhkP+oRY`ks4FepS8ZoyR&
zfMd3ph9i>>kE`u~=26#mI#j$VGsM<kt5Pu><xjX=sq4DL*84c$<dG>GZ?i9f3*e at _
zZtZtzvK^|GgMUYGrh~a}#POP<DJbf~wVuIJwI&~2_x=7HM!u}P^6)B3AbSLAbsGX;
zteBo=|5u|}Yk$=PI^jSeWxoXSi=`o$gBnrbm>y;pXg%*uh|UtHu|u{QnGL{WcM%FY
zm*5Ne+G&?xF2{xBuOI;bxqB2x?-|;%sg`-!{;4i42RF|fEPYr`qc>uJz}z-6T1f9^
zN0RxIHxjk{CSBr7jBrJv{#vJyMX40YrkGTO6IC>ASpoZ|@4R{Nw{OcA+AK<+5JzS)
z>1{77Ad5^ddqFRIKrj11C+tWCSyLG1GZ$q?8@&bjJu)HqD=HWXWXzoOzfKiqQD(L7
z8hyJV^SVsi&V2^`XPhm71j0DF-B)<=zAQ&s^!{t+dHZru)Xn|qIB@@w6o#izU+>x>
z+%#teR0KX~i-X3z#$hs*+ at h&y1YGHXjb>ziwno$7u^PnmQ>a)A at SF_jgtfVu#g|03
zlv{2q;a_J_w3h3Tl|LaX*B~ng9_|#7VIfarNGK^lm1EcGwie`@PqOLcy~TTHjXEi`
z*T$AaJMBUo6R4ftC>|ycugoKe$r$*f+qQWm&a@$H)88&6Xs3%Jv4pjEP9VOyhk`AA
zd$9J~&tpivc(bMLK_)<H&i{JuZ$jO{l>k|;hLQ|759f9L%?gY~F57DT;IeXXjM%Z?
znHYI5cv5veCvPx$Vau+W`nU*ND*>8gWj9tbmk{K3yOo10-rDpz{Ijl#?2rmu=NSQ+
z1D$&r^tLH0e)QvwyOyoUdc>pwS*}e;5vUVe%$4>nW{(rq{w<m^{$3j9Jt&_=wf!O4
z=mHSc#7>qTF#D#{I+~oohO}l7{N4%=6~}naT}fL8)z5p+AD;+CGUZ1u;Ve9y%;MUo
zLHc_XoDdrlPI7z<pHe!txv(eA<O6a$?39oTG&5Q?&%B9`YC0Zr__ZwW?kV+5st558
z?%qGauAo6tP>2Qn=@Z-(;0!nvoqNs at 6m15Oylf^z6iEOy_U_(?p0EPk1MW<@P%Z>{
z>`;FO4JYpk^X<AT41Ew;IBy<%0__eejQ=5C!M^^DvOTRc@#gs2`K*;NGc(2W at p#il
z1CJr at l+!{dW=vmD;Sidmr0y<cpZ{fCc5ulQQje?;&As4i{>yseP%*!hW&zYnPRFcl
zMU(l9YSHZ@!=PnLCf}Q)+9S=}hOeXQZE5y&+)E*3Qj8bzK{FlF)$zif-W|hpZWbx7
zuJ<|Bf7ZPuYdb9jI{OH>oVc;IWrEO~V>e1SJ(%OA8%f}osTPf)%P1$33%Qp&(>Z%~
zZFBeECV)j3_=mC#dc3X%XL&WrzDr at ***@xErzMP49^$kV{<<fZINCx at 8dJ%>v6lK?Wa
z=7%Azo`Fc+TBmQP+}4%Zs)o}$)Wdllj)(NihPxWx+jLy}s+YBAs}^)f9e-?Gdro5z
zf-*w`<PZe2L5aMgXKoi`0T+RF7h?F{9M1B9i^8`2c0N7kR>y=n at -V-9PT_Bu826C9
zZbHW3>nRs%YkbWU9+jx2_-)1KdiKerTx+++&BW!C_e)YhD2qvS`CM%H`&9tn%oplV
zfm^O%dsb1~QyD~HV+S<PeD6Y?K>noVr^Ac)*54Xrj>UN1Mc}HZ{Z{r29*BSb<n!R&
zUtLlzSuNEWM$r#$(9u`dt44;{8fttt3>}>d5FwG_E|n3c^2VG;j1t)EKLdMCf#mX)
zItO#yA+kbUmx41o$1%j=D&u2&`dKA@$f7C9IIw>&lC9#&WiiEDK3WdSyLy9%!eN^Y
z-iO8?1)k3}=KN{6h{V+jDco#~TH5KsS at K0o-oMpce#rAIM0e$|BBn4jrhhjUzumKT
zaZqnvEGib>#NF)=XntGY#@PmqsM6J9o8T!Dm{*C4<kvqdqh4I9YDZS4-YslLU?}b(
zOtiG4=U?==XmgW<=`rv`0{zo4 at zD;Zyqy^b;WTIEW^W-O!eSY?&{m9msT<A3u8NUi
z!9`D&>QtE|?y)?H=BPxyJl7Q`xB-=TzK<aL*lfA1{}_jP`ZvM!WDY*jt%8QrjO>Y#
zdQW47j$o^SVUAzp0>G7dw-yMne;P6`@6SAvEseU$*Neeu at vmmvrou4RqPLPk`OG-g
z2J<Rt6Dtg+w5^H{vt-6h3DZvrLZ-^VsITqFFUrW^MO#+W at Hh8Eh1)|4IgdNa=%up-
z4O at n_Cp3jJoW=`Zy6hJxwF)V1H6)koHa`TSoW6j?unIX9M<%xO$xfOC!H>s{EY@}b
z<{fHH3V*p)mf=LB0m9p}$y~{kl{RDvSy-m#bSH((5LDT}RQ}smPvRg2-f?A|z3BZ`
z8hDAiqfr7fIR7Q{tJ?EC{-;IHH*ubI(tjjYTvvYN_CHQuWz8V*wYzir42q at t`AkKd
zY)@CYn8rrZiSp<zAozMtYRJ;Y4mj4gA*@bh_$2sBKAikC=+i25RC0oFq}NAu3vI#+
zE_2_c^C#hEl+~O-8?#ZUZ)`f|sh~QI8_1x#Dmd5dC?z2i>j)b<xL(K^^!|4KYx-U<
z)tKKLi`L;2u%W4G5N)U<h}3{Kjdape_}Eb7uZsMd{k<xd&bLnP6qUI#S}G#k(qmCQ
zhA4~p4Ul_myML-*&ex14KK0Y;Kb)=pyz8)qwCCRuUpNFI^a5lHIE)hr at G`W)guu^4
zDSnx(irJ*)>i^NS<fDa4jogt?E3HMOB at e?_m`k=&0jrY6vI(xFqewva<1+_!`x)9k
z*@3}G)VsNkTD&4aZZ^7<9D$0)I6<udn30n-m1xPe-eLtZ`xsL8PTj0D*m0nwot<mD
zY-+Wv5&!XYrYP80r^#m>hH+d-iBEYN_;eesz;x>9jvGQFvx{oE1^}}J1%`48^ve#Y
z*Mi7$+Z9Wd6^q&|ALnX*EnA7#m$8cckY=Z~o$65Ef8-e4GPmZVi#JlO&dnbVDn-@^
z`ObQUP88PilpN0O>|Yt+_}Bp%qDB>ez#}`ez=xF^Hz?ml7y!CT3M;|J0=Q7VBKJPG
zO+-xY^_1VCsLEi5kaXq*Fo=({n;y1oSk2u=(R8O=si(k)!jMEAEA_UU6e(+^Iw%<r
z)m2oU^16{I at WuG2>`t at 97h8&|&<f^uUt`ESrrlfFeW3gWE6IHD7~gOJjFU@~F+4;|
zKS-zVGtRr)qc;$P6njGHW?K*FAQPih&Y#$!%S!5Wf#|8#ZHba$_J9qMQFTM!rp}y*
zxb^gU>PRM9RJi(-6y_O8Bx+%KI32Ta{tWs(QOYS=ijHsi?L+uehKhl_S9YYme2a_;
zZDLHiu%rwriTjN}<d4}Y|FN38&D}Jbv-f5PJ9$me{#}qcx5o&4rl>m&_^;haWE2N?
zaG)7 at Y7pmJ-X2D2jApRj%xQ&}dH&fG+w<%#ye>Tr5Zau(`{QWR^urjhOwaRujS-%y
zZtf-NYRZ0zZ~@imsVUCQWkzAF+}F`lx?M+DYQ^n3U}C9r7VK|EXnYw-#fVtp1CSo<
z){0%QTr0qsCPZq+x>O^Sjz;p-XS+mgeCmsu(w-YHK%}%vnx9%mH-BM7Eqk{LU5U7w
z>8K>m at XB>m7z&+4sx?L8c at ASZKPn4j{jsk3xj?)#T12uU^FrlnB;F0$L~nY4SeQGK
zMO2LhQ+kx6cylr=$-WG&x^CKyUcj%|DO>FRK$q-5MWF00bjVUCrH3;I^6U<ZOh7$Y
zWl(#CU?I4OEA{!!MJ)6xUMqV&QU9?uc5J+*MI>Wrs6{HI>wM`Y^}JtfyWyUs(PdM{
zQ{R_c&rQ#B8gtW+w^x{n>3)b{5k|!|4%T<<E{nT at IfoULhUC7h4f5dc&Acr<_vtv;
zfA0ufDSq8LZ!w^5YKfa@?mQUF_)|p(m00*}hbH$drN<ktm}!o#_%M1f9*7GCzMoF_
zo87w{2Jr?&v;ys+spefJ+abdC4sYLwW&VfUS<RkWJ-#|c7>!kX8~tB$QPwbuyRSTj
zi=Bf8S6$5494v8S4|60c`c3PfrV~OoFW3sDNrT}R9hDv}84ACAh*^Qx`6fMFHbT{O
zh==CqO#2+NFS(;cD2>?SmELIbQZUi!4BwZTkVDc;t_6sX-JJHiNS_D^F5W5H>ObzP
z5&wB|*wTZuNS)@rn>MsqVD21Aom%DqSujy%RubMxrtOqwO8Hx|Tp;AiDh%mfiUas0
z0B_;;^C<ZP+rRk<(Pn=~9$JwRs?(I at pPIZi$4fHKr0p5MdT>e{!|^csZDno at mCb;t
z)Gp_PPE&j66;J0AZ_h8ZhJ`-X31vCHy}IM|o~80;)V~N1Y7GfL{uj}ff?#hO3_H!w
zmqOE_6WrSsc*a7 at IIqCUjSJFhmZPpjS-*X6DNu-RyU3?a$G^Ap>&(}fIE8<P+8h+m
zS7v+;eR at 3(1QTul#aVu2`wi;@_s}hyZIY}%-7`W1;<%&G073(-;pKT<#Dj;}M5io|
ziUe2VXn*%YpN7eELSF at 7E^b+^C;pyHykL!f60};lMxbWRkr3acZ&F=;%`!A3l#_@*
z-2OfAj-msf)}3z#VgZj$#*GZkMUQ;vd2q@@cOe~K=26`fn79hFx#3KCtX2^T-U~|Q
zfSk`m_mUr6CFeSRb^_^SC}|)PTK&z%x<AQ~wP&CXx63Y7FR!yJ>MykhT&eRD5(|f3
zEIIm5GXVEiK=AWp;^DB19lL+^uhBcBF3}zkK;d6NWffH2+4HL&S;KaJ5r^<^%sll&
z at cwxoXo`gQdFr|GPjW2+eOPwv(1A6!?So7)pi5Bk&Pvs>YV>;8H+b-q6Je*XFYN5d
z=cgc at L43YlCS`XFNPz3rOfMUVTDrK~^lH10!Ap*RiSMKd*Xf9gQN+JWmqJ$;Yat?M
z7rbS!hbzBM3Do|v#{nn8X!G^aj@`Jptef7(^fPS$bn(XPN5JgW9S~o=l$~Lxl8+8N
zA01nLvj&LFwnf|kKllMBaJT?TQ1x_9uSTbq={}!pNwh)+AI|2C9y*;Cm#*x1sa%h%
zCEY(&kI|{lV!!@|GsO1l$V`|Zxbb=ZwqpM38X<Akr!~hfk8voU+cnkwR@|D2O3|P*
zK+pcFHhYJjB?TxeJ3eV)Qbilxn=6acuuTt;XMgf$;@B(jvngH}vaW|oU-tZHq<MGl
z?qU8$Z}rWMfy2bImWewU4~R;~%bpqSORnf7F(SRwKODf_37MEiF$2#Sq2bOv>~KzK
zyG0*$YvDUzIPqU&qO02F8ZRJq7}V3xR8XWPw%=cT&0%K>WkBI-w(Jg1Mqip+9^rV7
zC4mBl at 0!`Sq<`&R9}X&LYg4(XL(c<FhJJ%QpTKhIqaAt#GCzMUv#h$?%d!jHk(V}p
zR~z2%w;06%FKD-Q#@;yGBV7yG@{*gY_56JL`B at IU*6ljhk{WZBBEX6h+N at vy^X=-~
zRBck<E%jerE5%`{^`}AZpy(VtVn6g^tp}K1e5V`=KxWjP!{!%fE+5b2_g#O7nlAf%
zjU-|st}_nlhOetf*_*GXezP++8%*~WqLOT<%0o_c6h)nzUNQvs_;?w|8NIsErX)nO
zFNAG!#cg{3R@;|6SH(kK%ou)|o~&1lL{hc}QIYc+g{z5wu+X^ob1x;`aj>t6_L0iD
z5oT at t?uTPpdk`b0cDbT!KgC8~`OwTG5S8*C_arC(dF_3B^{BP2E$;oMzR4uCZwC`a
z&Z(ev=;7?jeqtHl=?*G$rpedQd)0+lLtOcG**`QH9HRq7hF<}xHCOrNF8RaU$Xci0
z=$4i*gqWCQnkwv{f0MYNra2CIzF)sktLVSmXSSeXkbX`gn4w)YKaIfHEkb;AG^BQQ
z^ATCZ%F=*1<r-6XQ&@}7Zpb<Ej|j97KBM~dMGyzFc{aLo;52Na{(Q>qyk+d@%Kxr;
zh10_0hs36w`6K%IEol$LPsHE-*Vcs6)=Tf_VbTN?W4 at s^R1Bx*0n)Y&!T%D+XzCb>
zWCg#s^8s3jN^J_FQs5RBxsu25O1hr(mK*r<jHD+2zo}?Bm3)4q0X}MpkdFd06Cu&Y
z>5GK&;B)40L)E>iwq{~Cs3jD#=T5em_XAG`Y7=pn^k%E_AuYc3LGE7r(liT()u at --
zH*y)bTpp~w1pGB*uatK0*s{`xG|ywhEy6^Z9DX+x9aMw+#lZ>D5z9})=nK!>+s=+k
zKzvFawj}dc$7T2Fm1vI%uz<XpNR{XRL^O)7V$P=(p3Cftdp-GdF&6SRj#OKA3F}92
zt|$KUdu2xKDw#ebN2ZDx3|cJ=*&jER;mU6BAI`sEqesR>&5x~hdHz0c at b?v(QWu`M
zjrTCYkB+Tv*@ZP<{;V}zt=VWH1>6yN#Zrt5(a%WTw--^@9*mF{L1P!h)5!566t`Au
z!TfUcbuW%LSN>+nCz8i;7-R?c%~N$l|Gsm|OffadFm4pd<PNb-j2LQFzi<>jZ6yR8
z?DZt}%#vS!zy`b$(rp6>2 at b)Xrz<RkXDKNARRh~ILD{IB&_<4ZR|Q at EK~~iXIe at j*
zMpEJ({p<U#+DKF=87c<c)DiPh31cIU9)W7=JA6%{j9+=kZ5p2f0N{<Epcw2rT2J>D
zR~U)UL+M%^uO2#{;Y9HlXac)cWe6SN!ICwpi?W*e>e|TnH8rEPJ!X*+&<T_IS~mG)
zz3EjnGl=#P*#{^um)4*g3DaohcRfzx_(HE<E at Cb{$l54tcXOhCYB0Jh-ypQBFEl2c
zD5a9N?{V8|5^*W`ZdQ$wn7M>j?+YF}r$7<k2cfoFnfGhAzL6f=<tMk=0ZJ|(77^$P
z=er1O{9cHj0;<RYJ2?hqYG0K6C~@VnJI2~we94Zs!3+83Dpc-EEZUG<KElILaDV{^
z2cQbWmD?uTM;^&XS(KbD0>3!8THfB~Jv!Qfj1)Qs=JjCniSLL_H;Auq5|$Y+P2zTE
z^mg^pgBtiX5i4DPT-mw4CLZ^*n8W(S{u)0s1VwZNiaKb8-67MvJEu6s33nOkIMdP=
zB)sgK*~;Y$%fZQy8=<3|qgTR8QW$DA&d|_)=`dtBZ<IBaElJ@$*QX?@rNA#VTwh$-
zkZ9q))RE><AE|<#+<{*xw4FZE>_}a|dd%)|boTCOahd-%W7Et}w$Y5MqJF%|uj$~3
zq1rnkKSOmpP`#nK54{k8b;j|Br%7TSzJ2*}6F_sxSu=$-4Ulp2uQ`SVCNh(3i}V&B
z9B#gI|LDJJzQz-sB)E3Ug(thX at u?e3%BrcJ(dMPAq@{a#_ppp&|Hfi)i1_8>^ZSg1
zudma8)Iams3pGwRzNxbqau~IaKoj!@{Tf<5qSyU1hOU3YJFJwdhU(<=GftMycXzaY
zVzH*gl?~}{$>yYWN?&3RG(VovwJzzzK*$k;*Nh=vs0YSW1#9NG4zIZV at 1mk<-fl*l
z2PJa7A*lsv%H5OgUi7gN?0{6o5RT4)f+>DZU%WGHSk at 99uh;`ZdZj4Kz6<_J{uX;N
zGxf5mYwg$mk6RmqTOY6N>#I<dt!}TvUvhdHD!;w2{qd*vqXb5JnE`F3%0H`uCP{ed
z(S*|q=>Bo-ytYt~UfTOy#4ie4*INMgRb*mX?(fw%yG at _-``JfjTvw+nL*~DOc-lh|
z?I{2A<emK}_F&$C*<E+xeUF*m{MPSlfwo at zzYqiWn0POJ5+$<ss%K34V|DQU6DTQJ
zbF6``o;ZnNF;1!JYVF1E7flq+zIWLjr&SJRc*>8=ZpG=|x;_buoixQB?|Zsg-CB8;
zRY1<W)80}J#s;&u17)*r*aPAC)>~;KPjG<=QyP(B_n<kSxQw*smd!h|<$~qX+YpNL
zR*fOS-fKIvJ@=!Q1yOKKO(TnRt>vkup!s0^$<dq)B%|}K$~_|Y;dv|(eVh2&Y!;VT
zXfUcc8 at i_?aithV7+m?H8hX`bc*K-sfhAcyOndPlAC>1AB*QntF&<+uvk)0^-RP2z
z`bh0zv}>k)Zws at zY`stx_>zO>gp{Q%B*I3SVT70N1?~$A`;h&i<OkEPB>S2gyIZpd
z@<At)x``LvHN6`?)_+baVD=5mx1RItawx4kJ7f8M&l2t6O(YI%N)9PMwb>Gm(%@&%
zIEeO9<;RV?cj`?1Wd*!u>?AoCgLvq!Rz*S|Hwias!RPlzrz_KpvWdPIa?-cg8kZlR
zU1Nzn;2by-7gRL}%@G at QMI0LHTwFB7HTogWr)&A8&kXDj=LaSa*hj1r)`tY&4(c4O
zrTs$$7^_hbc{@^-*;DuEP!-_?8WL~)GatYL50GA~^j=?N`15}3+WqvAOxi*no-n`V
zy`y9?H|QBFSLMFs6~^^qH5fVG^F4q2!Zd&UTHW2mI4?Z~{hdw=1 at zZ>1E*Gzf*Ls$
zmVb!_zd=d7GACf_9tN&w$`_fWybT8gp-%^r`wiTs-wy2?ks9)R6Qfznqvak|D1nEu
zsmQvJc|UWx4fGOc`F!H6A2T)+BkQc?kkBLnrX=wal at E~Id(`*WqxI at 8OMB>+8SA3`
z2gWHW<QL*(JF#K8<nWJQdTHriYeN&BgWUjKn!4V4weuv3 at Ox#$#DG7J9raNGy(h{t
zW%EVj$b8k}m(NvaG`xkKgHEyX%2{~7p7=1JWk at 1~v86Ngkwo+BoY&coL}!QqE|zhT
zy~m3^_we=!WiQ at zrgS|vS$rd{(|EYvDkA+E9LRNK%kI0#lvp*@2-dx*Q2Z%d%d{o+
zCkOtc)W?cl`vTnSeb>_Nd^yHa97MP-y`DhaO;h$1{P>Db^IAgk%Ag=v at tP*IKfFJ(
zKh{|?*X%GmWgreMw18Nwo!2LPM at W%8J5h^4jS-JKCVhg_|80!YD~_Uq at S+1Je!S;T
z;8!$JgpVnwGms8`6H_tn^XD~_%La at gsO1b^g80^HB}%<q=Kd?w-~_Iwr7G`Te at +qN
zQ_v0J#mTDh4P|aKEzg8G^)?p}kCK8=2Hg#H%y4#!#;e_yi at Q-H>Ndt(MB6M1j^(_8
zvQ~oJ@#6k6?&Cj>Pa#~FAyFs>#nbjH(<4SgG;MHn3fknAK$Xb{<3U9cq9}$;xIJ!!
z>dq at Q71^hBBuh#H{V7-$Ww8S8AB_R`l+YCMp8;E7L{G6r*)?O5N%Orit=W>_*&$fR
z3qim!Ot_Z4^=jcszI4&;^N;3DLps7WChv{2OUV8=a^8O<i#qAwg)?$-(nh?Bq@}OC
zt=<OfgJ(Pr8^CBl9qeK4MG&m(Lz~Z{)V+J$B2-Al$s&DKgRAU+Z$*v{+zf2dQ5=pJ
z=6It$qoWVzO+{)9dxsCGcOK^_TNibrV7baV>y=KVj0zZDX3A)0TCIB|C{|J0{<>l+
zH!`80bOI{&DGsjz`&2!hgw82rCZx9-%HbG*nii3tj-za0+=%|dc%U5>9+>R3I_`3C
z9pW?$Kg+KQhr#%w)PJe-C_RdV@$7wXb7*txFLt}HR29iYSNV)w)pFT~QC_{HIwXB9
z9r-R~!i{)`vIQ9G$Jqad8gV)N-%uywRV25_Q?NY#u7G`t1lz6KpC+m))aOpsKP5%x
zu+JL%WIe>kqdm|crE^pnVNJbf|ByO>Wht%6rOJC<ZSOinpeo{0p(@;+*@mA>%gt-t
z0mJD|F~UH5*UsLD`R9M&ajQR#En*{2 at X?V-s@~JX`wwbcVb$waH_T-Z^EnL&J2bh7
zh4D`}(2=k7Rph?8N<_W^yjbt^)P(FRYN6Ic2i5DYi~T%S7x~WBtpZ|%GO7{<{|}e5
ztV%jxMcx at N=w*TQ_4(^aoj?3xj-jz--)BwZ51=Ql6etO>VkkLb%8R`yQW8X2-3w(R
z8-}l5*Av7``l?_fd^<GSRqnm<$8P0E>bmXvJCC>isrqA?BsU?FVT`<_z0_k-(m|KO
zOTf$p`n3Gdg~J6l&Bi9x#F_*)rGOn~MzkUB#D0{O2n4XRK%6Ld9)FUg5H^qcrTsTW
z)M4cNvf7ACXth&yEk#LPi>|pH@%}-9BqpUU1Xe}%l(FQKSP3*V*@@Cm(y6*ypakIB
zn=b>R7;cCYqQ<OhW?ryF*)+nKq}mB_)t8Hy8P6Y|Q!uXxNU!R`+m}~?s}kgXIMugm
zm_y11N_bfd5EzaGU>BNboN?&Xxnci{bvd=Y10c(-hn6#!w29~lMlt3g-Z1IuR28We
zHTzdB9f&)>-|e$41y{k(Ir_icSWh0-&Q^1ZT6mj}_%oh6J^@_K|9 at 8lW{RnrIoK-2
zcu7cG2a38UypI$qdHHwb-B8~r$%!%&37XvG6_l~LH1YeecA9 at x0>OS1zWZOng3f$D
zz^tn4;<4=*P`*4D8)^6rtiF!^{N(L2Dq%3{|A(0dhS at ***@H;e$^|L8AB-YX*!
s-Y+F9sc{&2_xpd}v!>p){CG(OzkAJpHPZZ?0R()s)bv$LRcyll4~x(AU;qFB

literal 0
HcmV?d00001

diff --git a/data/panel.png b/data/panel.png
new file mode 100644
index 0000000000000000000000000000000000000000..0fd72b87f988bb5745f952545e163c7ee8f0784d
GIT binary patch
literal 41955
zcmWieX;c$N`}V<&S_Sk^6%`07ZE1 at _DIjYSl`8E+A^K231cJ&_B2WkzA$y`lK}A8O
z${wVM>>x!95R!;2aUlspAjpycfrJo}03rMK`hJ-0%$Yg&nfY+dea-LAneY(nFAsca
zVPRqY>n}h5*TQ1U=dQ)+FSdQI{~IBk``lO}{u^@AqJ`xs{yf+MI}vum!lJEUhvCxJ
z&*SaszeFP}ENuGzf3al1>;7k9QH}cb=M%r9paaIx(U!PE$D306+g_L8?3*`jmhK(5
zI=p%ua4^Ak<;VQvzq~mqdUEsn>A$}4eBpR$TjHD7J6B%=CN>+~psh{so8C91#Hkf4
z>XeHQ+8X}-_uu4Z2|+bA^F-=weiN at NqZ>SI(@i_fpoH?f+qt(9PYGi&GQjTmo-F<z
zvJ)sHvX46dKht&fFW7KpDsEa`BMQCJGT>WhI!l%W!PVb~AGpkM9Q at UHJ*J=vGd>++
z2<vp7ZySvwR4!9;V#~Q{fag>2CH?(4YhO_3ha*Wou#GgT$lgQ5%hG?LtW<QEkEwHN
zunNjr0bg2M5-+U|V70yk-+@!x*!+&l>xpsZ=QsNFpc;g+)(JGWH<?x1wcBSDH)(v&
zUrp(Nubq&>_H`rnB4;zMJaL{yS{qN<b*}k>FDtgnKeesr$#d9i=-rj30A}O0DdM6p
ze|UwKU6m30(m7*e6{AU#MG?r|h`a1)FA$1mvUaR<J|J!(L9vP$9mDAKLGS_Fvu2fG
zbItkXxv7A`RUL`}Kd#3udZ|pCz|}`r^Q+Z?>h3E5MLl}TjS#x7T|kb;Zosdzr);is
zTe>|GrSyuq8>M4l=^ScwE3r&{EP-jiERC|J!rPtrAHV3}|55N7{=Tv&(T~1XPgv^_
z<`H|cxnzd5uTe(1(jq4&&xhc(Jd7GX0fWNgcA2d#;5~1OwBG$GEi<mmLExm8i^kE#
z_>7Vpz?*Y7G;Zv3eEA%5x+6+H70ZU>?Ty9cWo4GW$Fc*GIU5LqYtq<xX$Dq#uwh)F
zm4Vl4$(sTEbvtO5#)gobKi8<YZ_1Chlt(L>w$j0tqo1cdY_ubh1}~JNbHJ}cJ=rTI
zk=3Yv{_9oGp0!(3ju}DD at E$=-_|qt3ylm5SqUN2Zx(MCrei_rFl0(J!iP=HUydoY~
z>zke%BVBfpf}C<2_1Yxm!$6OH_HvhSPn0~OXAV!0bz3S1XFLvwYK-;76h|y?u$H$2
zpr>Eb(s<Er8JRFrowVd3mOX;QdCWF;CnPc4o1{kC4t at mkjaH~`_Fs(+w5NAD#HvRk
zu(63^01IEjM-BMd)A at 5c>N~uIxt9<IIgVXX<UsUjvr03oouLwy#$#znO-aRl;>t_>
zS8&s8qrMJAaCM~_(|A3!Qcnvw={>xZd8x8ATi0B$Pk+QIxzw!j9Za65XP2=Zl2!B0
z*F{qRmX}G!8#a2G%ghP=<`sX-0`n(&G1^SG=q&k5KltMMQ4K~+-d|=%D{Y;$3X{&4
zdf>*qc#GL4w^+UahNB1S2NaF+HuKp!%@c>&7^+A2+LJ8MMNmwHHg)h;HUahLeP;K1
zzof-CRyBd^8SCw{pN;`PJpf7SW9XnjcioJnJA}sGydeR-Kj&6#qNG<&;g6{?u-7T~
zKA4+rdtM}Ghz7RudbW%izltUMWDUl0`55~a3g9-eaWfdpu8OA+yCk&%$rKu%YWl|s
z$vY4{)91~l?AAG;G!eCY(W=GU_>}%ylJ%8ajcFNhFEG<0$9xK_yd~Qae at J#w_cnSe
z01WSV^MPa|a#2;J7UgmWu(Qv7SulIh*qF!tq+B6vK7O;r*}TmS<eJ4T(*ji$1}wae
z-dS_BwfXFysG&IR9(xbISh%*V|5t#bZ&m9S0<Sq6u18h+Hc_38b#T+a*~?t5Jw9WD
z$T_EfkT9Ofv$|<YC9R&CftgltbD6e+g*dPCeel_jt)*A{82q7T)txEP;9P59Z0B`-
zv6`j`Zby`pHOHZTYQVW_&{YXv=l18g at I5<O7QJQ_hQ^m7>KDyBEM~_wmis_^H9vq&
zq$q<If<BxhLK=A9ESE@@ok<WLe_TI}S+ at PXYrwLSu8m<SQt9)}#4A)j424Tqs7Wz1
zYi+bde~zyXyaXNx&AxK()CeAm2J`~zZQrmpp_ at BvDh}s7FC;2drRo*a!$$L~4}%~7
zY?Z6fG_ at UB;O9ZzO at z6pOTg2qr_q5u=3^1lBad63PVP`a2jVPf$+G(<ANgGGBomvy
zewCH%caDzU^Yjzwy}C=_aGprv`j~%@(OeS&6(5{zp6<?)!c>@9*h}AOU4@>N=F1GL
zEnSSK)%eM=3fCwMyBUNzs`^9*LaU;!u#v|6o^8B&2x^q7YV~)BXW}`jL at -$Qi+&r2
zKC(+7Uu_nx#?MG5DV=0^$8H~qlUC?dms%md0cUpbAeay_RG4G$*PC2z-yLK9f+m;w
ztR9Q<luYT{`odti#e0iVF91r6pN(L)T`PzKf;(l2+G at hu#A?aijAi-L<@L$WcNSu{
zn(+f)O2UhBZNmq^dGS*s)Y|O|2$LTid!j4(3Ek4{VKHwmG*?IL{EFypBwA>`Jl3=q
zSj%XLO6xotSHwx`sM22NcC%xHSXAGaw#Gjy3np}xOI*XGCDkf{?P1`=fH;&^*4-He
zlc=zt=~Gj#b5mt=X&_q`CWHxun>;iN=Izc%;~PP$P{Mz5f=br<-elo`M8!UXZ`S|4
z;;ZWQsZX<5Wc-&)MGV#Dmi?IxX=@~}#7Y_$Xx%4pz%UrRJT6Zi2;{$Ml~QKg1W}r6
zR{cYZF{Zo_Q1TGN_v`qsPFrm;Hrc1|g(yIz`zS#~vg`Jz7tPI~#NV5OJv1Sy60stH
zzpIptCw!Ae37WT$MG_=>n*x+rRRQ;^=`v9^@zzJ~QZ}9nfez~^&g+LB%-+>*C3P-4
zYh}r+!gq at +xE#(ai|09Kylia;&!raKf=gdq(t~yM(iEj+Wz4)rPl>-mrmx4hx2t2-
zrf&yriW@(r42JZq#2AJC;f&_2d5I0#WRL5vl%&<kk*vAkwDNvIS!<Am?6q8&kz_Dz
zTCyF+Zg`I0D^&_pdsM^~t5{vGjgq|obqrH8rH?~eKFOLc?3kVABSyOt6HMkWX5VDa
z*(O at HPHigqBOdokW{H|vo<HO2%Yu*`I0ST*Wk6X>dzz7jAAW3qJ;0}+0*Y~__>obJ
z;eE8350hgePC36crJzbCQyk^N?X*_Sl8{zLU0i45AS)^s=RJju$7h+XXsTo8b-ZFX
z;c|ZZ)Tb`8-+CVWN}8fvzXzK(t+M&E;Bma3Hp%SdcJ)V@&e4ao?_+?KLC2ggELh#%
z+WLJf2plz|4-NUsqpADHAljzHZg!q%54buGH6x$zG9T?!0j#e<8&OJo_x8InKs~%|
zy^L`mtR)MbkE at 3XR&dJnaVc5UgC=?^xYN}%GCCfQQ-!YJ;eZ1F+25^1Jbr(1ro>7u
z45bCVk~Q1D;E_#jWiNdA6-f$%<Mly3q$d+jF|}M`I(O`tH*p5i#@iKdd~tLRjv?5}
z^#u~RWa at z5{g6s}pWuH6jb8h0j!G!)Tw7>S>pT1aTxz7jiAjEey;Z2+*`M(IgrOx~
z>7fU{^axmOX`a}a1!<-HJVHVN$)QOdXi#y?NMpuj_jzKDRztL0P1-+}lT%bTkz&($
z$~@j}yH>0?hwF2N%+4>Ck~^=Hq!|aL%~sB{%gXH_fg5h5LG at hw4_O86)@2X__Q3tv
z8c)%Pgm~tb1F~-%{}E|~!h!sWIe|LL?9ab857s`7%$$0MHCThu*0HKQyB;mxL0FCJ
zZvrQF+GGm*KA^;Ed7@<V at R1o8zUH40M2o^AiN5-2LhUd;@9ftx$-qM~060Z3qn_U!
zt9*k*<+UOwd_KV2$+Fb(J;%s|TxX1TC<R3r#ryLwP0r=b6vrF)`evPA>MQ62I|^v=
zJ7jZ?J at Mw}w(_==n-Jt9a?0Txp)i%YnbN|8=&T#*CVb at t(n- at IgIPe-dysjyhNEzW
zbGh!5y>h_XxV5GY)C#^D+|!<3&tENu^$3^><y1hLq1jfH7b0B)e>)!TW4p%tAgO#x
zo1u5+7IAmU3G66oEl*t7x at g+#;tC~NP09b7Q(6O8H2`M|Gu2EMt?a{-q3a`9{<xod
zLXu<KG5JnWc}tg}YqCZ7@@Tno^@P;buw$jf9B*my{h#4&C at UXl=lfKBRcq&1g}#Bm
z7AGB#&aaT9*@Nk$F^=a+13TcEt1^XUyy*me%)UU&*D>a<oJ?73dF&frQ11W?<YT}`
zd4SCv{K)TNq#c#K!<c4MMv-r)8F`uE>%*n;HtcceR`PxuW}mpdSuI?9N2c9J-}5h<
zvLKF9#q=9+sib^9A{d_nP+y4cZ>+W8%}w8FjPeO)o?mk#2c-eGGQqXi{2D_t7xV1X
z<k~Njs8(yLiOf7OPrPm8Poh;yP1hBEVw$OzH~(5s&-CE0jW)$dn?;4}9Rv*gq&%DS
z5vi%eBkhyw%_<vbL!Y3TF!y- at ***@Zh~R&GsB9SKQ##dU?x{yW9<zitpJAA?tWB_Ali
z!hrO$eMn%fu!knfQI2cRecn*WFQBRuS_TC7<Goox+Pg5<9 at MO3An)>GAV^e=oWl at X
z<*{o6iVVK*wD3Hx at 3TgAO23wk@}gv$(<nVg;Zy4-U7x`1;^2Mz1v=Z~AVk_F*(@{;
z>w^Z#x+t%I(x5u?Gve{jLS-<=TWrIXWT)yJf}#4L)g4d|ec8$!_4choZWF(sC_we9
z3)NHjc=N$~bmLi^F1W$*fOsExnPmPtr)V{dy)*zCA%0Y6#UIDs6rMuPjJ=S6T9fVN
zRoJqlrW(+ywR9p=jEm~mLv2yud0T{&EuTz-W76nTF*f(LP<~vw7@*;(E#qanBw??z
z4405L2YU%W58zhN{=$}P=Bfh1`xwzsHAwUoaen6<(i at Ct0H=2G9Z8{HgdKqD#Egv#
zrq1 at ***@w=4bqlP_`frq}}do-N`JRLNdh27UU?}asy5QY3_fxw;tRwx#K@%&2{aa
z&u{KqW~3)>M$un)-|2T^nKh|nxdt+}$9X3&d5rR-Y46?~Q+D_R)3I8ebZ3SBu*$F%
z+|JD`au~7#7R;nwjPpt!mj!AkHf!g1h0r?kAsrrP at Qi9y0lm=q3Zs$jpXqT3^Xf at J
zMn~D}3(WP>)j}LP8kmJrWONGqCyi~s7bnk}Iqhc-REFLo$D(FJew1bUa<}tmhuzrg
z1TnTpKOU!hAJdU1v{O;y<aejL?BX*W8sJU}jP2F8YxE7bR?RGft|>A_Zt*h at 9As;q
zALwmg+qp&-ZlJ$?l$(p&%Qm&txF?<ui<MTzJ#!__gn&Md>Y8 at U<T;ue#z;O9-JDK#
zb){?8Qb1NI<(JJZu<Q1Z+`vnn5Y at F6!tPOf*t+yARP^&synN!o+DX;g&bZ_YQy?vs
z)7SHIi9KQb+e$@iN^xaACaa&jSK(AY=E9`k at N;;FPvn0QwsDNxu`$}Soi)1RM}cGh
zAWC=XI5)XVAJFF-0gF~WjRuN*VfFBToV!)$;4EN9IcE||cpv{ucm^i0b$^?cv8HkI
zhAt2^3w<lV*Po at rfXJg%y2n*XQXF=hrloo>Wmv$er0-e$6g9cyAJ+c&p at H+`H$Bip
zr(@9vMMBES(T?};fXF{=JNEn92O;k`W}s^#<<EfKzWV7=(e{T3`*Jj++%B`s{tN5m
z_36wh*KpmgY{9)QzD!-Zu`InHXBP8HLTytI<CY%cNF}31z~#blz{!n^+mg$b6ZWD{
z-=NEOw<V#rv5lNEN{Nl~dNL@&6ww-(lqT_#&7^`=8bcieAKA*Ay0%_G82_g>@lcL?
z73PZVdj5<(wMK$K*?r6_?pSHx|FiI&1lmlV^!FOvepD$rdR4>;dRp<Ga>yO68m&bq
zOTriWeAR`C>SMpzU5V>YVQ at TJ=PEqC-;2spa`Z`qCs6x+g^jL?jbBoAU*@(}u+Z~O
zWyi7}xzEY>byu|WMekcx|0}rW83L+$=f5oRLhd}8xgJqo``S@=`x8a5RCyt3K at iIg
z{}a=yE~|y94~c+>D at ECSxU*u{hid*7pq+oCZbw{U2y4_|uzJC?{xEzx$o3`t%InH~
z(Afmg)pgF#;ABgs8!Oi2U#7g?xu7={ySA#^u~ls7T9v?N-A(@3wfhO(Z9KhoHSDGh
zwYSzCwecXuV|~c=*{PXbphkCF#g}0VQ=63(<Vth#0kOGDL0^)5^+00wv6y#Wy8&H|
ziT&c_&O3G;Z|(a-JaolYFs(naF?k-p&3}z!isU#Ez0|>un1Zub_X1(!fm|@I-0q3$
z3gN?i;4G3=y&W>>AJR2&E at Y=^<*+$`I}}4#ytNvJ1LisGu4va*UPFw`XW+eUGI4BA
z2vb<+k#!>NOsg)=PQO}q>d(m~vX^)NJ4xA(m1`^S_ at LyJZCyHR!9D2m-)=2{UPF1o
zKG40;V3zSQC2C->f|nth$n(p at HLm%3V``$Thvf=h1U&M%`-2_MW4kKbuV%b$t4wZi
z`}R%V0jcH8s*AkzcGaPve1e5K!?d-}O at CVMBC;7FdCBU#lkcX$Dh92Zjy)~SD39vl
zvP;Z^ZyJ5xov7Yl=NZ|2RaFn(XxK4WP|92CuT^VR at 7Sajw<|?{cN((E7nH?}4)+(r
z={pkN3)3?$=3`qL3jpK&fl&y9H~zZg^75Tg%lvKx$ed`I{Pzd=0%zi$jtmz5=uSNt
zZ;JW%(0x%x1H{w&uZ-S^TE#`yqsUCjeHx;ap^1r%MWp}q3PX2er^x3aj_sGh>C5Nb
z58D6425nA$9IuO$1SCByAZ=CuPSm{blgvKb{nk at ***@sUFwasL|(G{wp2_z14o2j;%
z)lbG6NTo5f>wb#^^78>IP*3^+`=0Rh;a!W_x?3Lk)U(yJi#;2qdpxU(fdcxN{^sDz
zk{Cyk6H1^<4Q)iFL)&9xSGcjdzpB4I9%cbts4jRAqAYoJJno7rsnkv|vraen*DuQd
z^Glrmk61deaV+pwzK{0wpWn5D81(3Qr<#s{@WqqLiP$TKYtZjNauNM|VxfUtu0sf^
zV+HCVFUjqr_M*~}2H)L*KSlxti1)!5?HKg9K9ZVv;C-;q@^l2DrbF at C90-+PDqRRL
zi%fAQXNzkm;<B#azwh|h1U8Gfb4 at c>jnRjZ at b}=i18`#LWDMUG4E(KsQ0^Q|GGzQz
z*>PufNUtS9IxDdO<~vjVml at -K5`vXwr>9%GXvxmBQ3p{^!iHA=Xi6Dk%VtummRGx{
zgJaj8*u&Zc4cJeg)@D^UgDxI2L*KzLg|Q59UTv{3O2u~zn<HnTw?h-kHO*b5$->%X
zoAh9c_5)hbqskd>@}IvI7eT#D8<;(kb-O_Ell^ov64596h6iK?_UAqqviYCRQ4TW4
z at gsaxuVjxtW=c;@s#!Cq{kg*PopG&$W6{#Rp^|h$O1D}ow at 7w?o1r_c%@v<~*ha%m
zGVeGpPj1vJi)-Xprh^p&aeL&G+3^%Vka7p*RVM2k4MvJJw@(c3mizOc>LB@@%j!<Q
zjWgyt{H@}mRZ_^23h|DVSHaV(7ooaEw4!T`96QbI>mn0lXniwRMQMQilnQuyW2&r>
zp6mx-ivfkN%<IqNB-r3_k$HZji5=v}(r=NEk(*4%&6LAw8$JC4VwTX!KOAc--YV*W
zr3{=)Wqv9p1Crop_zvbs`{evZC}ar91Ihyv`Kl<>YMUX at haHD#R!HOQ+t&P?W=&`V
z at jWrz;Gy4yDiD}0EDWKq<4se$&ExT>3G)ck-mbb+B#ii{oScBM;%cy;(!QYBFJlO1
z^61J}!c1FqlUBNwJCrka<udd<r_xKcazXX=!W7`I<&~{gspww>m_bQ+)h)=zw;18O
zj^K?$EX+{;0qRl=x(eS2z>fN&wBNRZDjl%r%YjZ&kR(5^tE|8beQ+U6K4eD~#$a#Q
z1=&`xXIF-=!@@vyC+q|NC8Fo<QMNG3VcGsY;nNt5mB-QK$>0FhgAee at SZxu&6*%Eh
zS$xY+m>AD`RdSN~7X2xhq#R<lXSGEHT%~YRW(r9o$*riV<+<rud*pE7uh|oNH2wBs
z4Q71S?eCVC^#vDD5oAB{50R~gA-DCjqkv_ws564}uGO(N$qKTu64R=f4%V#$YcF%^
z>hW%S>jK+^KwvvmmysAt84MbGSXt~Z%yIWFfi-^&Tre&~m~L!@%7 at NEtW&lo|ECOr
zcqQVbByRj@^9-*1zlvHK at +rVk_J33%1Fy>u$(~r>u*y9k`gz9qh$tKGCM2*L_t$TS
z8l&pW*G<$9c4tKug$TIxYv;A?8TAiym5ArMb$l6@)Zj|*%$^2!`3urlx3oeRaD7_V
z=Zx;XcrH`>L;lQcsC?PVIYXyuLPu%aPP?CgjP7-gRRu|aDXe#tg1~bXm|!~dhAae+
zS_!npSJnevJ4dsFKF3zRF_g<VLBp~}zuzDQ0A*f5Z)(r#N;`l7w!mvQdP1gm at a7;?
z at 1?nVfc6!){Gn0mne|d9d<bC$E&49MQ&0IUH>VbKxp<RY5(y>M`zPB}I8-fU9MZI3
z812))AlTWA+PK?S5}<{ZL+5G(^cWCC{2x8ee8V$JvEHoIOS%VY;kpLjlo}6nP<5_P
ze_wD9^FKi2kE6-&G93v}<i6If?rM6>kljmczn>!RB!oWV0^WxfFUbj(82=Fb${z%3
z6jmpjVFx8|-^c>*=9QYsM6F0boP&Fai8pWC7VP-?%3Te|=jrmEY|;0$tCnaR7RcRR
z*OXbAat at iQq8w9<KO<)cXt&S*?omz>)H?s67kJOyiKr&EjBWPf5*~)6W_Z?itgVTo
z0B1vA+UmAkd5yM3vrdwD!#6_lto35_#`Ade>DKVU8W?2hi?uz-qr_)7b#;93#n#8U
zn6%75J#aDQz&bT#nSp2f^S!%<FRbW#AKKb78+A9-98!}lnA7_`Oj`9xe^>3a(Spy_
z%>1{kT)lpz9Q0XE<&L0nhXbO0MNb^@0Y#@{Kfe+1 at 2rh;8~Tsa?~V6NG<uJU@(lh)
z9t-ew4<9Jem!mxTm*#lUWRTY8S!5e8G|;vgaa(ZI at F&Mzv_gL5kusdYolS<ycTd-m
z6G?6 at ***@PWD+j(B~MUe*<tf-q`mtIvy<Z0IM)!{5l`KtPW(yA|4xd!~lmpvC>ntfa3
z^rjl49US+f`$NRr7_qh7^b2ubl>F(Jg0F(eS|LTE#HZ{9dP`Ob1zHj>w;WqUs at u;g
z0aeAJCs#(ITCWan$hw~YVcljv>JyvmCBR|TTk7_E0&NZV-`E;kYFe=O3JURe at i|Ja
zqtZ#^D4o_j)_Ej{)cW6DJm=~!u9y1Xbx=l%hSU+|&>Aaeqc}UdATGsK+!P+BTK>K1
z!W(rn^lDr+OSfr*M7LbKgLbW8NBhgmDfZYR8#JR%#D6~4=c>gdtok5Xzqkt+E%)Xk
ze1c_UzYka%?<YZ9 at Cw`MBwxSt3^)t7<R9XreL`Ps$aa&yukdiR!5u^l4PhlD99H$S
zQ=9T{dkGLZu)fbU{34Rz at Tuq^8930z7`feN(vh at N{{pJ~l%?M$LtSgp0B23vLeolp
z*BE0ISmpAF8&|*E!#uw)*R`V&bjBFug6ynhwY;;E>*yM!nL3+3Z?@Q_t)KhdAc#-g
zJiEq1uIw^<7$4I!7x|Y%)HS(?7<*BCiBHn40)zNm+<^ih5|zq`5osOL0 at UXKuE>1c
zOdKu=T>h6rcL`&xFEND4ADr&K$0m1RZ}Ty|K4l1KTTfgR@!Fui3tb at T=^=B0gWsd1
zgT!-r0kFm=YYO?!a`ms+4;92K?urK0+_g at E=q@}{#9yvlFXL(N$3>9vM&I53gct)J
z4UxcbA1bD(@DBW!f&5P8p{(Ch%@jSSI?EimeqQHf4>CBV^2|bjParuFk>A{ikY<kh
z^}G_i`CxJp%6~Pu8k=7sv^Nl);kA;qOfGftFHy@(?ZIX<nXrDxl}kS{=2WJChSmeY
zY!SWV&3y#QI3DO at l!qZ88u+*CyHmJb?cQFMa5Q%a#T}3v>anzrSwjo9r>pGMy7IJ*
z7(Q`efFL`sZQ>JS9F{|e<a0`2Q)Cnk!YJETJ3HBLkGx=3-8-;$PTDv+=hK_Ql6LoX
zw2X=mES7yf*-F#thju3QvT};JxwTuFx`j)-q))P6jB&k<>=~<wV)_8+Mz#b#L4r>x
zXBu$~mK4XZS&OC+ou77m{+ARQ#_J#x-BaRj=QS6Btu)^Bfe5R($u)nO{ANCV+cWSN
zM9%#P`S2YtsjSdcBUf|W8|Jpay8M#Pw?dN|ooi7N#8KAUXpd&^hC7PUm+K%6Q0CO-
zZMEp{vv`*F^H|go+Y{v}*^n9eC*^JNS<#J at w$QOKmxJnVztM%6`%{1=Yk=q!_JRI8
z`p})3rXqZl(O;tHth9U+ at _YUTlA3(N$x|`EE6?>VtXa30zBbvuein?8UYynd-+OuQ
zb>>h)v%6E4KFNP=@zzkXScd=sH#&MLPckx~n=3nb*!9sVOk7~{bLZ|R20d_onj(8&
zs>T3nu at BsA1=X)`*)FG#%=C(T)iU|@?yRDsiuFg(jHDx?CJbB$<0-N9L%L^HP3lMm
zZ<7oiuG~(EM|1AgzT*8#T_m1BS*~toknYb|{cd~tAJjj7o3VrNSV{<xj!a%W<)r@@
zqn^h84F!}z7Kn&<DKM at Z;78^O=_PdkM{tJ^jKhk?ECke07G$;O;b$@%wf9yn|EAA!
zbo?CE2)(e|b=_bitdGN`ZJh1nHCRhQcE;w?9ncKv7fzQYt)z`QQe8cyYknajly1i*
zBFkZHjVj{;9u<RI))FcTyo46RPA%)%!~5$RJN>4 at EEvZ1Eg|M+C(7|c{5nASF@)uF
zqsG=6=mHic*bB#ko6|=ne`jr+j}3Y`cy5S)!#g7 at wcL_8IwaW81{XN`C?}G-4LO`s
z_X93r1AJfl+V)2i4f)6;(o(a*X~)93Mqc*BrExtu*{7i1Eu0kK0`d`RrB8jR>R%f7
z1$pvLVu)Vcm>|=AOVz#gSU^?g3wNq|3^0G}Uyw=k^{UL%Z*;c+d1Ol^><#7#!QlI9
zBhI{gv(3Su9dCb|vf<_3b={&bD8df9u>Ko=W2Mt?>0yZTWz~<WPr=}8L5<@X5?E~4
zL3;6H^<DjOdzfrfv!--6KIo$>m{i3r`>uc#ScGIc!c<eS701BH>+bqoxyA;7jAz){
zw#eEfgNzodiB{h6?$f4&kRj}r+z9=@d!egm?%9<tg{JD-J-lx}hBY~jK)PFsNYv8r
z3nqKj*;bPJ6#368f4QQawU1W?e6fGI0J`W|2J0Wk4g=?(LoA>$7BAG~pV#GGUSo=h
zAOF}#oBe5Af1;AQo=9C^*%7~C8^8V#=7fKLj%(Ah$KI2F{=$rJ;wh$N5J5_|<UHH&
z!-Rmvduk)wZV;B6NfW)vn9#sc599-P0p~l9`<TtS?SVJbRt`HU7^HGG at V{lGgwq50
z<GE2AFMKbWLW(j}Ilh?{A^<i`#R^(px at DzV&A`j5)tPi_ZOZBLl~8$p0=V*=J_|sr
zxs-ol)wSrkX5(IT?}^RLDRmK4zody6MaF+Bm2D1G#J86eJuRP_UEzfJ_C$a674t&7
zjl1 at JwJY#$0cevW_Nlt7BsiGBl#zc4Q_s3b!>y_3tz7R1Romjyx1(zYI~vI2l5U7h
zOx<Xj>>d94s_;g5de!cKeN$-UtU at qCbI^k>`?$jSrxlUp0)s10<(Hx_ZBr~Yqi;u)
zVKAqg1<Q!neTlAgT-J<m8*)7;hEGi~y=%`Wu)YA#<oRD)AKo8u61aE^v;2r%x-oKX
zXS0?O)Yxv{F%E0Si!V`bR{}XV1o?B-lj24w>0^B0+>oDQK{xcNs?GOp;dM9~d6aiY
zInm3To69)UQS7qMxlK6+t^bIuFR2P`F&rkL(JjWoCaa}AUgE8w%PWr*cEgWst<n5%
z=F3Y0kMs2l?j^PHBxBgpyH4B=W^L4XFxxn4Pg*{8bgdJz;d;4XK0pTGx`1x`-<ib=
z$Nvva=4i at _z+Ig08724um%%@kr=<NE5Kj7ku-D52`oV<OFLU_%D0{LZ{zkcijOHb~
zy(%H&U!`GxmH}?yzUDqjWIjl|LVuW-V)_Yj!UufIccw*Zj7PH}E2M$V&lQuI$J(^M
zGlNtJcqzLBk+RN_SL2?6MXJ50!Gg+L*el~>@>Ui6;<%b0EXr60oLmS+^v;Ugu=BAU
zo!N-D=Mtc8i?U2Bxd$_hlB|ni7W-s`Y))G_{TquAoWr2I#%}_}(*w`=NZ+=57c;d}
zuBywaT<6Khe2oOiPjsUxV}BGL`5MVfL8IA&)mfkVU^h*t1fnQSzAUUACPf^lfU-#R
zk4rU!=543>cO<ET@@_8Dl{nRIn$k>Sm+Q7a-`~B5K971yt~3NHbiIwW(oM|q8C^d*
zHGT1u{0Gx`;6?q{vzPd=Ui{#SRIy4$(D;20*mBbRZlb5FM6S1b#pp$-?0OTdL`c&O
zwc#v9Dg^}E-~~$gYsG3O-Fo>i#L}nCkZ~GHe%+|9%L;43v)-9MB?OnkFKLkk^+ynQ
z|G55c^$jbXQ&jU at 17&3-gFe?Xrd^~7tD;{K7aBg>D(fnM26J at TFIOnD+XeHXf9TtM
z9 at L`!a`;Q%%JuchJ0Yn9c3MD#trPwSvyUcS?Zn`_Zor8#y`P0YTQJnDzfA_(gOgcK
z6{vFXMuHJYRLTMKa+{Cxtx=xd4PARZ{jY>OLN|5*6?MDc#oQZB0Dp8K+ at +pA$PHQs
zls3!_VYKt0Tn{+omYQk=ZAV?Uub4m2c&FW at dW%d6r>-TQbFspUZO%hv{W1 at T@}O_a
zwXr_a$R7rr!*UIxS at NLuQ-(A5XC_Qlf{zS*8}~MvN}r2}$5rWH5l>+EO at e_0_8keW
zPV$Tv<UM+bd0l>!w80L1k!Xw#JTMr?4btxCW%V{8y19OCIk4nL-^-e-Bn=|5RW<wP
zK(^o=W~eRbsUNFJO%oUCOTs}_a==12cjX}{1rna2dR@(TP3f{d1Ru-JZK0=fI1#nz
ztyWa at sUuI_XYMw}cWsEgE6W8?&EOr?+w*cRi1Uks(L%X6*1^S6a)T$c*Y{uOx2jr1
zpFy0luf=b^SD#`GfZr~~DVo&Xvg!-fe0%;u!5VhUUormd*K5BxOClT(^xqk_HkH5M
z6NtPXts`_W#7w7qu%ig(pY9SM-T(4RpJ{dAlj3fI4Ebf)!Azg(jX1YBrQ<JAIJJ`e
z(~DY>V_Z2$X0qb~({pOQ2M0b4>&G1{N)h2#HhpGUK$5Xw!pfF2Q=SklSo8DHC!g{R
zu;4DcQ`ZBX1)R$*q9Jv{A<iN&#$GvpdxU)YcHD1V^}7=BDSpH5^#<Hw`R%UxeStXG
z_4a>T_Tg8KR`hmu+8(^045IigZuk;Vb*|q1ys%jDe#w!74M4f@?|5MX;Wd$MK|4FX
z&Of`cykaV4&>n_NdzB>^N)a|$UjW+1Le-B_gmVd%4HDm?jMaysm0kl#4~bPrLB>qw
zl9_iTOiAmp(}z?_y)KUh7uHdd2<b~nV59!;a at 3XowmRaw&4j*{c*l+2KY+s95r7L<
zP^D3-M{0y+_r^_d_}EW!Bs1{4{D_Q&plbUL&J})x{Jb*Lq=|ZS at P;P-&fsa`k0;BO
zD<4bnHMR+ub1SuI8=m53{FwmsZ)YH=CJgX^Ka<n6a&|^AzW6JMCusTTh|bA(zO4RY
zwvpe-`Qxb1CU0?uqyo=ugv5 at q2yvrni11|~tH*owX#w|#eBZY?w%At@@fMUcR>{B4
z3mz>;Ngwl1#OjI$dz_6ydmuFBx_u=O5snCw07^uGf6QQ2;Y_zDqWL~B@(c5<XRfDc
zM%Dy>^16l97=oYPPpb<JE>J0f?NJ#zGAuo_`&Ei(8UH6AW>GluR2*gCNYYi=y~i-e
zz)RuNA+CvyjF$^HCmsUcWtRJJ%LC+_oy`>igE8lVV9AV}q=qM^xWEife<<S<>cd36
z7PDh~KpprJ$)l)?Yt_#q&lL3OtD)`sp>FN}ol7W4{6!$T&91oWy11<1-Sd*8(lfzp
z%eA0oF&EGrbyRCtK+YjbuEK6)_V?uJb+W($Q*IP@{Wqd^T;CF1At(8hapGzMH_26r
zYQ}r}c99+%Sz|*Z`x=}*{RW2+`RWennWG3v?JFRKoiY;HO1)3Z<a9u!-&D#z&g8YW
zx5*2&!mmOrV^2;B{{bfkPPQ9I+%Tc+>8G?D3 at aMBF$#0+cVKpV-&d`6Q9M#8d at So-
z#ouIj@}68Pxs#8q<Uqx?WY- at dO3uNeTsj2P7-BrB(f}H?;qCU0iHVi#9N(A0GkK;P
z6HXbGyNjOd7iQWPd)n0tj-y}AdO(D?7DilCI$U7?qjprab!N>4Y7MHm9&}N-G2=OW
zyms7QIkr>zBnLOZ{D#O{0taFCG!8~|EbRyr9D{UqZuCgUx~}Q)Nd=tmL9i81>PR5A
z5CTrRKt!#yQhqm<FDxu7a<iBZp0hB{+H0}h-P!Dmc;m62y_s($Yo8&c`)kfE2nKz7
zK3gs*@hfW5T(|Ya)}4)CbK@&xXlu{S4f4Obx%1hGEpX&|pgjz=AuBferX^^e3Dsym
z!F(3m8&wMVY+WE at Vk_PVYxeLunR+=hvjr`<OGH=Wf5^H`Jb~N6{hmkVPOImEahtDG
zR<+g>@&jDjfQ`HZPpFg+V$v&dD;)TS5}!q5ThWS*ld#SuAskJuO^M=fhG(utwwA<i
z?40RMh+1bJvNF##JGNxBB3RM%|661uXI8ake4oVz^i0Y;FWHwFG9ims5*ql)vp1Po
zT2;52Fb|q at lOl<sn_k8^Pv;eM#;{`uYiI+ss%vT6X&@b;>oGuyUkcSp_G_UE4bm$e
z9V`Z1n1A0VnqTZ312_UVq4`#vb~b;D at GRfRR0k0GbYvxg;5xwCy{O1v)8B-i`TR))
z&MxD!b`wYWL~;W1k|vh-zXZ1N1w-1rp-!LKnhq|2PfYq!lWo?ZYQQDMP>MOGQcoS1
zHiMJYa%JJS$(7fvX3rt;v;C1+9Jm0;&pfOnXEB~gh~qu;kyGW`IC{anA2+a~T}7>U
z<6{n_8{Rsr;0h~Q?R?L{90QH6oBHVJne3exptuKtkNp%0K_6!Wm{O8cC7}H0{-&<y
zu;F&^l at P#do5+x(tgaZEC8jIBe>L>}L3dVfdu7M+3A%7JR2kHMtZUnPm+K*ZNSwaa
z&l^og*^d24N#3~F!b3$Y#X{VXKk}Du9TOM;x2HTLOU(9<B-spTsm6ABsp?xyb-4TT
z>aWm_W!Hv8!VJ8-c=OTax6v+g-Q?zU=Z&o)9*X*ifTWc83eJCB+;;&(YAe2c+gt0}
ziL<BOH+)rOCBJY$H(ZSuZ+6#hSN-7rIto-JHr=KcpjFR6*z+)GhVlw|VWE|L#}P}h
zS56*UZ}{dB_+q7Qv~Q!_C2pf7$Zz52mALkZT7VcCKQJp;sJNT$dQBW>ye|2N1Q^+p
z8+0ui61M&cc0t<?+i2&ZC5gD8UAd-(2Cr5$2L at 5Bd*J);uTpSj;%tm;%CO!ihX3P*
z>aRT=ww&2I{=e{wpvZCn^PDw|qj!H;lw;^kpzpEj;b$E+kNja1w-Ob^LfhwF!={Oi
zfLB=ABN}4wFpk9Y%~bpe1-6BV_atNu&e3Hp=L4jV2)G?HA09yK+F0!}t6%IqML)C_
z^9G}g|0jx-ZDj>bQxd24dtM8Pr>8Qb%p=<%-{qHD*kDFqw<oL>BVOQw`}7NBF}@+O
zEAbs8<!tMx@>BTq+nW)#YxVE6&_aG+Ug^kH^>8z_M$J#Yq5POz*b$JLySkZup`Y`<
zn*UEnfg1RolVl8Wf~}65EkU#W&g9!s=faLkMry#oIeSv1ue&;%F at 71~Bf5vb%l6vU
zCVo3W7^}P>l>>|I)em!)y4UXsygBZi4z at U++Eut5)KTp>E(n__^iO8>(o=wpjox5a
zxUwQPpz?G6R at mL#8?C+`4m_FU#lo=f`v+CktFK3X5ynpT&|0iSSa*3x+IbZ8l!=$d
zkc>}?KG#mwm+>mW-~8FlvwjTS9<#>idi#*$6aRS at k+^81iY9fx%VcVQX12s$7z+n{
z$YTGjQcrVO6>6xgmL!Y~)I0J-O1r6$Jm6u-wE7q6!hxAlAEGa{5V2ion3%6bz6VkW
z1!a9*TI1mSg0#4MMM8=TnZ}lP^6X;S6^Lg^FJ;l8C?Zy~A~alM&+vheKjRpPkTF9`
zoE>)(mdZOMn4<RZ0=TM~Ry>zKX$Qw024Y%VuyD0_n(b;{)~@mQpZIK-zom$!16`3B
zDGRmGqyWfFp<;4Dn9o!~8&ZF1jQ)%ypfSiW-2BHBVjnOem^Ph&tIUTHSqhAP=}%gZ
zV4BidG&||qiZVU<Zy}GBk~NMz`jLw8Z55Sx&GaRUJ|lY2hK|JXeN)5_uPFuci5 at -$
zf5FWZiKvrJ=2!Cb>*T8|N!MB`49$sbkf`MovhjnWUsb^gM8a)X5k)tHB0fVP=oaL=
zPCflSk_{rKA at Z9Nwk4BEO>ooaJZ`2l2u@>S!@3k8xiyZht6Y1;rgT6mIbPwZ>ffl6
zW4 at A4Q-+~3qHx6jLf(w-=urSseTP;g{A^wDGr1~?HyDv5s;EX99LfT?{A6)E`cPNx
zb5FS^7XR(F{P7jSV)LCsWFv1)UYtDtZ9xPc at hSyVByRs~4L&vP{qGcF!^r?F9Q|#z
z`E2FOXbCjqZcP;1Un>78Gn&Xk#BnRwrJ}5Lc`veXysJd-Sbq003^(<M{9e0ATKb^0
zi at gOyG?>ha?bi>wpTSEa+47hU#}}v!zup2;`;Q3ax0PM`-@)#83QLzm!lBbkao^=*
zxCa55i&HV4vO_GDL#cIAcq at CGs6C~{kMKWv2}N19?W@*yUZns0jKqST;@d2~+Dd`R
zE7fZ>OTkMojD(R^evKtU6YY$id%(#G$2KgQzGj-DGD!fjRIN~q+53m5XN%y==~YDW
z_rwzy#K_;`nE!(+nQ<B(ozIlNL^hNr?aFqZ99b)Cp^ZS-G1Y6xX|HGZ3yqsu at AA4Z
z0L76a5L$L-TKmK`l8vzEo%_zTRfoNn`kFV?@q}T+V~onbO+BoaSoZ)tjRP at 2)3Fk;
z&Sus9afo!_1Iw6m#}t#);`wrF)S^NjO|n{S(+O<u4umEIfU&1d?m6Svviap#5Bbq5
zFE<Xr&j6da72D*+fE#uNpf_?5 at 4<BY6Q0sx7bC)J+V>#n>T;hIPN;{H at jK?)(>0SZ
zp32*5^MmJpyOaa|XMDjTpVoE6IN*J=%5P6#zuht$`@fX{DG%v~JQ`+#o|Wh}QF{Ox
zN=cd0VedrQi!Pf+24L{qPI(o+_v8O;iSW+`+&VDyfbyKV6o|X;taat33?<ky>IVqN
zIcu+e=42d(glXFdipIk4?k7XRywbRi?6<w4u1|$QnLI(KGKwv95vqe;^Ou)I_ev9B
zS8-mgSR70Bt$KKQ=CQ-Gj3Xdb=jyFKZbcBR+)w=qH;r6^$`0|?qd)LRmp<WhG;(&m
z=!j|?JRonTniqWL=v8b=wl0GeCsjW!2fc%U`7R=+;VhD*(^!N221SnWi{HUptJMch
zwif0eZv4fdo52R`pE~S27vHd?TO%$ZM~a_6fZjHbja&>L6i=0w=N&+LGT$a}SM*V1
z4nE9_Lvd5E!(E?M%`iEIRsW`h6{H}*i at m?v)nYK<u^$HOr!_r=Juv!wIdlIQ){hpW
zsv;R at 7!#tc!#hAg#?DbRap+a7z7wwbJ05WsX0H3l at R>Z6I9bvr+YxsX&Z8`))kjg4
zK{Y1`;pi1$L_2H~ny5^Iqn{l^-r<vzBx-kS)Y#$3nXFvb<IRYNxvrYb3y_PV@`qk!
zg{>+7uuSU%caYC%K^!{zgz~!9B?q<$>7VK+XF>rB%{*kU)AsZ?!wb`$&KB<1RwF#Z
zuaq=;T)ShC{y`ke98ddHhLh+Qeq*snO<OzTuXq;4E?;P^_=$vQC_rPJm~+Y}i;xB2
zV&&w<d-a)e*c&7>x(*_(``C_|sPy`&wRrdldYe5|+PV)nF8(8fcSyfb#*bDs6^V*d
zeWYDJW9r+UTukp&++S)fry+ze*N0Jk^QuL*ohNg^ZMeFAT?rCD?k1fg0Tw at 8&<A})
z_}Kx4UN7e#IuoUjc+YEFXqNus_XS;iS4_Q>9=+b%wim|=KPnlFYW1V0481kJa$k1g
z+MszG=t=j5mx|%b=7GlN(Yxg{|1i|{wY;HGtnAAcdLbqp06)&sojwBen at U1`1S2Gc
z>XWiB<C48#M|*x^eBT*~9)vh2;XE>K!%<7=QL?`&4d#Af<9VJoeEHY69;oF7*RP96
zTB+TqN*w0vyDl5#N9}Jt0j>r>rW!)~=*TL6d>bG{Puf^6OtmB7tcO1GP`U758yo-3
zQhYe`HdOr`e3j$Hy1;c|G%fk2TKFU<RF*#ud{9uX3#fPbT~dx6ZeQm79R6KFp-$C{
zzN#9>jc*>TCsDieI)}2k71izp%qfrgz5zp>sN&`5M96`|$&uVL<&@IqBmFaWd_Slw
z_eTt{U>`!458maCDajGtGna}YiK~rJzv<xsGM0B)lvY~f#CtQ2#;q=ba_HaASn7g^
zlJ5x>%guI<%Qi_zTM!uuMWIH^BuC$h1o7qPh`=n_#U;4rG`{Dd1nwCwqMDqbU26q_
zhDn3;s~{vZOoSSR%Z?+pn&<Ds+^F;c&HW!#(`}hqI`=t`UtB8u7~@dZWJJ1+DF4pK
z+Su~T!UTA)kFO)Mv9>RTmoQyh+Q~Rl0iWJsF1CD1*yS?_b#8~h2;lvT>vxNv%m8T8
zlwtjz1f!EUR!RLJ$iEvFaX}P|_-M;N=dh~tXAq#2-pu&1bQucaM;<=}?eLxHHM#4a
z!1-tQDIv9+%M%c;MRJpA55E(lyx;7(B&()%eCGMofly29%;5x{BrvUsQ0@$Km(FI%
zfTC;siHB=-GZ_0?8W(v^R;vibQaw<k*Bht3oe>#DxakT*wo5$fLk;zkT3U*D at 5?^G
z6R$;jO!h_x at rK!DgPjip<(*^j3+bD>I*Zovv;hJwiNEX+Lk!%*UuVXzc2-OHnmF at a
zWaYpZF4sG!YBPD=sNYBb{vQ+J=D844LvNRoVv2NGh$DKCBc6_*r5IHnVAJdErq_qk
z|GHOR=a`wiZjiPh?tsol!Ixhj^0>*bA1Kk?wOz>GTJ`~jI$jGcsL!i7Oa`9M3ur@#
z5!-;z+ECb_ at XA~JsLSN at -9uPzhI?H+<yN?V_?5rN@=f=APtgSaU|d~M3*o%%KH`#m
z35GuTAr at K_Ogrl%o9!X`D(;-`9yuneeSjwD-)3BJr0-bniFAF~fkQ~E+cD at Twq2H-
zD#R8TkAtF1YJR1goL=V6Y`-0l+1q at +bOa=r4(wQDVisCDx at 9ruZ3p+lyXO6D=hKE<
zA}cbkA7CT#`u7lM86Vo~1`EP?zz-MHhrV^a7RmRju|9tk7hQB3NQnd)uy={UkyM at S
zpw0Zo%oofnl}#b>>4q4uG}CEH6m-Dhw39YqvC8kYZuOhrJ>Ud#U7jx$HFh<J8o%)T
z(u#8Ud=p8herx)+8j?BqIh^v5e@<86`irc*-*b^1BIGid^te5$qoJLvZLpM4GS{z>
zrjMs9rYuT<AG=q#)=uk|@ek}4 at 9eAH6@*)?5G9BZ+j0v##s4J64%FRoBY6!3S9kZC
zg?AI6L3089F1FS^X~g#EC`a7J;>taAjys)__=U`282gV5)Bl7U#4UE$Rc)?wg9tw*
zz`J>2gyjN1Sw`0miREIMeF!aRz$;5WK@^ABrdSG>>xm)fcgPX{@xrD53zFFf at xMTG
zq}Tjhn+2<P&vE64{mNHb`41Jk)O2U9CK|d)clU$(J2v9WDn;Sjt}U1cJElW`En|RE
zQQJm~8^B*uT0`GHmIXnzgRXIY4+B~#>ii+$J(yhk%cfWV=IY1Pzk<}I at ZSON+4~O=
z9Ms68tcFYB<<WWFFB=|1FDUYQu$w5)i!+VZ$L+mp&K{9|lV2XIn)Bt;^%nCV6V$Kw
zm#%E5`EBw~ZtyTMoc}(^qMJWB8&ZhGec!zHe-t8jzQ-ezV(!t(0L8raS8E#@4x-hm
z03m`<2=~X?`%xbd%c*yI$EIdPMXHPRlElTN4o~@N27Np<8<+n4F~2<HI&HP6WzMj1
z&N at h6>^o_DfvYA_)C<F>don8R6jUo^rYI<)2nY?lPQw*C2i~IvZEdyP8LnVbvb>$=
zHdOFzsw;~YbZh)&mLARHf52WlkW9q43Vo)i-hwsC`7`i=W3_7>EPr?a_)|W=WO<Mq
zH}6fepo*-rYUL+LLb_}(vd*dJIcje0evf%}?whZD)kUP$&J7r22lz~&<wg^!rYH*q
z+KnxJu4b7e$m?n`dfGGjCMr2lj$n=Wijsh8r>~Iwx-mzA)wkyIwQ=%AY`*3=U(pTT
z&36(l0o$qM<cVLgQX_rBH)zCHSb<{Q%mIx2x4=vOK)DhUKHPqF{#Aq+O3PDgh9-K|
zPLzm*Sox^YvMkUD0R_D~XUl?7an3>5$CbP;J6QsCg9Q*Y*Ya7^|LY3$xrdEktzZMc
zvV*yDV&n%_nw%&(*ez_HY%canB*elr$0#30qE<65&_yfn3>I()Q&29{ah_x+n#&N<
zqWMddU7jHwCGcrNLaD!hWu>byAGy;*SQV0w(q;&w9On%*CJ?z=Dmn(fJQs-!r<aJG
zJoyKC_w-qO;Uf>*83>?vCd(o%@PB+xJ>fHZa}UN#Pg}-Djwce9v*=o>ZNn?rVR(Oe
zwG<sgJm`US7CU>T)~+7V{;X`FiQJC~N^7}N(>o~{(ae1$(K>+C{jkBF&7A`KcK<%v
zR)a;!?1=f{`p+IWN}rsK+Z<6CtlRl_rA}wqe74%X(|6%tmNGoLvi1R<Xo1ZxFlHn&
zGnsDo{oianfXeluV12*nQ-?OqDgm^f8OeNzWBN^!5HEl?`os>4HX}WVi4(kY)oMe&
zzbmi~zcTAJ;$>vj&n%Uc_7A5d_As|$r(LcsM|Y{;!B;*8NJp_JKJe<i+|veX7$wuG
ztd(DBJw?y6z6USo)Xocsi>M8PX#@+66XIiH4vaqwwLOU`A9pByJ5a(>a22n4Pm#Y3
zQ9QHcrD4*wFP&F)ryu at 5iq8BY3H$%!D_5>hOKYy2np$&<wU(|Kp>kN+a?O;?ndRAZ
z6Vnn64Y?~TEw9RzsT`SkUpX@`j+_UX3LYrs0fq{S3d$)U`1Sh_ynlVYU$58m at p!o&
zBPi1`)Qzx$gMv!ddc3{n=Hl7+6^S#}Pj|1A4;N%xwSX91MW9&4BG%N8fRj~7!Ol<(
zfM37X<qd(HFKo?Sa7aAa8$59Y_j)?LF%={EY4RYUBO|$gE1vDv=sla+OVX&ml-Na?
zPj=8F;j<eHxT#?8nw=ifD)HFqKF~E;vwp^k8IE8XdL{LRv2C^Cl<IBodV=uEY~@=t
z6hVxesfG77aT}l)b6~Nzi)G6Xif{tSS9u4NV~3OO^yfy?*(drkg1c+_tuPq#p|;mu
z`)PzB&e+z~(W}nf`@{(KRoT?c(gH+&pHbzUL)^Y>Lko at x$dl(`F&fH96*hJvpe6Rc
zPrPfgo>lUG#42&|jUjpw_c=*5kJ!smB>t8Lji+uDF)5ujEtbUh0MLU%S&#fH*M(~@
zmmurRmx*DL<+&yp0Ba$IwV}!P3EJk~u at dPgPk9Kgz_bFc8*48SgJ<wFxjDg;X^rn0
z+0E{R)Ry7<1bG2lzvMSMj$46XNx68yj405I21r@$Ym4K!7ZrPJzK?)S<GXdRDKcnX
zRQ~8GiYni7k<%cblq}a8YJ+tsYwSYUzsHmkZI}`cCFN{h<*luHg&(h`bB^9}{y7$7
z+W(EMHP!7=F^6vbEgPawUB`_yG{X4G(Ns^Ps at w{Q{gU;r<Zr*<w&zSu6vx&CL at YVt
z{;I)R at B#?WxWUK6Z`^Yfh-Su;r7ccHhSSw#0ybCir2Dy`{7hP|x+Y+8W6b3ze-x at x
zI9JpgoB-DkFg=eGuY3!T;NF1ZcwJZ7LthmAeHh<<&>HZt%3)e0tMu-dUxWC43thss
zK27dVS?-e*!d>Ru4aAe2;lhwQ{(Q}ZHp}Rnn=DQp{xac>dF-tgbX-U=wrl9;Jj9ik
zu1xjB3Ee{5%6CV-81 at L#N}HwHOuhtNJvP+6jm0yE!)J$C$pw?^Oo!#ge2C>tF>~r{
zh_V>LS#gb=j6!9aRZ?6L(UyMw_?VI==7(P=PAt-sL>pnuRN0hqi+JeCQ^Z>Qo*+W`
ziQ>>BD9QFgeye~Y at 6cuzP;L$83ExA%&OwU6UlkoW<?A6X38FN**;v;J at AAK(?Q#cx
zNKA3>Y`9=FAB&1{L6|PkTw`I4?+7e68~#t%O$KfOA=P{p>QzVpx~^6)OgiFz*z+K+
zZqTdQTlUnnMM0Gy<Ml5zypNZjuZyB`ru23^%xZecHVSuv at C%5+F-w4!0Y#D7I~yhP
zPnsRQ=JiRHK at lej0xO^*aN355bv4J~!{;qU7NRG`aF5QRR~I1rv)Dy{(o6>!faeZU
z?;ViOe0BRcLNt+W%IeG<I%i2qRAgRE?)6D6Q2#+|E?+2IIJ-}<?kja8;p76Nv0Iq;
z8ZsHu0*S2~n&~UBPn4GUu*iIEB&AIMZP23R)*5{evK^xN+!4s!6)UiYigyp-#teUC
z1t;7&I=gL0;&h3lYrb4R#j&YB9?yT@#5^JN!o-o~`tn`+teCpO18&owY%Y^cVL>^N
zFvoTCo1Q91quHMSC(Gl<Kpb6I(?p)pf?2}qKj5j~aC4-EcdzVsxCu%SJv(8%Cfp8!
zFjzOqDZJf<-O_mmsz|q<c-b^&Cs!rPO7=iG2hpZnz;fW^IpJLH`UW2VW&srEETGGl
zRV~WRtF8<G_2b#XPZrWzb3P6vwm`lM^IYe|n`Rb6NC<)BDdDs>@ogK=*}9(({@=`6
zjf1}50E&y(T+5+=<B6=TxHOQ=>Lp=ezo+2PF5w}Ok9^gLG46 at bvpQ?EaWoyc<x{SC
zTwYU55{a2}U8`PgTa_Wj=W&yKv{gJX at g84(h!b}~B9!rkpERIru$<6|vWb-n&Ar0)
z at w1Yq?v{`&x`|Si+ep~@6mGO@!DN_~w?)r8>ayCd-0 at ke?-0eSmml%R>HRpOXqm9!
zJA;&ol@;(t)Tk_CfxUinJz#Za$8+Z_wjFJ?so<@Cf$)ShYj$>Nfwe=pO5CQjLqa5L
zdzs_P6WS%CeW|uB6L)Q5qxvwGU2xg!rgN_A;qk8V6Lx~vQ$g1z)_Fg&<~wKeN$B*v
z3*QLdW;pMo!EN6Ht(T%oqcq0V4!~;1PtiZ^1DLSKrmFQ32qI_hS0X19IJGZQHR$A~
zxpzQK87>^FH<yy9k3fbD%V}nHI>ojfaZ6y`#Fitmw_g|J7ECn-r5w%E^GXn-*P|uS
zv|y!`P`}ab<$&3khg$Cmn1~mIF0GZD{RXJZ94-WQo{}vQE^%85ih`AbLt$*mjNceg
z-vL?}14NRm)fVF2l9H{KeS^-QPWaB%(3B!Us!t8}Jqa^QEZ@&DX at 2)z3ffEf;N+s-
z_>j|&Dl+W at qawNk%CIpr?e at d8%VgmE+hMOZGK%v)c+uBcKbtxXi8_5{uy8HKCE<vR
zadUZUad`NkT}+KEzhM|88mQm1qL}WJ_0az$?wW?slM)X&dW;6-<hBlo*P5-Ab3m2f
z#|XnCE^*}TpU#F1xUT?+I|?8)xV+xg;6T0^-t9J at 7rr?q0rNXpv+3pTi9`C&hxfQ-
zf5D~GxR0IDe>$`Q|Mj!fbW*2MJGS{=AK?Zs{=rxVm+9Z#bugyEv(H&r##AHwGKV8o
z^&odO0;>M#g2en~51e;5S8i6#eyJX%h>qUjKwbiF=Ufz2^tYw at Fok{kii0(=yx1mH
zKUMYA8QAr!W3u99Y4n*0=u|0b6SPdA<p`K%tFps6b7#V?0{~?$v$&5TQ0(>?uVTpS
zsn0b-hY&c<M_xBxbMIccaghhxrvHP)X^s`0UH@=5v`AcU35dRj){llCPbv4r4doKj
z>c|CHr`3yxB?la-1@~<mv8etF^5ugOs^Qe|_F*T(&j7?KqtXGWSpHuY{R2w$>{jR(
zS)y95>m%rm7kvEm%-RQNEHhPa`JqfOz;hM_JGvWZCJXukda30Ndmt!mCnSM4yEa3w
zWiBomU-mO+0*c)MY^rJ?TkqRQQluV|&wQmi=}9Q?#$Seg+U+s@!OGQau at 0Ji;Cz)E
z;tv<xkmF_fhZD97e}_RoZI at k^p3lV<2C1Gm5gtd;6wk~eM*qp!zK=^S4;V+{_Vs_7
zu}_ at y_nBPYX4$E7PrULUyYb$@-$q^Zau00Mm)e86K$iOYV(!6KoX%RBfZs-bZG&@A
zR~n6@%0CXPc1aTEyNbf0JSVxkcU9}_>c1J&%UxI0qP^uT?98I*<aW!YpZ3Xdc{d~q
z(X<4Hk at K1TNBn4Ahe%)>PuWFn54aQd-_SiO{z at P?k&$<$65uw0S;<7_G!IQB5fbNh
zpJCaC^VW3kCu4isQ{j06gdP4akac`)(rTFrbec|f>=g<ljix(k{O=uLoWGI!_v|(L
z`g1W3Z)ON}snsPr#%@Rfu#3hm^Ix_<(M)_VVutkZm5V(j_Lce3eF_460{|<1RxXg@
zBG(I3vM7gK#s{?zFErlN?7mw1X|PIpnKwX!7&)I^pI0oll-NUC*czKx!D}H?z?Ffk
z>#L^Qn)=qr&1%xp^|C{}GB*xAPWIR}%+4h0^d=KF2H>iVe6Mwj`h)vgpjn-56z at mS
z<Qz1{bG_{=e)w*eoFf^+{RkZ;ORIb?$<49F`SN3gW0I*vZ_25W8q!qvuDL*xVL9oz
zH9+oj%JR7H29DjiOVo)ox$eEi*erVfclbK23yGCE*9b#|q2C~1;1ib&bkuyl^|$=^
zeEwAm{~2qxrmF|MfyjR>#LYU3_V8Tw=~K}rJ at R9!PaTmz at qHv2Yc_i$8y8zvbcw8J
zza(q;VkrbCXTDt=XFUSI at Wn${LuEnwfT%UR&@5IRLStb at OMrb^!phb;&l`|*caI8n
z(?Qbp@=q*(12nL1Sk#i+e at Qap<sKc+nzEy51Oy;hI&ptYT2i_%p0+E>b5%v12QxzI
zR%g)%zJ at zW!WEhZsz_h0-Fd-29T~RP8)o4^f&<q5bJn(;RD!7V=Xyue!uraxm#OZN
z7469C=#~#ONu|vT4anID;-1w1u1w>H4dp7G*atl+=;I3p&Lm=Kav?0p6eTI+E}EBa
zRoApI(9#3zi^<3(Dw$1joDi&e2^=6?P+E5~mui`=WBUMfs=0|4GAJ%!x_RM_5q!o%
zlB>mX(8%sJyOeSHSk!X9Jt|MHDJa5rS3(g;V*}}hoXC&4x2)Rp7&)oz`=%Az01Z%P
zDz7r)=qz<=gV01Mjly~=`;Umf)KXmIVKmKWRA{T=8po~-xmvD74mQFXbatS|`(#(;
zCAl#7%HmS#`b>O^9<ziZ%7>8~6vg^Dn*Y64jZecT9Dpr==<DRQH|fLPYJh?Xg0b at W
z-MDdKAb+=(t~;Ge;si3d5 at Nai99sFI7;%-(9ZwWD8ImAs0-Su3gXb7+Kjy;P)(^4B
z6@&uiTGp_ at u6CrUjWjN%o7QLssy-9SDn_ at cHX_6UE7TC<vJjU>fnUwZ$06Cedv?}K
zrYvvM8_U%&tGu^+mof26|NZ?&Zy;H`hxo}Z*wzIu8mft4s{q$mH at 5eW&EKcu>i)*B
z6QTtI)6 at A3<?y0^hsi*&G$l;zmz0JJhF-z20W1^^WH6FjK^CNrR at y^{B?;7COP(p|
z4QDi}WP at tW)9_%fwz_9BwnyRz?bt<TB+CaIjKZe*{akm0w;gq}=$)&{Y3kCtQ(8u-
zo2NyB|MtV8J1NFpYrA50jaybq=f3~X>N!GnZxmAXv~>()2pCRQsU3Ewoem!YIHE87
zbXYx9BE0XF>WcP*EzGtDE8OlEOopGFn*~s4LsX^;1Us6~k1r at H5L+^C+^~P>+Sx^)
zdX!OS9Xpy9&^8Z!5EQX`DDMrS-Knn03$Chnz;Mnuj^yTf%l^U87R!!B7qPKhg#O?s
zTk#{EO)&B2$nc^QNU74Ha${lX#sEBox=+s(G)B#iEp!^3G3PVf9%48$!SaeAz1^mc
zs`%rqu(&sTq}|opGjjEDs;qN_^pK(O^Cg&HIY~pk_QLAVK>hmC$!-1(1P^a0&gsUv
z+#}ejnq1=^FYDy~FHB_BL6Z1^m-RbSwX1W?p0$5a7RKA&q53<~caDi)vR=<x9r at I{
z>;uC)!MWvw5h%O&0l8?8U~KH^{>OQmuObYu!Vz(Sy|^O)#g2b#CxLaclaBp8HXj|C
z(jq_Tz!lnDhJ*AaG*tfHLA80r%U(2PRWOWx;qn}t at T}dVS at DNGUbg?*f_sx{)V!|9
zi!{1<&PnPw at CvS<^Ugxt5-erxC6 at amLsK@!8Xpfiu3%n_5<7gLx5UGC?z-hyrslZO
z4)3vatBPNthT_wASaDuvmZ{DDK5&d%9{9}$J)j)0cE at olK<}9qy<q`%wv<6OS$zuo
z&#~AgJAvvS(&#wc7#@J^TC@}nWFXEmjRkfBb0Fw--w{Cc%q9HXOjiN!6xH>fr at p<{
z+sI2n&Xie%>8HM9qx$}{VO9d`Osbu4xxpzFj)*Ik59GnOJ=C|WCNClmBN`7V%Khz(
zt*NUszo%k#&uYbIQaun;U(%|J0D?g3rxOu%cP%;hB$o2IL|73cajSK(_B87{nGq#3
zuMV3VE~s88ytfB;!g?zEl-kz%i!jaKetuurqwm`)cr%5{Q{l;p#~Navdb2c*w#{zC
zuJSZDiTWz`1J!=mi#b)}xp1Sh)M2>HSvleJE*K>}0^jI}e{%_o9Vy0g_{95;*q8Ue
z_U<d%-5?kPUH&0T?vitN$d(LJ#k=4_vB!cO>~OW(BMyw-ropy(Gp_zb0x_*7YU$e6
z)!PP$+`8p;c*9yfqHEZ2YpD$-nLf)}0DaLv7S$1#Ii2H$S*@c~mFf7xx5w8H&-6 at A
z)QP&6OHITGVL&}<dqE&!Arq_RpOp<1Sgt-F25ZAcYeC2a<eDI&UWH`X)tTOo4KC|p
zy)LF>--d_#1ck0Fgzttg3QrrUcb6eX$=Pe&9jLXZUxuJxNk*6++FC{Qq=9W`n*)iR
zx?5N)d%Q9&1O4R7I5UD@*9Z-rq<!8wdb+2-7Vnj!%4gZ=Z&uk*Sf-{wJAiWmreEcG
zVDqFPN+ICqIIh7>sQ1d#H3?UCgp-DeigQa<?w=i9Xj)I-ZZI<M&)(Jc$Z=~IafF5@
z7Us`IW at A1aIXoUNG)BvD at fPc0>dD24&=rI5-bZ=EAqOm*xLp)TngVvE2t_s|#d1q+
z;9^VC7L`DwvHwz51{3q;-!0{ZcZVtDrg7D-!8U;ui=Ou6C_z}I?q(gmZVijjuKGbP
zyTW8Ak1L<>mxS5gTw^?Ko$1H@<fVMmA%0|?XUu7pWX}b1OPUf`KL5ownc8)kO_-)j
zxf!h7IQjNayOr^)BA%F)cT&DGonz`>U(NH>gVz82j+9hn_s;&>49^<=wKt{NfB1e2
zbv=vp4KCg12gxNUL+-d=LQMzVSfWPx2 at j{t at S<xFpuBq8E*gw7)D)!nSZr9rMelG8
zK%IkPe$+rWFJEkUk!PH&Vv at rW=Ng{w^;;@hyGaCkt=we!YuT{&eDnPjT$;1yvG{sy
znj0pkoM!(b2)%R8&bDK44?L$iPFEk_I<PfCNY0}R>fxA|7d&pu!%-RB2HY)X2ge*i
z3TgF<y=vVTrrq_smAkeIAA6dDdV=oPYzh}|Zpo7)!A^i*BA8uZzM-Xix at r$ty7bB_
z`UrbMb4I|RQwuOK)okHATiF}@fb|rkqfB_5IXT^^lIka&qGlzK<ht3yw}*fQyBi;T
z^r~@7Gn|HME}#92E_jPtNStd6ba)4wH}<9U7p0-7!j%2)Oea<#(>i+ZohF40=^}NY
zQ<}kYM}Rhv#eE!JZW{QVdr^H$g_36n42ORnov*>1PsJcv{qHLdIm=72`^2BF3Jm`O
zk^{Hr05f1ylU}wXn?Ho07!G8$rNh7kc?mUZZ3H-&=;L#)`$&DC2g$*RJ!RPb3w_|r
zwM(Dm5pQb)(T7n=C6>krx$eCku39-u<IPy~^Z at ovmP?qkiIGLXib5Em&Y=j{<>Je<
z$BfQUJo=NJ)rs-XNb0mbhLRwj^xDo0aG9>s^ZM%ME<g|g;`+v2<daq~ov`Rac&;5m
zUSIsrL=V#DrD3yrVKdTS{kV5k=g9g`yWi;o50Nz9lgiTxyr6Iis;qnj%7;yT`g>!0
zv32g&2Y69ZSA9@}d$HP>-J`9ZX)A;L?vn*!%LCLJ9~Hz%;BO0W_(JFj7jhZ%cIwZi
zihl4pFK2zMxtQ}v8^AcpIa%GHb8B?b2a#KOt#DnpAHyfsRqzGZZCJu~%-Fwg{gcZs
zuk at n!ri07uZ at sgUa~ONDimqKno()sxl<S3Bb}0H|@d*mOz3VJ_G+-}A(`WdiB~MTy
zJjKYjj;P0+`V#uwL9uC+=Te)ZdgkY_I1g$Ei}Qn}5Vj4`t^IEYBr<`kh$fL|w@|eE
z{0RLI59lv?B8bSe6!Ixm$k}k#lZm_G=9u%AcbwyZX36uv*O5bK(|xUjDKqz2k%~qy
zjY|6`)Ndw}TVddX+*@aYBZS9YUy_zTM&SEic^H9hN84NOg<{B*8;2uLkcGuK*Qd_H
z?}Z2CmBNVr^n#;RX%5doq(V2wX=i$VMn=o~Km>9{`UIwwxk912+TqpX*uN<CNhfvj
z@$(kq!hs-<jgfI(@#%ezf_GgfI at Xq>{JQ$Q+G5?z#JkiyiTn;!aW2fEvIRjNDw5Gh
z{9w$)m_MeS=l-Ov!}Lv`{g&6LdEbnG8Q@#5^5@%?XS?Y%h%Ah}t3iK0m*m>h1v-D&
zPyJbIP<P_#$;PQC(>yy7&$)Kj`9s`^GlqwCm_1dXW*OX5>7SD%J#5VGKO{PBJn(`8
zx(}lcJcHe8n<40T>?r7H<AwZc8CP3Jh7L4)chPYPeJ;T<v32E_ppnZD8p_}!=?~fv
zi#r`Yq_!4#`xT(1H5pAUYTv8?B+E0dNGXq`yQRE8be-B8l at jPjPQklirjmSliJnA+
zc+iZg$XuxT&*~LSc`b|bpkw>qNUA at ZGgNJ>lxBo4GoxZFFBFWzP{Y<p#8ORLaWw8{
zON*9`0Jn(uFR0l}zfriR7>;B!yyiza<3rj9^f?&;FdA<3t*C=0-ImkEPe94<L6zvP
zu7js{;97#NHzMceH~DrBB~e);HGlpjyS#QI6ensf+qWaGXMdBt*0y;$ARaKSH~xmo
zA0)A=x?APvR>T<reMD_}IJI)*egTJfxk*3yY7f$Rsp9U|<OIuCInP+XUU{6+n)JRG
zgxb(`9KZeB%*pJlU!Rn;P&gZsiemUk^W~GhKayVH&w{nwv^l!Y+<Q{+w?NIz<xUzE
z1W}9E>cvGe|McV<qn4foLF2ocm4)#2c;0j{A-7w}6pc3&InIlla>RcxHfA?)LgjxO
z^zKLF_Dtyqi|JU}aySN=lT|A>9EBi}23UQrIN29EZ0H<tEEhI5$jww1F7hMz*ge|S
z)9`L$S?v}VxVExc?n2YVyYT<v3a&|lV&JQnM~z0DgF-O9ZDHLl!eQ7)KBDBDp|#|p
z%GlA+q{O-zpE}!}>kiJ at Ke%B3>Qg?4ww2;dhA)@nIfZ!-8+G;vK<MPj<gF`fhu>_K
zj7ZwK4w5bEtCWQXVheYv|LqFpjrYP&O`zSN*LrzGryJ^?V)SHQa6(T5Kl*F!p>w1*
z_H;{?L1v at W`ac&gAg?Y`Zpy^pJHz|5`FXl!P0JlgI+CDl%1>nWlWi`d-?i#7PY>Wq
zy=l0-6p(6z&nh?AxDFY_PC3V8XyqQe)}GZ6>}u@^-5A-LZ{3(H3_We%#We{IH;)yr
zwKnKA?u4C=nV_GWB at dbeq<~AkdlT`9E`QYIEnJ9955aYhx;tWw=r6Qh6NWpr(J$ib
zrDlQ!Y)2OOojoKiXgzDfkI&kF)Wy}TObi2Y{quq_`fTEQTM)BX;;?StNiO()W9l at F
z!hTNrR2lu7U-%t0Y}2)k&(udbL{=WEy_TgO38RIdR1T>e8mQ@*PZ;eN&ZcoN;(y~x
zwxgkN{mkd2365v{=FV*+U{e%nflSI6bL+8^rDAa<?3!BUvlDU(+eS|gGC(5de{uQR
zoZH~NI^?JuIA5&)M0a2;4_^V!d$B`3uDHr6BSElonk#ydJ}om&k2UHMhhMFJLSPne
zd=gbt$#+`?h`!op;CvkJ5_Bg<^Sjl?vcX#7aYfW;vvMGC995s=Cat>h%2)yoolCj^
zjdSbGE2zZy{Us2dM#S{Ga8-z!>nG$szBhr``F`G^^>&P-J9j){<pe|NJ`ZL#;O5ZZ
z6hO8Q{UW%DP=Aep&Fsv8$FQo?h?hrqm&x-hRxhvqO4!(n5=X9~Z<4iJHVDh?Z8(<V
zpr?9_csxew(4!-KYEqRBu6fK4(y{zn)o6VA-xOx!_Beo?R9vuq2d7mVW_4tB;BkN_
zI>UyCp}OjKkn at g7H;r1p4 at p$jT!J{tQ_<yZ%f7sj`lUMo;RR*3%Gz0KNRz)wQ~JIN
zg!h|dRA0dTT8;aw_96jwuglzsOy>A4U2{%0S5$p;Yi!deZC#{ZFb^__KDS;YKl!az
zrTQu2r1lK$(sl=cWQI}>I+`cBiSO+&=ub at ov!*W*P&btJIA{tOF~Q8Pqy^Kr9d+xu
zU*}+S*dsm6YZGh@#pf<B$SJ5KxWWEe#5~#hTp42SnKd$4*A~Qu80YF+<BY_i9j2}P
zaJs>nOxVY&=yi=XnG|K{>-1ujSh#oB#Jqc1^ue3}%oT~>Y)2@{wX_a*5HzVFk<CAL
z;Pw)<8k^^}CdQwH#VwSs_x3{_(-$1uY(&nBgEqFEbGy=vNjX!mUA0dg)B}i#cY<<n
z&nTRonj5aU<s at WOd-ty)lM87;qE~lV6dmUl@`HTnwd3pEc1$9TnrEAG0KiIons#*F
zU!Jl_zqu%1;Kal@`l&ahEtcQu*ts1GoxfbY5VrlP^U<TE&l*wxYb(WeeJ&MMS!BCQ
zW`E^*WqA>c%zm<POq?+TT&Tl}zRNE4{7PT#Kx_#j;QJ?9%ah5;{J-`Z+gCDSS1eyx
z)3Kk;eKZUAm=(Run26pGDyVh=9OMq~OdcaaK<QTb%CD$%a;wl$C3|gVc>6?U9w3rX
z2mzK!?{1gF-UB-tyFjssL}ncXQfnLe0-N&G0ywi7rG0F!G;uh8a;<_~xC(d;k&CGn
z{v4U6V^`2qdgDs3^B!)07v>ESf5Cfd3GDEB&TOXBWEbi9?aP}bYoZAj<oQSXP1^;9
z8-m_&ePsIUI@?5%z6l%CMvY+-tw*M9iE$%ehcKF-B~M#hBTll4^*c5u;h531rsy2|
z=kOV(Xs1sU{#IjU*#VMyU-9XfJa1oeWXz at QjO$na=)JUb*CSH>P&<KT2-XRYk10Qo
z<bp1Op*n;2PxQqfIw9PTNcCFNPP#tvNA^KR<j7;vT3c9nc0j;}z4qUy==uVBZw{9K
z!wphr+Xfto{)YV8Vf)O<4Md}tm77^6K5u;zkw_6GJ_wQ_x|Ixzmm8rWnMVt!D2UrW
zXHF- at ea62^b&tM4Pnl2kzN%Jq^gL^1`?a}5Zx(%}JG?WM8*C(&1k#d1>Mj<{S((?E
zt$m*jyT0fstnj-9l>3Jgs$lwKY>3-JE))ApEgCn+L+-^r2#Qxqh4lm9N3iy5ztV)x
z)K=L*2rjW~bbv55s&-W+W^ME*&~6w+>ufgnr%=4p(q(uDBSChcuH1k;s8sy0PR}zf
z)ioh%pab63SWI4Bhsp0Ve&>C`B0Nm2YkOz`t+=nBGG@=D9pDO1jMZEszpnhGvUeyr
z#S(5!Dqm4GV;>fprpzCEo_Kc_bNyrWhd9#hmcDr7K+<|mt*I$k*+!HA;cYFY5;wf}
zr-~I@`Ub(QF?<(V*5*<7LAyLg9!VT6Jzc*#>K9KN`fE}9t{HeKNHEcvg(_#l`)^Ec
zL<spFtR)kK;e50Vt=9g!qXmU+Ac8T!HNg4IcA;0<KmmdoXV*qunILqda_S;yAArt-
z<+MgTzdv~bn}`F=Z{+-hRabK6UH&2pfyzl5%en}6;JG~IKb^hA9r49{e&dolTMLZ`
z|9At&)e$}JigBLgjZ+9Q|6~NvB|luKO<@k=b1SR>zTDj|goV;>2G;p#?Gm*j_d?>y
z7VMA at o^2(Y)&n}_0rg65!41AW+GsyCQ$e7$!5Wo)Da`rmzb8=)REJU<HsO`B;Th>(
zqNKDnX-56v{mOVzh@`RKz3w8N4*+Rd>Z7l4ESJ|qhL7lfn7D$V9QJ<(@PwGF&mw7l
zSpR%p;CDj!MtPqZC4V&6R#sc at J_|o<*>3o{&3W1YUicb96UP5%uwsUAzoMfxn_%V)
z6h8!xg4eJq^0smpE+ at B;ptTvgc9p`(;%z)jo%qy^j))ag9}u{RrJfe&sQzbbf=eDn
z$u;c!MoDcrNwl;>%qWzjq=35oLZlHT<G~CPTtBf3i5vlrY;+}_e~?$<B%KwhuuSxB
zJvYMiQtH+dXq<xo7>?K1HeXkQ-`U(zwdI7yd~5;^d!w&&R>P+KIy!b?WrT!D40}`C
zg8MY16SueQ1dzN*w^oKY7O4UESs6yEQAB1CjX_(Plen+i%ax0{C|up91X{|ZZVEnX
zl&e1%KdW_{9h!dqfl(ddx?wlmS(&G|n$GIh1|qMFR|)Q7C?o6L*MzCwtQ)`oR at hc?
z4<+5~ZAKu-=Z>V*rqJ4IFDCf%I1c_DJ&f`!&?I&wt4f$wjHh&92EPLOFfJ(Rg7R2h
zNF92+%mzJq<KcmXPcG;T=mOEL=uc;gTFXc%kd?Z;9fqHD*u8N0K$Af!JX{y?+?Mkh
zjvb~nC6^5iv#w`w=QoUI`(u|+Ax%2~o{Y%wm>pAL-tnrmdyT28CR<(kK|w=tT6x$d
zK<w%HcgmkOB9IUgZ?~4Y+go;oyS=+D$28G~rZ1w*j+VHxLJ0K0?kMx;ue*2j--jR8
zB-Oa}wx#_{Vfqu`{F^!M?uX(Wgh$p(;~CXp7&e+Fdmz-VUZc38R!>&Be{{;U0XXM0
z5nc$wcRRj}(2f}HKE-$5c$znoci_h1tR!oO(`w!8w4hpT1sPQmcsM1-*KsQI_UzCP
zwP3fhi-c9=3C;)b)L}(UkKJn&!x|SGG55^Ul5#;#>;^%(WB%!|3~j~5ok74gs=I46
zD(`)f6+0j~QEd1iKOVX+w)}=|w-o_<<TBv7z=OqR<OE+=gMNv<fh8zwS=XPnyNeFV
zDKGXg`nSB#g+7^ndBJ^pXqD1+5D**B%N9iS|8oFazRlvu`ss3CYO57r&Ta;)nqD0R
z=4rn|tle8siH)OTq*{@ojN$0aPOB}ChyH_@%}l)K+*sst?OW*M4DZxzLQk=rciM6K
zVkV*7;4o-OMXW5tC!hIJnm>gAR%I0^RWwaBSJ5_rQoGXtQH!>X<f at NFHimuL{6&|)
zsHlHkj<46agiRiL<iUrBQB`~3979yLa7W_I+;nwgh^RX?0H#|$jmJLFK5Nakyhj?1
zgfF)W-BCe$^D@|sB-7oZYUN94GH_V`8XR3l#l%#29TvC)mypTVQ3!3bYD at F<eVqBE
zaXIHB$LY-_K+s-<swj={zURcSJa at vXV%O1O#FaFEK-wiWGHYZkt#JT#dXsJ9sH<Bi
z<^dnP)o<@uWkYGprs1>$$@3Wn(o7#XGIE`OVVRc3%iR~N2xc?g?ua|2=gIEYz=Xa_
zIPzGP-m)3B!G&7&maW<3k>=XB*Oo=kD2_59k+SyX#Y;M7Pp{e7%*zv=alE&On(N_O
zUbS2M5zilTD(%8$R=92mFIdPjUrh0n<r)X-7(4T7CGW~4R982u>Vz>7u6Zy_oShW_
zgP at xm?^QfPYx%-5&Q#a;ujAAwswh!)vVL$uHp8swOpW$Moz~aU2vb}O5DLp%(mVKy
z2O~&=0$e5o$pTD$9cCuczb-9e92Zr<<W_fGaea+e%mJybMEG0um2gwP<Cm;cBQGVj
zQg(hKe|veF>3EBq*gdFz?GfPH8#PHAJ6c?#`0PwiTv~d2m5bkO|Md7qZ|V=v;?TXM
z=5-$g*Y!!EsMBX(mDNjU;vBeSv>!*Stw39&pHmd4`qu`mfC=!<FZ<4i6SoOVSS{G#
zJlAbqrIw_=2jt{L-YhzbqKqt6&%!FuG~>O*f?By8`0d(Z5OQ)*TPgUEB_NL=A7i+?
zxVG{#TZo9ctL%U<)WNNWMtFc@&2+f<X*En9A|iH%h8u(fW2_y^jr6DQU>wU=;i!K-
zQ?B2}nw6A+4A?!4_jYZS0Pa-zZfsp=j%V_3Cwy(Hj+oytZsiXx$o~o_0K6d#`vE at _
z{H}S_w3z}WWDP6d<h>&NtMxr35ZqDfEn2kw#c0fbK&0|+N*XqUJ4Qs$U6mL0;(5{~
z9v}LEfb<spshlhxD}=`$t&>~`M<XrtvSC at cHq`aguOu8-^`~*D?a0EU%S$-_&>LKH
z+BzpA1QRLSa|CNP79|Vt*q_9VcmZrU;3+v)>d7hdd_ at qT)LP1EW8Vh`sGQ&UDNsI%
z`a12Yyn=2h$>RV4+00tB;{q^M`!96EjU)4Mp7y9huFN&+YCq!1jVys~$orHp>Kaq~
z|F;B~IeHII$sjCw2Z=QD?HfX88EffuZPK$YOl|%%rQQHU%YEK?DkU<~1G!^5%csjt
zyLd;~&Tu7;25*o$j#H{%Xz#QEOhV_ZeUrDQgte06?&48s$R_I+eXsgqglCYa6PiG*
zi7VW*mfSMfbPCN}o=p8jas4AMW{(tBW?+f`MH<TL6iYReSxrsv*LYIl<HZ&1brGW!
zd=Ty{lMpGOX8x>myM2<2dso*&yg85S0UZ at y>AIu!Wj5B-Gdg?<GKKV;)g>@ihI-ui
zK57!f|5|%?X=u*&m1cX+Ow#Yx<vItKhj7b`c5h!W6y5e`%4ck^2~CVZ^++40r?~n-
z{o3l5F72Jxtc>xF$;r`Sm(hywrKGCAt6QL+f;6H<9h$XKNZoYS-0-E at M)5#{elx+k
zeZi|vI{=yG*e}A^De}3Vz0gYwSp8XxmHzcNX|GN8t#6by?m8X1181Ow at U`tN=v41+
z9qBW-Gr({6yuB1U_GlfE$vtQyf13S3Fq>;6zEy{#WJNwRi$0dqiQL_Mf*E;#|KSTV
z!(#B2J9(3}&u_fdoU}*il4^7I)?bklGBZ$JaEe&;M`pp%?q8Xax?o5wfGV%E|4GxT
zXhNB-eKf#j+9o$K(s3l=f1>+r%F9dckZvff%ha77SmhxS8*3_WaE|2SWeX<n0Cjh2
zNb;suay#Mc>CQqW9n+;v_fRa-h!<Qal8?g)(6}cq*<~y)4Zmtr{S<w&598lt6+BxU
ztu%Lr6?6UApA_Kw^{qT1geNa}JK+gLu|=DwQvQYQ3vb+oh!Av46*T4)n at VpD);Umj
zDIss^`t0K9h7B&htK8-si1i2wi&PRmUP&m-*-J17XeQa?2Q{b!rulQ0zuxVgWxC}K
z?MgvMvvHJ9$Myx37j&7gfb5Q}Uvu(Qakf<*Bazs-t)l70OK?kGD{}N3IerC|CXTCB
zPoagv?WllZ`TMYc<e<ZKGGCXvOFyMtLs{^DT~z7{tHvJOH@#U1cSF-8iDQt&OeF;#
zCMhga{}HN|@#8U%S$&SIlJ@*P<hb<Kb at B8m)&N9+R2|e{W)@goUI=%;x<I_XI}BWl
zJ7qzkeXe>>aZHX)Zyi3dX8+F~$spGGs;u-<qdvTL9Qp)R%Rg;jKlubt^sGAg2A3)P
ztrKDy>n#p!GWqk#qWpzWsCtKY&UN)Mq42g6-LKd%wRXdngzF8F*G+bx>Frw)o&JS%
z&3#txKuX<lKcia_7(oEfzvvDv(?%?$7ZqjCHT@!#o*`V>>xJ0K)?0qJj{SPQ0i{_c
z8NW932T>ChAFY8lsZC6e>CO37LU`B##WM;<=lMEc3u__8 at p9>gLwUzq#7gI?aBZ9m
zZ5Ox!fX)kts<zc=-UU-HxL5!fyePqtq(ZP*l}qRc at bc=VwZjz`8(K-4=uG49>@ZiD
zEl=f#pRQyd^!v?kIao8*XVUaRl7OB%Y=_jzbHJqNX#l=Af`X|x>fC&CF$+9EgyNLu
zTaG|<0j}<z{8xb2{*#TDSF{ksV1J)5vFa=9vKvu#D at IU}JNVw#me;ELy8N{4#_FnW
zqT*9k%Pq2#QD&9*vn5$I&+N<vuY3R+9JFHl5cKt!pS{7#{;Iq+$S~WVcqdw&eKIb<
z6WZ#n)AR+)(4WQk6~MM7WG1sx7is$J5jjL360ukMsSp*r2l(IeedRJXNb}BVf!dpA
zT(jr^-3Vcn<_4W?gcNFtV$~Nlf5sJ{JZbH299&Mcc at VC}kNU<k3BNAbWvoEj8{28r
zsh$eJf=!cS%IIzR2kpCHO;UuGU0u)ywDBnn-w`vj-xvEj946xvE)0Xu4Ueg6_nJ<z
za+9i`Fyln1J&`fPU?D87<j=ZujdMMw52VH8!gm1?!Qy&!%<Q;pWHc`z;4++ZUSOKd
zLM;I{#%|@1qoRSby}&E~3S1Re9XA_dysyi0pJ&_7pRa1h;r(RJ&bm|bmnOQopXS0f
zth+V#TVsP~^2~f*fejyRldL+DqgPFgQNO40{#SFvl8Im)0zS%cdRgPf_(~>Zz#4!B
z9r_h1^^VF0N5huoY0mv5&mNaolvxUn2|yTi*A;CbcR00d5<v7B1QXOyS2zRr7rB6(
zi at 5%j{gYC>xXAKiEwJT<xYK(>4T~3{P#4_8IC;e_R&+94e(i`-qZW+*m8G8=aq??5
z(^u^g-UarLfc$<FDhs?Kx<!-bU-akerX$wd(mp>M>b6GH;4fd<g6TTbFYGUxy$g8@
zNvbdokI41o4wC`t?rv5jTXn&SQ=CifXBz0WKd*Z)U0zlcd!jr12-c%NMx;ALF22iU
z2(g8!`0<a0a}=pB{g{|+t5CG|UBXOGtNPq)FG-GTB-&0G6eYWnuwdSl9N54(nTt{T
zgY=p38KOui+tc>HKzSS9QINaBBni^M^Dj$@=7I9D^o+K-(@;1eBdiL;L?=?Wi!j;7
zT?mt|a247$Xn8YDG?Zd*dKVZ+Bnwde6lL&w7!>=~&?j<fB?$EC5;|(M=^B#6U$akU
zqJL$WD8R|JV;^((HWq~0UUzCzf|nf at s=~SrVbK_7%Sla^Q14T12q&#qx4aQ}uXG(k
zt%bZR;1ZQ}I!+;b=u0MqgE`ugM;|iReLyaraw|*0Tc$4kBD#A-xr_BY`cU`=Gp#*r
z|4_TA^+&S)<}cP%(thCfGD8f9uR8XJO7aBOj#RZB3?bMBoEXQx^skmzQOikNlp%9X
zPoin&6My18c?*B}w!9){j6__9CJi`gS}((RDxA&wyN%ds>B^W{K+}5Lh&C_`ysMI-
zcQO9gxW^Th#-=w4?JCn+b-tdL3B5rCU6`uAZABCs1QD4)`*68Flivr)-Pw%K<yGW#
zI>SNE(qwCe)aoa-YkNj1xY40DzPGTi13(XyV8*Yl9`RhpvF#5dKdkAUGpGNEpSX9_
zT+PCLlea9$R!%DI)I=AQh1mYN(_BC!n^_yhi0ux9OG%g8FIpg`(9K6N$DVfk<=>-9
zWc_0+M+vb<0Ej1Bj{qyIwcxI-wdbn?uF*SM`^LwkwEskO*8<AEA#lu(rl~Xhl7*l+
zLSAK@>7=^WEkUFhY|9#(^}A`<HpS~`p0ZuI1z-IYg6IJsomw`2dyF(%Y?+SbKbVHb
z3Tys6yykQa+UQ=mH*VmdT$pwAU4t_(RH^|L7S!tOck`PzS)`#8DNY+#tCkiv1X84L
zja_ox9-l+mbkVc4Tx6-PN9kLkZPr(eob9TZWo%Yj_ at hs;7<LB5;c;(5g%9_c_df at u
zuC at 5i2_NIGVg61B#UJ={&`rkfX5`8}>FoGd^`sG{eJfF$acSW08(@8|;LBjJWN)k!
zo3cr4?ga?fr<VyHfqy>c2QI7A_m{;UYJwRFjquUp1CDctH6Z-NuK;bj{rz|T*0+m;
zX73M}=c!kGUz%BF<H at _Y$Z-8hdFe&QCjdp%9zfdZ`c7`sZuJ5BIuE;ab0Q9W!}+>O
zC7Ti<3kwF!=Lo%nP7K!lkuCFULd!ZQF1X&JMp at Lr3RoUE1!pIo57^M%&=O_#0 at Y*M
z>s>)v9;3ZM6Qk_5nC|Kz`RKk2o=JO(YYji}?cda1Mm|6-rWwePefCE?i%BYhaxAA&
zA9nX%{YY=bPS2zBmze2!qj68_!V{(T(3v+8vGv81#mpe8;;<#Ri_&0{m`}%<56 at O>
zYGGnamt|=kR^ngf!D?A}1ZKM;0RJf$cPAEU`=|m}(cH(iO~y?;ZP at J~*8Cq;E$xSq
z!>4leQ(MY8c$RuO7se^^Le7P9TVp?QLw~4Y>(R3+FzH<Q1IwRT5Z_!p_7wiPV92)2
z%~1X3bz|z$_sQtxN_&WEDt*x_3wM42`lOfxvSFMujo%jj6{~?g at CpH5na#)Rip54+
z>;p^Un%!4d2HwioZevfXA+FxgM|i0h+b7yM$9+|858HEsGWMW>t)%9TDL}Gq$|;BR
z$vFM*uF!ztu^C1gJSNyBJk;>Ux+NuJ8~@8|BZ;?>@e*dol%sq<MXz^g at YLb1c{Nsa
z`F#}9WhDiQ(N_*EN3}zz;~iB?o*qdSv=~dS)J~J3%9#U#=88Io4s=d;f<5f*(a#sc
zaTV}_tlA8m)Ne^)@PRKqZNc?;tH<t-m9vSL+7 at 0y-C0qwxk%s04RiGT<2WYb0G}W$
z38vnD?H&Ye05S9`#?B@*E;+1z?J at j2i9Ty_*Be=<M*9dm(sb;I1XJgwzr=Tz1__wM
zZG=_<P_=M1?1jXSB`z5!5CpNDN$J at 7%nHb<-+c)=sCL`9wHD^z8$iEB@?09MhZyYt
zEmK|!y2c&OxAj)mpaqZU8^58w{@N?{1L$IbiJ~berWZA$rM8hQmZ1+lueak~N at xEx
za)UNCHlsHht{O`aYg=Dh2REUAyXHmKHfu~`Yi{v^J#QMLea+ouyvzHnw1TR7C?1B1
zkS#PBpC0>eyci`>{voL6+ZW`m_@*^wqUJu2eIa=(a8W-Pv3wUrZE%jrK`h;`HdHUl
zVarRo1vs*V?7lGDrQOykx7bMf>GC}Z)lG`6Cd6gknIITGZmGPXv3i8aOiijhlEaz~
z>rIgr4L9cI5}CIK3V7EXC5%xF<`Z$nud?wpwBma%_*?jEWVf`)Vao0RKhY%rLCWVG
z%g}X>ath=F=lXGg^~K)MMo2{!W4H>axOqBJe<Gk!^e<m>-y5>_vO at S_(chUX>tFSL
zeBb%%D_v8N1+>MR_If1BZGvW6(j*YcZGOD!fg-;hhDd<&118}?eOhb at hVvx{>IZRn
zBb$zK7Uz>@H_dZ;2vqdTc=c3#$qsv9m;Lc#rs8~-`w at 8(|17y6>15x3$YO&6{TL%4
zV7^7umS2V1j=pb8GBm}R6ar#)Q-NNf&uGAi!jOr~uI)VZxz^@5{X({ma*;h*<Xvs5
z+=L;?6PHZllI at P_nU8HgD2{0E&|&wHN9GT=7hRE0=9<Xr at _c6O1Y!v&Y8{?25L(d*
zyuY*DBV}b_8k`uT7<dphxqs;<J=jq`6TU$m4STMdF%IJDl_uH7U@%pFuC33;m~9c0
zlJ~ynj8&s1 at y==2P|F`Q(Ay|urcqe6jd>RzR1?{MEKJzH>NbMr^v7AwRAw<3^M&ly
zxhNR62S*@R^iaAQavYvrLZ64PCeqTg(39;GHo%ST1!W}en{{zr1OD2DO|5TBO7-qI
zkm2x$zKNBYS at iRQ)!c<90a1E4d#_(tc at Eh%u;a>@zbC%m9sCa|23sb*KQX-}q2!Uw
z*Hb4*Et48l`a;QxNyBrxePve#sctIY!RR~Ys+<vr6qUMSR>LIDJnC#mioyC9ISE;l
z?NAu8_L)lhD2**S>bN{D6pHLj20K)0Y6SKkd at +vbbimnlfRD_EtgQLvOB^b<@%~`!
zmy5g|C0B{;M`aeojzgN4Y4RWYPfWtmKSD(itw3};hl)5HskO*P%sgYuLybdcoN9F#
z7G=0<?Q=~|fywl^s`>RO%5TZ0b?RRM!G>$NN{Q|HyS8<~;-2jG5hwq)k at 5RY<o}N&
z_y2su4J2JI(T3E;mJB;@9NTK<Yuyn`XvLc6XL|=(7!C<V8T=__GOm4Hl4jthIRs;@
z*%18ZvYeHf2C=co-Su_Ee0vw3|NZr##V*(hhNa5>+p;$bhP?Jr4&~ji0$cJ)J|;-|
z3OU-+c3p4%Q(hVO at d0S5U*f3c+!J6wV#m+Ify$iF#a|#E4&aq*8tSf$5Xsc%jQo+!
z>6Yg^avR(00kIDfJuZ^)=ua^-#rXosM%wMPQD6;7d68t1FgNYz4rb+HQPHLwkHNtV
zgEWqHsxSSSylTuNpv(k8c)oV`X+Z42e|x<O at UtiSAxZUngrFyo!cZHYGvj!!dm`i_
z*z!d(q+75nF6j2!z{(<3d~*G(X&&@;LrQV96$(B1NbB(f!=U8Jopg(j5S<=@5>Ss|
z=A~nq*<J!UV6Wkb_r?jGQyX`KL_^<d<kO*@^zn-Cg$2?RHAG8~fB@`V(!Zsxv at D`<
z`J88z?)z6H>4Mfin7%Rr at ar1vC5kVl(nfSkSb1Nd*7c^&dt6`LCXUL6sSDCjL#^Id
zF2G|((YvmD3)rHp0cob8BqHHi5!ob=VDL`un8=tXX%|db+|mFpoo~_Qd1H57vwSaM
zF^GY!aiHI at u`S#U#0FSl)PNvhXWs&IDzM2lsnY5J$b}KP!t`oyG`G>(C*8~b;80Xl
z`+DYInDB?V1-s9r(;vqs(Q9r#jWs*StsIe>@a$0bgv42Xa=8_bD;X6m9f$figeGb?
zE%-SUa&UhLG4s7qGMmdg#*TM-dpoa-ZMMI&JWb??7Momr^@VlU$t8u!-U$Q0QV5@^
zv)97DdqFcvGgA6K6{g+0T&ssz^0>pe+lX)oy4 at n2C4J<Y9Z-L+ak_#!P|~C?g*6`W
zKJNTE8$F#p`!|9ya!cDbx*sOdG6hyQEmP*6dB%P?9I1SCKw8=e{>K5hFup;3%hwds
z+=Tnv60$taWb*s#(xjVK<YLM01{duDv(gAnSsXjDc;$n;x=Gj5BH0nn>N1Zi9pT%V
z@`vgzS9+Nn1Or7K;odFjKcF2s^M_+XY at dM<Dxbg%5Bx%mX}v&Z46a>^u4y5BRdR;F
zf47mvPe<2CKz=Q>(h3|vDC|3$>7UWcc%uKdR;x9%!4~um$}9`1{j&y>$r#__#svwm
z8?Jwc|N28hv6%#RNTaw1)4vc>IFTY8ag8%~6a=zr40eaKCVS;;q@$!qqU}03A)d#_
z3b}Tn)2;nDQ)&I`%DwmYg%YUFZXl$LZ at ***@c_gZm0bAaN at -aVV%Y
z!<*RY*ZOIBw3qzhN<*#ohOE>Kbc;EN`^XY at 52|}~Era-VwB{!3QDzw114kFgKRwJI
z%Svo2u4ox`ipS^TQ=hqOto|8q(MvELK|pg|EBDh*5*{pBbJp(xz!0Q3Pf#X_p61pY
zMmn)>qRU57ZcD*fN@*QB at uwZrWWqV<(0A*2%Py*Cq5=11{9 at h3omzXUuDPneQ5YdS
zG2xCBE^QjwD?$e6Y&hyMJb}t3xh-Jhd&kN>>Z<XGBxFDek?S*GQ9a|9V at Qmq)Zj%h
zGcOigO5~N6GL>#yxFcoM8R?F1n&LIDnK-oXZ*YZyY8c-lSQD&*p4ZBy<T!Ghfh!md
z7mmqYWd&=CM-D4-&}m0?2P9qjWk<`c18Xj*`$x;Ms=pY9l6h3h5e^xEbIQw!e&X_(
z?6c72<&HH~mU%G at C!v3Eg_Q4L;=+P<f^OzFNCqwafWz9evaN at A;R5Xeahb{-FyXO}
zuxR>V9UZBkb$DR)D9AGEg?7t8o?7%=8Jwu=u52=g1V};^JtGz~FKck at e5F48J{!XM
z-(kasDiRwkYfLR4sW8qFM5;cp!R~2UBqp?Z!kn==)?lx6utBq=L?O8-H(B)?DK?6E
zRJ3zE?00~(v;i%D;D-AHyf>xu4(?vg&r(sdYfI)eN6MZwkg`HDe;FyuxYQPO+$DCK
z(P7dF`?agfm(=j;WVjG0>iE^cwPgQ?pky)Te9lF>6ZWUl(?-th;(VGL;yWQ2eT}=w
zJk9%XC}%3aOxE{vc;f7{EzXgnTV^(;EMLo5&|iz_e;hGeoug}Cfj&oj&U7xP3v(#E
zQcLBsQ)mN3+Voq0v*bQ1XtYKQ_H$X5d`Ts4(f!4cWe2N<o%}{E-i|=jK^DeYyPZ?T
zTRl1c at Dz6Dj0$%j0&!(A?n9ywvs;(Q&ylxWTfB68a-JQJA7Hk3_yDET|JTsDxFvlr
zetfO9&W@#Xu3ULrbIWxqT|YA~Ag<YRt*LdaXkKt9cVtP5ii&_h&C1G at b(&c!P?@56
zn<GQz)<q>#!4yH|<`o14L~bGoKfZqe&-4Aj^SSYUzg}m84<b)&%$|9@%NO%q?7>Zv
zw)FP`3Ol|}U(JhC%~dp4rLTU_)f^j>m(>83B9`E+RsOE&(SV99ew-ibMNy!FiTY;{
z#lOT1ZR0jI1fx^S&byi~*R at p}Gym7IQShA$uizO*eTKC}o<w}|&c}8tF<3gZj(`r&
zd{o)>Y7i43&uau*H;vvI^81*g(^egcC{MD9zXG;M|3TU<`3maNxGubt+0JbvS#lDG
zUf+!p6zu&8$u)b!5q(4D(T{Ex>t2HLyEf+^?SWNzFfXj?j|?bMUxrQZFI?Qw0~=4F
zmgT%h+NFrLOCv*orJ*tMEsD8I>EFu6*?BGz-@!weQ0{JwX4tPGdJ^FA?1<tUkiDB=
zJnP!rNBSI!u21;7(n~s;|DmU$*`|l$YyoG#IJ$Tx398|pJBV>C%WQEY-%Inp^}jO?
z&AqvNSJ4lR-2lcYnddsSzK0UI_{Uae?FBsvzCmU#`-YL7vmkC2C6BjJHUH~2Jo(X-
zf`Q4b)E#g&KWY9Q{}Gs1te6CbTk%HY+n{-Vr}KTj1z4Qj4r|j%z3~@e6muaC);B?q
zd}xr#uE=_FyX&e#L$$jT@}8;>V!UUEF}X|1G^nNm%%isZ0SSiTiU>K9%(7&6JPKt2
zg;N%)E;yYl^uZ*u0Z7kQaH?_e_4-(%!KY>yG#5*m-nTZauWb^qjg0vBNy<V$W~iE#
z5r<0tP#@0WS9!gSlSLs3GhIU2Lnmg&b}W9KA2A?lKB={e-rza*>|sK5RR9qAC3_v-
z8=dkGf79aWusT;7<$NJ8&Fi6TW;YAmKO;$`^z-ndb=@G=7X-^)Eh3>X5+`U5HxVAD
z#5(u7F2$9xA*(myDiOw?cn{K9`*>FtX~<XB`*|+Kt7Xh)wCr1<#W*pM$nAf{xaypE
zPD8&hZ))?O-1Q<hupy+C6vynA#^~f-3)j81?Y`?vG)u1LV9e!nXx$JUMkaZo3H8!9
zV(sa=|7Z at OPl+5s)ny2(EGr7jU89YmOtX?pTLo(D_UNta6Z6bt`6aJ66UWYyv-(Ar
z3E#)arO-J|%3o<$I0xcXXp6^Xk3_|*%@h^b2;V`;ZSj6ZuzV&hqQSqwWDl&-zVx&%
zy1y}mXG9V5kn_{?#^stv_NJqi#Wss96OpkO{U<g3W15VOe&9WsUbtwq)XYtK;1LTo
zF+sL5O5xe`N#qXPpGsNc=`Z4=V%BWm{BWb3wP_+D6^F`%bK0toN8_Xgz>I*!lyL^=
zlrU9Dk^NVu*5(y!em*71XP*>vP%+e<RB!LRI-X=YK+#i%E`5#KTF_7-d13+ejXr6Y
zilBdTt$YE!hip2A<^P{n#^J|=5x0h$v#{)`W+G}jo3W_$vtE~8*{IofL+y8?n;cR1
ze%5}@&xk&^Cdyv34Ds+kiR_B}yg^HJn@(S`t(6B7VglyJz1Ab{8vMq**85`;X8#u#
zW4_>f*<H4WH+6Rj)iy{!p+iPD!S9FlQ=u7pC=IuD;YJVOj_eHUa at MVWjOIOv+~caZ
z6_YNXCtYcmWROg(_ai1kEwbNmfhsZO!lG at tyXYVpQR&Lz?DyCG(+|DVj9bRCK6)61
z at k9_<K8MUFb8xjIBjPU25M!q9 at ***@ZZ(6~JcT_8dn4Nx<~iR7S$I-G91g!Am>S2v
zufA39&Mj<v;AGvQPFe+i_u<B?yraalS|-wIp57f}a3>)D<(pt2QcGA>FX(;Tg^vS5
zgfVhR=EWFhi)CBKN=^uyt^P!;dpUlW`lljoZ-}l^@zV>W#;~MH<DN*@oTr`vr*D9g
zMQ at UM8N8=~m9}k8!~pGdtINigfFHl@*EHx$;qX6iL~6%Ib9UAGH_^TrXm!cc);MXK
za=Xg2r0PGOBT#1G#11+fQQ51||L=(X5^bO)(9-7LaV>~dy;h3mXtV$F(Bt5%tFUyF
z at 8^VRY6ov5q^@Val4aW-7J at +sUHq(;z>d?s#r5Yok1Z)v(0tg=Zy_5yEx3ga*-T#t
zhPebL=>*eOY%+30jeA;Zs8J4DT)ELh+FyEmsef4Kv+u|09*A_G6BSOY3x($E?L<Id
zkO6(<`hP$NE{(lET6P5U7<|ak6o)H$V|n14IY?1?wvbTEpLRvkRLgFpKM1NvdsbP>
zMO?#w at zxV%tcbx*5;b=$6kS}_P;tJ*D6jlZl^6nh=T)NOd&A4tGb%OTGTE`ijeF5R
zP!qi6ylK1xm6iy)K-%<Mr+4?#3C#x#-mYYML`6BI_=ZRO29pLol8(3&u%NBRo|-4E
z%0Rzco`8AxKnYs^4X(&uv+IpxY<IdNEHF}6E*<?+W{4sHPzhM`5pUM45<Or%<J&d5
zmjPK{QDU|RgjsFArZ35%xi!Z_i(THoH-78xU4#pZFS{t2YLXvp>ry;4Z<)<}2`2fw
z#CDj?w<koMs5#K&j^zAzoMiK9Ubigx4(8WH)CXlCQ$CM#KybF6Vy`L_Mm$PPGu{eJ
zhqMa0WB&`e4=<U2-S8awJEiC?D{1^<;mBv5mVZ(jBlQC>2TK8;@BGOJGCWisw7Sqk
z*Hmpl43Oak;ul~d{ZY`fBjnTxRF>erCrbC2Wq$P$L7O-#oSS*MrxA4c&VKoUK1vAh
z_M&GesyPnu8)x|RN!)M-g!&%WmFTOPFto~nT~p<L3a%l3wA%7 at LXT?p(PyUi9!SZW
zZ(n=ZeqBcry>YL4B97PeXlse_ztOsH4}QFHbL=X2{Q)dSd7%=q6U>$5hw!OEhaU;s
zm#=}=|AsttuOU?@Ywo0y-cFDaKe^D`-$^XKvIkJPI2P;P5x~DBIPMx;P~Dbzqk_al
z$UBA8p=i(j(DaMH^N4S&e at KYL98V|Jct$T&Z3Pz^$_Dn}#U9c8B~a54Ei+KKOR6Nx
z8fE(!Z=f#s$NnSinxomuneyG9C2RTYIAYj>v1&k(84`A*f#dgn(p at Nb+i!{Qk=}K<
zdgOv89_GoN4m7ngX``l=H8NDXyRT_5JRfzMN0pbx5}D1Ey$_RP>wv2xyH0vV+J~vC
zC0U8~KBnbf>U+4`d8&i2hSU)^mpo#O?*euc%B1<@na<X)Jn&hu^{Ea9=Oy8=owG0a
zyuY08AmFS9T-M~4F|5yPHw2mL6Vl~jE8u~)=RwQkHpW5ksRNK}+wjyF=OS?HvjF2-
zWfxfeO$YSH`t at 3wkH`5618W0Nj0xZP5N;YGUdGY!C1mFjHPQ<<AfDH3CzqJEvjr0M
zi|m0pz9CenKboTRXVXOXJ~D-)kPT3sy!7aocbo$3Pac0h at 97k-?glK^xZvz5GB5=F
zT9if=n(gm7k&VD>qK#m~`!m;O1SL9*H5;f~juKJ3(@Sm3gcX2BvH^)H*F*NVM;q*`
zwK%2Wo)^JU?*m#0?!*(U+1mA8A;3)5!vZ*DE at l|r-=XZ8H`hA2I?L0SM0QDlXrtb2
z1vzB#d7BI<Co4S=gKwwkzn7KKS*(V|JY*g?q?TP6;BYClM6O>e=`7t?VIP#~lvud`
z3(9W&Bmm=&h_zJ7p4KZeWNzu$>G_r(_!?K-yi0ZxI&1KE$RzSi?Ghbp#&R$+N>4|z
z*z%!BXiVq2X*!sSE$nHXG|5H?{|hhlmg!v+9nvsfH&-GUN;TVGczlDu8r3;^)4A!I
z^K;aJsq!P<ruwsl!_DFGbt6?~{#atyT|_4LM`GrS*ieNp>dO$`DF3$L3~yD<YIW_%
zC-*#S_6W#Z+ULPPoP^3U?Tqy4M5m+|l2*5;t at I?SAD#G>%=otg`knYDjC_pywnn#G
z=Kc#Q8T~b9&~KqWIbT!1>*rWfZilh9g#Ggu_J47KrqN{CQT>h6rQo{Z`g`b$uM?-|
z!aPb;S4a1Q;S+g5gq~W>mEsl8mJnEEAaC_}K(Y3tW5nr|n_`tJqg5gfmoFV~8h?-p
zZm|buPqe$Zj7ZK+R3u<Nj0b#{ZYgS;uREP*T&$ZpMWy|q<wu0?NfUIX^u65I81#8G
z<`ZK}GWW!Gh3}gn%P at +C;7o-gFM*&W^xFPL&g`=|^H}J!7IwnQSl8YjF9dfouIB#t
z#E*UFjOC$OZ7sBa at dSHxbU$t1A)lH<L*{$Wi!ZuAW*ds@$DTmfwn<@9e7-EqJj}RY
zx%nAXb+%fU5k7IY9Buy2G8sKLoB_f}l6or}l*L9Xu`?X0lXYYPGjNYFp5vhjsDkCD
zwDZ+E{vPnbcgPv{x`3`5Q?Jt+p at ***@4HtDvpq~Xt2`HZ?P?MR+fN at He<Q!m2E
zt^Luj0EPYigSh20kZ8*zuK~waaaymd%$Ly76w1SqHmyNPyZPgQ%Tvcj=Id4~#L-FB
zQso_HpCBbVI at E&;TT0T+rsyD}1#s8-GvT|X=RsLhWdFBR4pz-<xZ~0NEoZf~vFj;u
zvZyVxKg7MKh~Rh~SZ$G)d(8xX&D+I%&7b)RFDwNdf*xy+dUmDtqj!|(4CwD&@_!4l
z*u4)Yf-8*gcO-LfCHKouG7rC*824{1M`xXRJ-qOzr7j{6pC1{18tLxhr1qsQ^#|o2
zQK|G0erQ>{`6_4*7*_!(O6NRniCLShD6Ctq2BF`}%C9V#+hQtcXU<9aJHa*bEMfgf
znrEoT_F~eg$lhCqJ_RM1tB?a&a|s{dZ~GHskC8h!y$JS(E;^U0@#SK6Kcj%_HcAj*
z_yT*|t;6_zn`-RL#!R165b4$Sy7KM(w#jw{Ke~@|K${Xa{_vdiT%xnpnlM%UCT(U9
zGoo)a0XtCvk514Fz`hw-Fz*GM`@6tz3B4E0{K4?b(6HW<mK3i4Vh^5mv at S>pQ00sn
z-9_OTdFo44A5YqOx9H|>OYC-ERPO5S$+gue=;{g+^ENO{(Q12Ft>=#k8Koh?dUT>N
z4`RQbR$n~x+tU!9ODc`Y-5R+Sc_O4P<B07Qt>nh^j>z>sC<I<620j|1tweP<*G81A
z?Y^%NL9x1KV*Xxh{r6%dUgh&VFwv+<3j<SJqoSX<TWA9OO<~@RZ4c*0WEpSRHr*ai
z_n-D2#V+=fn(E6atD~RrgIae+ at 1oF(zB%t`x>;^rop5hc0%6lBmI~d^bm+n8sn`(H
zuf(vvdjwgKbsB)4jdPXvXLg+Qh?k?ls}XH6MO244Fhj{FGn>Cp1xVy?g8ta8`4g)8
zv2<$qbuDPNBe`!xq2;dwm%d;P=acUW52!X9+kZYC`;%;y*Nt2R-7oK6<HKa;!|a(q
zhJ1Vx#oPVnt}S&=MqViKLR%z}fmuNx>cZsMX-E_2qju=9?7c{%PdYZDUJ&_==@lsq
z#v;~mhMco86j|sh;zu8fp*HYu=l at mb4Ods%p0RAHcPR)6jL^gZX6<s at IKF(7C0I;r
zP<F3>paiGt=KTAkyP}6=AE1O!X<2b<X8k=1uJmo50KfldSJxyf#>$I)18DcH8TC}1
z<wmTYR--hV*m6_l6amEtM`Nxh?6#iquz{nQ)R2wh>*wfo<Ep_9%$2(zMrP&ZyZ5v!
z{XRg+NweGAO6z!|!8J*#D^IDE!;M>Bg+e**HGA4J_Z^Rp=-71zkXPJJKi3MWyG;qk
zEH+ at SUC%R}gh7;7fQ3Dwk4SG6xJB2bQWm`8T9EbZb)I7|B-}14bb!G)4tZ5Bg2BQ`
zOx`rox_yb&LR at pC*nuP|yGL=%ws^q#98LvkX2M)X_>v*GJt&@!Q~Yc*6-%*XAGm${
z=s&sH6$;r=^DoHRX6udO*A|e*2rI&Tq4=pIQl$8ZZoW=2Yt!^)G7lAjy;VgOO!pab
z+Ub_Vu0xv+e#l%b+34XMbV^>pRX1 at jBZa_O_-d^tSG}=dX&p(sDu`CY9b9~n*-mG4
z`#4*EaTfi=qrty)K#(4Nzq^)biF1X at 4kTMpTG7T{%T&Go1i&gvNqiy{^I+jP8PqUk
zX*}`9HlE|t{=J<TN&ai2z#&r0eiTaH0ZPVji(XW33u4sY1uTOagh-o8%0?(7i%p at +
zen-gcm+dYV?iR&*9jF0i)sbzN#F-xiL&zmZ9x~Nrj9W8X3|rA{I1#_dIt?OH8OD0t
z-9_Pa3cj>J2=-;YHhYEziA}Y7vwI$GT$UXREvADF=yFl`iEnMoC+%x)&i<H<Mf^s(
zJ^hB4vwD|vOP%wpET^%W{UVt}X$*Zf=r(&af)Lpdi6zbt`}s$`kNDGhjXM4&@AnLb
zVollu&iWLYhI$Nqf3;6Z{}B_R{nU1CV52ReJ8oU|<w7a^W6K*fnsgtT)TUNe$%4ZW
z$JLvSH+N&uTxz&2l!w&S0Pg}`5N88e?{|f{)p#YPFrV&g1ficWmy+hKHR|=r80#ce
zH8!{0bGkHm{omfwdqQO3LRDCQnL^u~mp0H9f*A<z+z-qoqhG~h$3A at 13AQP7KI&Jg
zNk(Ba>)5(mSxfjMe_L**WM97F7ynStlR=3BGw#;4<`c$X)N}a2sy<cBCytxn`mf#z
zI7W<OY&NYf5ziBVg<&DZl07g9EX>@pmp!;ok&{8 at m$@HO^g?8VCe=Ia{Fgy#`Ezua
z2ok9xFvnkKkmr;4td;L&Y;N}aJGd?Lbh_b59<Nn{JmboJgsc|F2ufqwMo_qEF;U8_
zcYba^4Xs0Q&t%&U%c8Gz!-WRszlFBhpZLMYEQMlhI{>=&ww^b-=6{>UGpf_RcurLN
z9FNBioAySvRrVB;BZyvqhafL88BhJYjLo|2=%+4aMZUJGOQpyDOHfDJ&tCmij59vw
z2!<J`x>*AA5P|+9nO!PC#&>3==}=?)%F;<=9ER(H=d{;Y3bq}55J at y0Do-^fi?M^8
zlyN%rNu%YI$9sf!lPHt|LN1Xi7g1ca*LZ0lxei!mQPyxp2(!7F{ou{~!6d>s(||mY
zRwof5b~jvW%zUO3Zvh%ciz?6e&MbjZ6TKnUtGL9PTGB2|q8=t(ooy}_xWek2Z8=Hg
z+zysoB9kh~<G+sGSdHmgf<dq~k?3yN6{fNcBJ85&y9C>kG;DKp?+rQxu=FhLDdl0!
zNJBdR-4L?f at wD7)EEK!61!NrDpYVC6Kk`#o$%(rB4)@Y+G%g$cBiPphW`2`-i&Muf
z6xKZe*w>JbL8qn~uVAltY!7k<DL(iZ5R<P65Be*J at d-YUUla0!4<>uN>lC`}P<<xa
zBcXgNo|^}a at hBm4uziLCZ5{s5oWu=s=t>PLCJ*>*o>WL=t~9V?{UfT$nA8o at I=dTl
zUr4(phGwQ+PWXDeww2ZE)Jm*A554Lz1VpvOu&Jx%g8W<u@@X&cXT_S_eT6pdrla#~
zrH61srDW^M&FCqETw^b at HbrM*zbn2dQ%F6Q;xn9*t(8%mZ2W{ViK`R1G6`~LrV-DT
z_p&zU6RFZ3<#XN=vA3HS>+yzzsq#Up4{8N4nMoCrV1KGZEzU-j!)-fsy?*TCwQxi7
z#oHdi2DR+2s`2F4Ag897zw@!f??nbLVsc|x!Jb#qmu at Q9ZV`{5x`qzSlb3^&)>4J7
zt-I*(CG7&?fybBRsEfJ&3<;J|Mf7BkY&wt8Gao;L1&}Q(Hgp+E=Dm!f at BD+)ukQ5z
zrPoEynXz>8Y at Tj!w#>T-UP)v7Jh-Zk?u$FYRQF5O>qw?N*>Ul?F7jCju2731k29~c
zFz?qVu81*%R==mtUks4_H$o+H|4!yU!;P?zg#Kf{k?%Y2b#6Vyn|vVNj?qzLmzSs(
z{~)qqlS%CpELAC?sEgsjOghB(@J%(_3)6ns(MAj*P6TXJmg6|nVMTe-^Q+*IJtL8u
z>C$4H&kNVyB6<0BF|VEYX*dL5`eJM^2!^xk97?>Qd>#*@Tu{hn(Eae}^a;N)z7<bo
z0tQf}1r3oPy5rt{+`KO>*_aDixDjIc%q1*C_o3R*xlz#0zhISZ2zPXcm9<GOoOZj;
z{tqHNyAO1iqW0HipoPr-x5zZ>!6NM@(bjIIzwVMki at elE-n{a0LObqd&%3xBVI5sh
z;z%NpFN&3Y9+H<6$UM4SKfiEkAv|8+xbMb%PuNQCC5T?``*JYd`a9wlobF1Et84`k
zuIT!y&WW>0?P>n-;(TT7)&ubq4QH_!&s7wEGT^UC^{w*sI)g3YHSB1ZWm0j_OuHfe
zTsm9QH;F)0F0xU%bPDUWe0%-g5H;Ntvo at 5214WE`^B&wv0|Os1x*KH0OW at _t7}lFI
z?3-(k08ILG%&nB<4$XP1U<(w~zw5gBD=G3^ymY$DcokNjGCh_Ge4I&*nHAXf70KSw
z<&VsA(~Gh+SbIOjtu?$`saj}V3e?s36lL?=J}Vnn_h%e&-Nj-Fq{19A`UvQvG>i5b
zw6D8N?=eX{0 at 6S2k?#a}M_NuZ3TdD|E+%_EUSS27<c7%53V?LfCi_c$2i|H~osN$I
zqJF<Cz|;kZ8)SwtPnx)p<SodNmK!)u2ipP1Z*q75qos;=Syp9Y7zh5?7B8<4u7DAp
zVUrLD!k)vm_Tj;n9qdgKWLIVSxWUh!EbCZj&AW{t6?82<8ou^cEnKhHg-bME3mXz*
zjAoVIsc_ag(p~Q=SJ;u6KN|elx;d!au?-i`8vy$^Irk!Pjl!;57JIk at umT~*sP)%7
zO3cfCfag0YGj^Y%4La7DG?QH|%9+896Y<ZT at gWWXpr;7o6Eo!8ZNKgPjGY45*o$0C
z&`C`P9r1d)(gf4T2;JF(wLh|LtW|p#0 at R;AJMJGdPu15Nao*`8YZB=!K8sE3HQd6F
zOK^6Ka|CZWIqP(M5 at 09)V<qoj&dg=;ez+8bN4zPmm(Gu&vR_(L(n^#|meHH^3HR%k
z?120#pN_S29@;j`!?kMWKV=W7b8WGX(RV^vyC=hO6YOYY%1g*J5T{9`jS6I~DGNS@
z!c#t0bTwd%2F3_ugsrDZ6T5B*A at IwBS$iN$axpI)$f!J5C%pdQUy)=ZZ7Q5;TlSxL
zoMXej5_EG?@Os&#RZg`rwOD#lsXAx6L*+;i_LfeE6SK~8HjKxkZjK(v;a{%qor&tV
z8EZDzow9oyAnLgoP2S*soD!iSX}TV5UJ7!Y#$U0BvtC>N=Cuh;xBTYdSX|ES_42X|
zq3h41qH$~)#?;La$&YKka{O(cLzP<Ci`*(#9xRb-0QHxqcNU~j6;I8h%!h|@)z>tp
z6P9~;mFJOkYZ<L7$Ku at GEgZ2N#9g*Y4~t?~ra at bmkt;4NzWzJDCR#Ey|EhPW-f`3R
z4HN-xl9fnTR#r(T*)S%!Q at A+<P%LYY#2f5qL^q<4Yd^Y`jFp5Xb`cQVU_w+60eh9V
zrq?-XuKT3R>|@2tb?WB>>fhCNWA6+ at 7>yg(PIGC3jKvgN^YcAz>N*jF3<oBZsikYQ
z^`L}}--Y39SW2L_QKFYijlUykHJtF`Y|dK?s@!ibJg26^NGl-&iV||QI{_96sSP16
zAa`SPDrUO;;MxJ*dOWfv5?|gh)wO-%jI2j(MwO~#j`mihSxU(5 at 2n@(orp@>bcIEn
z$f4A1HnkPzsHMe<I?HrCO<%hd%|W%GB-S?1I#FkaAzgXakfi7CVCTJsCv!%S2rfng
z=r-ke at M8MiI{-9&S{s5kY5Npk6}U5}M{Pe-GS5zO0iJzQf-Y&}Tf|nsllz-kg#fmx
zc%-LI)Rn at TC%==aYGrz40S!dhDEPs0R<pfb#IzMuC{pHgnHLm&_**obFq&;*<lPDf
z>3zb9^McLdEIJRNIEyJ~mxi~MFdU(J`PGi at lx)rz;7QK}5no<~S?+PA<<?r95~r>D
zigW9K^yzz2L-Xfbs(T9Z{^i}Y8EK&B^`{V4+uRPsqtKUn{bB>p#P`H9U&(hE{*;+d
zYh53&|1)!GaO-U((ctM5QjtZH89i=PZ_S^V=39l^vX19OEw&@tE?i`qXI^?%%^N4x
z5QOICidV;d2IdDs(r3GMUj<dH-k35hg(hHQV~JUTGT@<g;mzse{14RZ3IDZIKB4zz
zhdob1QOZ8AhNJ_M at Au~v2YlWk6%DSBel*OCne#x^EuW6xh}sVUCI~;h9bg)n+Ew>C
zbLEla9exwz6bM+JuHUW-PzWL^#YAaHL_qR)VM?N5`m*p0l!01!sXQ~%RW6&BfYHL)
zUk|ubIFFJJ{2^kfH<MBrOn&%!Vyer5v#UJTw<k847vi#JaGK*<?|w|PovB9Zhg*u~
z-4_leD9^-|G at m6hU=3hq!R5o!*rvFZ8cWMgiqfA60S}k_R$K|$8ZllmzK1xmpk(dP
z89p?9vbZJnSwp&g>1WfJ;f$671BOU5=7BQ*6r{nJZ2CvjO(Zj-40WbLEZF{s2hj-J
zqLcLi+Zp!zbXjGC$JbEo(jY;+ev3988>D at _{YFaH*lw_%GJO!qEROLQ0DkNGq7vHa
zs!xw6q*>X&U1xK)j@{!NHQ6qPU6d7+dMC8AnowjI*e*XCH1AR{v7Ju)s?cF`!e?UU
zl-8hSmT0QCE|44c6i|H#-OEFs<pD$QodbOb`x|8ID?C816j3&wCvp<A6?b7yC_A65
zpTevzVbH}AObz at 7lE^rsn>1A{h~g-mB-?Gc6%2HNZhU$s_F9-p-HRGJyL at iIymH=Z
z?pFVMJbI*X+3F=yP=#rsJtAAL{9K|GA?$Trr>$!@mQCXQ1{?NyBMkY>T!~@IVqkFH
zWUqiVf6j%5O~aVGGga5Lblp?5dVM*<<PR64y&RB{*@E`4alHAX(Pz4(aeum*&r8c$
z=Prt($)>k9O;uvH&UO_~8)iCMH9zyvt{GBywFaY|G-!ELH8Oo=>{kb{p-0#oeArn@
zCuCsE*e9o#qZIt{C5$+7$xFM1(cetgw?Z9VLa|ABvA42B2q?>u0y0dz$P at r<u!qg@
zskM+6N(6liDHh{o@(bPG67A7otx{nx at e*o5!j>ap21sSI22;$00dllTlW}AD!DMtI
zPOj~VT!e^vqdD(PX(G&jE6*=Yw?c!t%pHl at Hl+`mx6m+B@;H)AXKHiV6sHhEkJE!@
z_h at PxVK@(A36^5+R=De99CD``zqWYODZ3^D&V~EswqQ9HuT&c54_O3{NT0}AdlIW@
zbDSOFb^KMxey$t93e`xrnzC`|eq;he$TaWJDcZ~*rBF9OD0?!#OnAoWZmGS1VQCPr
zgCsnG)R=B9c`928rQ$!->IZdqwQU}Zzfdtd;F9Z>9tS;g&IdFB`j0J#OeR`SI6pMm
ze+qe)qO(@gisq9#=E#dz6T8SS!J$PP00g{-tg$@-YXBr!zj^(wt<k#<S+dwOi?*<=
z3>4g>13MRP5zzI1euvwW7#LbYouZQbE-DAh)s)Piv)xL%ZD`z4w9$w)Op1BNr$s|D
zBRRJgF+>!Z68{kJbVj%YjC~4_9<DW{iUrbwSCri=XZ`+=XYZZsSnZgr&=oHmwx>^Q
w`c3Luq8LJa_?pjiv%pprpnBz88FB_he6q~J`;+gy=Xy?jpKz at GyI+3)e|}^v$p8QV

literal 0
HcmV?d00001

diff --git a/data/random.png b/data/random.png
new file mode 100644
index 0000000000000000000000000000000000000000..7640aa052db2815aa29cae857f9cceed13774e07
GIT binary patch
literal 4891
zcmV+$6XfiPP)<h;3K|Lk000e1NJLTq003YB003YJ0ssI2ZTjGE00009a7bBm000id
z000id0mpBsWB>pF2XskIMF-vj7z8H}%l7dy000uYNkl<Zc-rM%+j1O7a;=k9)pNyw
zAOR8-B|(%($zgk?UE6x_I`)D35dWM%z#k!UL)sTz_QkOqp>T)*2?7{gW`Jo-Un>33
z-7|fu>h1wX&~A8w5e&}sr7A1y<jGT6Mf~S~{dYJ%p8d~{^OK`UzyJ`fKP-e00>9Yx
zcl%*uIF35o4 at dv>yUv3h4gz6f6`h{Mvn$i-^>!X at 4F?^qnVJ7z8VJmS*>t*L97fY~
zBNc<x{4alwy>5K(!S3VTKYX(H{=Lo6#IfOZj7a|FEeuqB=iQhxYZVbGC6C at 6{qX&F
z2Pf~Mo%iDYPz5JP-JM4dA3y&1`SZt5cDFbBkuipOoz at X8dd^K(uFLz__E;f=5G1Ac
zydVh8><X6`k3RaOv$L&2V0SS1!?V5JC%co&tK+jX0P7h#UY~(@O>X6KYR)`J>$mTY
z-(F0WQvdqV`yV|0Sg}CIQ%~-Vwm166XJ;pqsg$%5Qr{JXuGNEVrcVrXe&t^V;ntw{
zXteS1_I)LUU=~qqLSq0(NfOjxA8z3VYqv1gWI at -Qg&-m#5P<-}A~Gh3V<m(T%rP5d
zSU>;(M4bn5;i2~L?-F9`Th-?J>@K9;PkV3J#KtI>3phhf&UTrTvJgU`WUZ3*U_~0_
z{^rWP?8Ksc8`#=hcA^=|jTKyjfvWO8%ZG>-zZ4q{A()rWTIdB5=QL}f40ptYs at +#$
zEDVdBuPp}?AgPGR9S1D4Klz6-Cgw<Rj21BomG4pU30r(^_RTi)9;tQ8Hd3V<QL-oy
zg~8<fESv{6f{jXVId`wnp4S@;m8S*s-;W2OXdo<x4?=*Kodk%al#{cwzyA4$@!?_2
zhS at T*)!CmQAQA3A+I{xVUu->mDB?J0U)(5A-R9So0vlUBNB|2D#=-|k$}kAVhll6K
zM-O(k`~5yIrj)30R$Tl3*?8R5x+^j2b+7#EFp6-a#sdT_=AX at r;Q-lcsL1|e!%bvA
zy;misL3!S$bUMK&!~9 at p=f#T`dwY9v94EMoT(rywAR<yqzdhLh_T@|Mc^}-rcYkxV
zA4c;qr1YuW%#@M3A^@or5ha(f;0maKYnXW9a?X&EV~*HxHl;Z0b0O9wPgiABgvDD8
zi~gYh^y$;*pZ&vhHVeWK>E(+6x$L%-QhQ!#jMwdw5W|i)>~^FiUfp#BAqs=Z*;yC_
z%whp#IXDNm;k0>=0<_oZ4Tnm56=Ymu5DHU_D?YfmhLeXdgdk85MQ_h1ldBmK@<z#r
z43ea at w|{zZGQApT6~;#JGD-p#w`WGdb&@6!ky4Yhv%miM!}#4{Y*GXStSLhyGvvhE
zLG<9!?z7)~zP0mE7{hFq?!{%sgFFVgksXrcd_F&T{j)z0emXinznT#WWINBnh#;jp
zd3Sg*z4W#=4L9ciutEzUiJ~AFzdJlXN)a$4744M~&SP1Ej6JQpgpGc8=3j at Af#o5v
zfb^1WFF{E#1QBUZPfy2x`r|99z2nK$4+7Mu{6HAYXO~m8vrRw=391ac%Flpg9<g9H
z#%ynIzj*Q0-rimuM{JnI%A{d|jNiO`sXg!g`}ZD<HeZL)JP0XEF92T9p~XB_O)#*W
zlFUL9HoBdzQnlHd05F%}`P@^or7!@eS1_~a4+l at 5K7Ib#XL$r%=_94oT4%_}!%k<|
z^%Rwn5#>N3R3Z9hFp&o<HYN&#jnU at 6{rm4f{P4pt3}X}5j+Iney*=3f_SLJ7B!XZT
z0-Otr6>iVXa}dBhLBQFJR+p?YWIP{VUiP#OO`Ok<%D at 9&e5IDHgo{G4F~;lnA3u5W
z(X(e)Ge3;N8kV0#u^@`H=NV%Xe#kdqb7`v}CC%s82d`iILGaVNql=kOVr9XKh)AmO
zyTgm=rB0EN?fFqT7eh;7h1tYc{_OS1crx>ea%0HVvC;=eCnwX(f#=1X_zoK9l7${+
z2sjy!|MbU~QhUeKsUHM+loYMQJP1KBzq*|6CdkMwP#y~mLURtl%wZT!eE;m~ijY&)
zxI9);>&eWY%>ykZ3%<QD#1KXZZ-IaUXqjVhf!`;{sAYzXErfGb9kc|4*r5d_rjZ#D
z%9GXf0Ys8OdFiQjLS2G_M70XTa5UQdvV?%`6<AIteip at Ez3NIz{FuS);Kuea-!?Y_
z64bN?Z(7Qd^{;N}JZxg)4f^jb5HJjjT$fu$F;Az+$i^(hlg0s5!V2ahFAq8U+32Cw
ziHq_RP|=laoQT=P at oeVrACD)#pNnGLQlTeFT6+ga;{+LvVahV|ybzYp*_TWjwoI`W
zxf+AAU0_- at HY0xvn;;A)zJE5oN_F+7Vd66R2q!b&p9dW&v&6&MU%00j+`(p<&Y_{V
zKv8Li!-wDyCaSh(AyNb+$fbE;6*Q_ZBBBI6b23G4Nz5$?shYuWFWg%A_w5xe%X<Kk
zh(l-*#>yi>*@DeVj;xAiXD+RYw1-(MfLRtc8uerpMygD`nXPuoPiU(fp#ch9Us7(!
zQ64qapzVrCVv~DYnAw`=H9PU at VyoMO@@gUq*qCJ0sA at h-?!b00U at j*Y$od8#FaC3m
zO0|y<sp6Rf4X!Ndq3V`4e at r_I;o`GYyDnx2V>B$MSk#MlgANx_Xps`Mf;8BsQm%t2
ztnD!tAkCucJ2_!yA$1qVP#_y7<c&=^J)jz~EAkIJ at R;2To@|SXppqloK!=N{fjqpR
zC}m{dH#2F at Q3)v}NhwKExxQhMoPd%`Xjvk1%M}^4h at Pm`m8`>L9mkw-Xk*fOH!G>#
zM5LAWw5OF;S`mm~9Z*3emC{mb2nc3yJ@&%EVamA*N*J^v at S<r9*#14M8Wxwwk89t5
zv%eoi(ZTU}GV=*eMFvDts^i1A^J{<D at x-k|U~ygQ<^gP_U<`*Q%_VP4h!ug(#wXvr
z{MzewPo|fC5RiKmlMr)#?Vpdw_eZ1lOzPLI*>W@!8Bw&;FJ?B{^Bz3f?P{ev9tkn<
zJWtAk23E!_7AyuG at BV1Cx3|~p_KYz%kl71C9D<0XOq3L&<@|24H!qS^NhCpuQpWAg
zR0q<=7!Je!VEFv=FFJ%LTbsj<7shc~(9)<>LG-%4`&(P{FuGL{3=05CYwdYTYo&Fe
z2F{h$mkdNwX)UE%ESId1YSh#tFdOB0_a8nS_PX1njX}rbHpRW!H*Cy2jHdo|Yz*CK
z7A0-VBj81XfF*Xz6~8MRC`HEWYk$!33jPm=27rYoT}*sXrq#?Qp841NVJJbhIabkN
zoGxoc#)MH!3u?eEK!_LBa3G at ***@yR!@zV<rZlSzhvfK%FVBzOg6Tm<t>1S$_aY??G&
zA(T0cq96>I8%VSbKLk>pVP!3mjnSP90X;8S>F-D>sDgk^21 at duB{KGU%qCw7VVSb9
z^B{Yl3Bpk+kar6%#6!v#Q=yhOTg+qFa1{0j!%si|qC<FZYjfD~q6z|XNyAyFf$U_w
z2{HyzB#bGgT_yPx4n4?~%mD8C93rRIZ^xB7l{Fi32(R1Q9t?-Q?!(c>pyMSAtyOgk
zLNGHkCwEmNY$2C6CWxY`@5jcV*r at zJkzab|C6)k|bd>9)F=h}+r3iA7;Im!ksd!Lr
zB|;{PQW(WY7n7_`5~YcQtlM!E8Dmldq4a!YB_v=@kTFh?F%uM6WI{zlm|q1g03nE?
zAefw;hCz_-6mnK~Rt?mQ*hwX=VUxN?dFWUOL4fwW-e5y}y71Nl$3q_9AVir@<#L-!
zE|$F+C_anJ5(`Q-TOg^_<m~h>KYo9F_|_O^W>J}pw`9pl5s?FkSqKpDV0ZV^-~6`s
z at F6d%ez-_sU=x;dY7|%?n at U{dLAOY|0gw!X;P~+E+0nc0?VbLh&v#hU3c|JTpN_{p
zPj at 9Y`n}opbr>;RmH%9y(V|Ke!8J&OTBR)28`&@$!`s_CFTVO}Z*MP-BEzOxK)JPR
zB~?Ff_V>Se`L*tN?`>^vk2Vg%Fsu5hnY(byyl`UB&8kpSBw+3j(>lh>*(?ad_Gs3=
znxSGKsXZ?;rqk_0 at WAs19ZwSYHhY7bLArIG&E?sRw2J3qGEF5Btbj6hMqSr{biMTK
zVthI4X&J?FzNiH&4hh;MtGJQH0Z1u>`Sro;pZy^C-=mX@*{pe6)vY}!2 at xlUZ!az{
z_2$SpWr>@Alr^ljUkb}AI-s<^I6e9H)k~?p@$_<5g97XGpyZb at 2(G4+-R%eMMP96K
zpmnS)v0xU8XxQy|N&#(Kf)>W&8gWj-%(a%1fVGEDRnL_h9Di9 at z+o7UHt&7;`~OI*
zc;fixz}TGf^8$mE(r*s-zkT(xlT`h%s4YloGbIYQTlJuoAI-d|V|@RkXV0%@voKnz
z7WKvklG at Wj6l<@;#;luSK?tEx$gA=KNjqVTQ}H at k!!U7tHS-U~r%4oZ%hs+%4K!d6
z7ZfNWskOI%G9FK_`ksyr7whoRs`P`g%t!OP0)!Aq*2UJaezjB}!zi52{IjboM-*#Z
z^+BzH3R(w|lscUF*M1OcDVZ6oZC$O68B0BgZ2`==wGVcU8|g2J1}Ldm<<uOLP^`GD
zos7r{sUQMCnF^6Fl at Msf+L!&Z_?ueyyv;gTvwIphLnX_P>D-3M*Zn|XRZYU4iP*Lx
zpt2x~lCaRWoWL4LP!_R^wPk3ej<zRQrDV8)6cueg)he)92+XyeZk;w3cQWysz-&eD
zf^cp-yxoIynsjl at QLWaq6_%nz8&Fs*M(JL5)*`y+kR8C7ioC_mB%8g}RUDB#nQo9_
zv``T4$b;5X3|V`(a&SquY}T;tTrVD-z?Da#Ns_u5nJoAwEU at ByyDJTZqs?@uL%)7s
z!Y_+$`F-=n6vV<oT^m5GyTEQ9-^EIKJ+H8x-oc4ba-ovsBt(U+++7Lj-<m(#6h$oP
zrt6G}nla=RZNx47f>$(my*SvsBwc^-!Xk?C- at V7+mwB3UB|qimPiy9gWfZZN#-n<@
zO<CdE_tt|+ePMnZ-VdASRd^7 at txk4>B~ISOIcTMqLfonwHZ!Xt>jZ3T^Ki^VS4{{O
zl at eBYhg%R$w)<LX?Yh9EVL_pKL9~uwW%tu<$;Gc6s at wt%Zu+!h>2Z-sg9SKEXxT*@
zN at 5(ALW3;|uq89%3M!R}xO1YUN4;R#-n3j`aq>o%kXLwnx={$IH#QhcZ3v+Cy9Dmg
zyGolI`If1nJDbntH7iXtI86gLQad)op`oHZAGB=8^?@t<rm-S)SjY~obujVk026BV
z%iZ>)Zs~z#lCzGT;48O*-6e3XsPx(l)Cf6?tv<;g*SgQm8f{5iNJ^5aZ2t=dSF0xN
zs!>F>b2*1$07^OP;R|M98v){`lg&zds8a(;t))_V{TVr(lWoeOgQK(6`ISv;T-E$Z
zoX55AzuA8sMA81q+0^%CWq&a{Jg8dpS!<wNaWj!r>iF%Ox$h4=U1&Sj186FL^jmI0
z39f_(RXUyRwmuynfAjKduhSi0UR?(v{qng+^5$zlsh{6irc7B;FYJe7IyriEa;S>;
zt!jH_W3<=V*?qjIhaY&_lM>=i!WoN!r|*w8_V)Jry`C{9o2<P0>tU}^v|uRO)e}G%
zW{#r%aQNwOf7b!;ZjJ_?j^cG3`o7|)+v{y at -3y{{`D(Vog-e=nL=@FTlv;X__u%2f
zVYj=pF&KCr-{sM*oK7ZVOb~^a*Yh|wxOw?Y*`~_wKJ6$7mY~iYo7wgCn=q8F&2DVL
zfP8ecgLJ*N&ACEuX2TrECX8e2#-eJ{Z{czkkWtBDIz;JKWs=n$%}y{wvB$<3KaLw~
z=TV7g5cWC)*S_%FPOaiv52pv9NTRIz+|hhn4~b;b{iNP0HIRuSVOVOVJ00EeR1_tw
z%f;Q99XbwIx>PyP-Oi>OCFja^B0D^ym_1d7lO3;H9t|a>)}B<7jp6M0Vl{lUi(c>O
z-O)S<_s6HxnZJ-PoCn!(0oqtt!@naH$u8zLRc#LCq;w;5Z5XezF9%kDAf-GxKB4}g
zJK9j5M-b}qzkEsa>+iq&E}Tw|uV#J_CISx^QyJLDq$yFTEmB22F)S%Z3A3 at eURsy9
zEGpy1B!*#=E}7XF^ar%FyZ!WOZ!}UusKL&o;QaLX at J%$mR8nsCy453hYx-E8=xzE7
zhk<I74Mwe>aUKtId>bv!r&^3N8;;`cXk+{7)7|%<OvC8s(^C}(bD^~N!AHB#KK;k{
zcDILv*u;jp1rb7{nBqXA7Wm&#O1{#61GEC=U}oicy^YZ{jD9*gIiLB8<5-ZC8=D*V
z at 9ll^@%vkwVH_J{+A_tq?YN25aJzTih}uDr5K4%jPfpKg{_E58{{x)L(EOMxu^<2d
N002ovPDHLkV1m))aYg_D

literal 0
HcmV?d00001

diff --git a/data/sidebyside.png b/data/sidebyside.png
new file mode 100644
index 0000000000000000000000000000000000000000..98ea7803b39202f969f920b3fd2b4dc7e3a4ef8a
GIT binary patch
literal 3929
zcmV-f52o;mP)<h;3K|Lk000e1NJLTq003YB003YJ0ssI2ZTjGE00009a7bBm000id
z000id0mpBsWB>pF2XskIMF-vj7z8IbZu~@9000j7Nkl<Zc-rk<+j1Mpk<F7;-3<`D
zh!RMVLs=3vGa82-;mc0=VIAR!o&Avgx%~kDgJTpPKh1djvau8PgGGrF2@(`Z00g?b
z(hs=xrK-Cif#BFO#E^pM>h7$pth}7eO5uP0_xJJHY5)JeA9hX>f&oC at A0Z+l+}iln
ze#96_lc>GB`SV{#4|ZfUB9rRmyp#5OCTcc!9&WF<q970v`6w9#5fU*`BTnPw>cS{3
zU_Jc*zocO!z4u^mfA4pnK6!L+D>i9rWEm at xeYppN%I{naE2mU3v)1b5?a80N`}S4m
zZL;%8y0)%Ios-7S!`=P;XP<w*f3VlySWApCBFp3sdCXkuMlMVG#P(PsB4VY2FdU6y
z)9>N>-NUD!MmudC1ADF3?>>97cd&PP-8=1e0W4?fWO)pdC5e?wsAVcaL2&%`^!VMC
z*80n*kA8CaOba0j^})T(_Qu+2x7)eAQi>PS)T>gVOO+rS>&Fbb=nbw%@ph~EaC75X
z`@SY35lT`M8v{ToR^S@`h=&v`ox at lX2VHv>#LUcK1_LCN7&A&!O++M;iZMnA1OT8a
z36k7H?cc9b#a2`0Gk$s(CexqH-iS$!(Jm2inwkvnra~%2L at 02pz&%(s4Kn{q>0WW_
zqAU$!C0Cr<3`Jr|Ds&*1-uE$oEE`8dFk>t-vgXn&@KO$CX_8u-gqnAap92p&SCmbk
zeUAxuiag at NjsKRQ0uS^|Y{oJqguH(D;TRUYiX}Z~Sr(zNUBoIu1k5D(;})Yl<Mfy{
zDDK;wp%;gz0g;SdlS(~=%n+&flu;Tfu-iw++w*r-`e~5qoTrn|T;rlv#K$Z^a~*`a
z4$5*?vg=)3^Ro9Sppu1hcvWy&0wE$1SVc!rwn0UCfj>lmDyv6=f^?2WMQ3d&Gczk@
zAZzU;V_=b&`Ye~Ibh*a;&kYtKBL+lZ#`KbuCTla=;&}V?SCNXf$v%j|Wz(eRvjCLV
zK at iONQ^at_giDPvkUF2fJQ4(BOp?Sxq?BS-b#RG2uo3$zc`D at TpS);}l{CPd#G~%%
z>B)K5hIWkIb15+Z84ikvn{Qo2FenJ4=EepQU0-xZ!(pZOZ<Qo*Y%ND%REk*vYBZYb
z_wIqG<{TLYX|4O$*FSv!-4B2LYtfUfg>}Rm#1Xq7Fwoxr<cnW_38EkV at _py{^#rqn
z_Z#0E7!VR6fEd`>KltgFUqUNzev6GIC?1VEZ{A#-ob2xIwpwd4<Ml#l)<O&dfpIe!
zbUSBjQDaRjBXV(a(mi?GZttwEuZc+cmJel6d3OLegF*M~Y^@PRjG)<6ie(;)P0fag
zq{g({?XSN2>gnOrG)W{&pe(qUm78h`P$?bg<D;W*zWzFDHV(G8MoFTXw;#0s>%YHx
z`ZPm>)UAjAmw7UnmDc+B=;)glUq{WxqwRa6Gzqmf<IDxdRt)1!EJCu at Y8^g%_WY+`
zT=n~-IQ9Zx7X{m=<CRiD7{tbejfMiRN8wO0Gp((y9UfNFAPc|CwN5!2nAaQOFi{Ff
zjmh{y`MEJ at 6eq_QmzTZ%*yPLYIFGDY2jS8A#o6_BD~jSYl`IWOj)q$T*CsS{Gc at Gw
z^xO{upp?29^k2Pvc{7Ut_V(nWKj106hB{QYc0kz}gPD~+d;8|y^>q}6hKK-m)3B(j
zsgs at w4y}~#%xEa>20go<nS&rWdGqd1FJ1&;czSg;7>!U$afp{?sQ+fBAxEQO|LQ8(
z-5v8m2f<|>4ex=_SM5b0p3=a85kV&C(gn|&goH#fHX2bw>vDXtbOsF-XgCbCo)IT?
zG%S}v0EP-OqroacL}ZMK<9K6h>o@=T+b2(+#BrRO^j1SdX4X15es%Px7cUyjOq3WC
z$MNRf(EuW2*Fi)gVvLERX#dfpr=NY+>kr~MzEz-6DGq{glq5kI8k3G)4U?uh8j|={
zk<Jng4jnWP)<sO3^!ojmr)QUgv4TWNUh81!tWWRWk*qiff>$SJovZ8hW+OE+PP~XQ
zCQW+%!OPCsWq&ZSVnXiZNFJi_QO-FlmZhOs-lEG75hJ5Gxf~3-*F7~cA*lCXF*l!*
z&*QjMgJRY}@UB1Tk48}#hzO?liIGtfU-k#xUQdk|sm at mv8_HI}Aen8kAh_)JGc**k
z8a9*+AO%*;3e&5wqI?;eQG!>PP}0&ub3lM6A585OGS&hhD24)<nF}(4lB7b)PJA&j
zf*g7?H}i}M6}FwB9U(FR at c6IUB~;lj<imNumSsZDJ(*^4X%4SQIaUMbusV=qds%}v
zr!v4iis$hpCp3UuO4=DR0H{QBXWwuEtR at H03^+mSA~90(6iN;Qa^SIer%o~{Q%DXc
z%ep~1Od5HY2n(5y_sh#;mJ=`Clm{w(-;M>TMUG9D2WTqiGjgg>h$<Y}s_)@J92{CS
zOE)MF^(~BNEHqv+0wN&ciqWgdZon>m$Yf&fhK!QluyJQKNg&DZ`#VVY*qM;mK_4!w
z|Lh;@eDx9 at DPBHneLU%3_vwLlF9gn3jACDnx`K7PyWLg6Or49gP_n>T53p<oT_}d%
zs-m3ngN=r48nZHuDpWMuPGYTQJ3DCl!&y4=cM5J>o`4GT2?q_gVd*Q(k<Plr$doXM
z&24vN3Q!E*rM!q4;mPp at x#AM3&<mO5WhuxjYyglu*DSfn1a<B%S2(!0t|BU(<%K-y
z1;huwdJtI&68i?96;+AjUD=wQ;<LrYToj~Q%AQw7FXU(tSM4Gk`!^F5&LdtpiatO>
zB*<;I3JLmvYO at 6#K5-47)3D02e^mNGD1<}Edb!g|ta8nkV*-G~z!V3$!L`{%V5&RH
z4?v}7gi2#JBfyD{aLtnA4i at dM+-R2-gZBi=Da1;LWVwOwl1phV9)`Gs)sMcc)y)9?
zA-9XmPxn*r3x)5VCsaJg`v;5sv4-xxAN?UKyaIG>=~89|fZ!oPKW<HMcQok5Zx#=a
zL*7SF#K*<-scU;b8thVAfd}FCR~25!(5-sXb<ftYx=YCCiE5C;56B}-qIsF(3HbmH
zrBhrY_RvloHmd%pMqUfe0=`LdH-kyf>;6|3`xL<iDWerD|45|{f=#~{l57IILV$<h
zy6dQ>KQj4&EEfB?WXh|8%0WZ56~ihl%a7))EHZ~tYOPqY%wk^EAqz!4F1=qV8#9Cv
z6(N+6>x6Z&Zon4gmkx^1{BQ~;_`p1w%&Rn7b&)hYr5LxT30)H8IL$<PfT;R}K~*P)
zEN*S}Vx>4fyS!Ocb26N(%oUYrcFJ0XCyfFojXTgmRnJGgWUWHpD?I7R&MfF4Sc(yS
zR?lL<VJYyiyV$T-4pj39o?20AGpimZ at LxAXtM#O7wqQmxS<v4~Yvnc4PkR?tkUzlV
zbLhD?n#aGSXe>(y!B#vw`CaP#;P>mpwcK>FzhqTc3{>hMSWaNyeHe5X0xgw(P}zo!
zf1G{}788`hc-YDxU8QDD!A1SmYI!M_tY&H8y!~BTK?jy`4^}BWsPv=@Y|A&XfGct2
za?(*sq32{u+-q2>=g(atax}ZL6>t05R*<bGI3p^$B&%R%rBtR1L)OfSn>xvnm^aTd
z+qW_gds!(~3W^H|6hO>MDWzCVXsD>5aw=)BQ)|r3N-^^snX5PsMI>P8APB-R2!bGp
zbEkc(mrukIyO(_H*;x&xR1j#bGw0NWNC4J42*OYYVGzXQu5^W_9<^Il9KC7^i@~gP
z5GbuPULLZgZF;_J0D%Vm{_CToI8BdE&#vajq4Ghg<BW=xR>`$E$&CcF()#51_03?g
z(P&KN3xmPn^{b;eO^-U~SJ at +3mVnpEqauSO(*`96`Lfpf^!WH at aI?{9*kduw!5HqI
zo&E9aKSYh@`E_qFiaEDO7j-%6W&tALW-z!oJ8y4qPfyTr_pFnr;TAhKj=`Us!QkTT
zti64YP&^egZZs*zm at takd;7!DC=4S8t%X6L6zm-;P}LH(itf@~Lai{ozq$GN@#83p
z($qY7xOZcrq5Nu}FUhk%Mk@^NZ*Dw!{J7C*^!q&vgVH44*xvr)m%n=Q`SVY<x7MRD
zF~*qHxo*v7b8~&YHyl3y#V;Q}|Ki{-Xjp5t?r(2jzI$hku}Dx5gb#KfrfIsfwXq&W
zLL#f74deDW=`c=)so8qa-d1XNbE6f7E2CkyQDTwno14 at aHMJW$E2WaA{hQ%&l4!*)
z18Lj+Qte)pG)K8#qKJqQNsUR2L5$-hQH-($^lQa~T3uzG1(=mmovU7)rdoybB2LTz
zQIRA`u9LW;e8urfakav7+*_{d9=F2*Gl(djv^B}Eao(+Pd7T~zhn+#=W-Eiy$e8&l
zD4lKnHp?c0yjrI?RdT(dbH+5YPK7!62|iCKFOYZzz!;Al_W|Zvujp*&g&Y74*YUO7
zk>=`GerWUOId|Rze}<2BE9(Q9^+GOKF<Tud{F;V4bM}t7^F!K;%Ysjk@`kH)<{alL
z`A3Dw{3y`xa$^CD_$&lRzypPGXwho1aD`kbTL;urRsGD##S-YD#TX))NAPME!PmQ{
zMI+?7LJnhQsfv*I(ZVjOs_V<gf$MnsW6yBHAd at 6yL<KsCq96)&k}!aZ%({1LOL8HK
z;wzyf-dH8oQ{|HJOgAbO1fkMu{9m+;-3-0{a1YJq$=j3RC_Xwnzv>TWn%s(q6`aC3
zAS+(nnOQmUDVP!aZ*T(!7AIBeJ%q`|Vko6LryXv#8k?Is3>l>N|Km42y!r0iZ{w at W
z(_Vitis!vVknh)MS(7^9sWkUkB(R)hb;X6KWWfxn6>KSBTr)__7&KeFv)_Jp*xcCE
zAl=$|IO?9CzImNoU2CPbnhl|nKkuHSxS_JzDhE{T-ZFzwDQA+|SP+l>obNO;;g69d
zX>4t_pB?TU99$*o-#cBM4o4J(;iJR7PoMwnV6VO2N=@o$gDI6d!}C945kI&X-l0OR
z;atFZ5fL4R&5g~gIQ`p6=b|^zlBNWuHnukI-+S`x at X`IPI8BW)i+GAYbS$@prYvcs
n&6a^Q(ce4Wi{9Yn`Ncl~qzWrgDPern00000NkvXXu0mjfvow81

literal 0
HcmV?d00001

diff --git a/data/tiling.png b/data/tiling.png
new file mode 100644
index 0000000000000000000000000000000000000000..dd3e02c0fb4c6844ae7a9efc1a2aaa82169d8019
GIT binary patch
literal 5620
zcmV<Q6$|Q#P)<h;3K|Lk000e1NJLTq003YB003YJ0ssI2ZTjGE00009a7bBm000id
z000id0mpBsWB>pF2XskIMF-vj7z8LDtJc8!000$}Nkl<Zc-rk<S#uo6k<QGj>Yf7w
zU`PN250eB<kqU44l=WcmI>Pi1**~{GVE at C43|oGYEx+vAD?8Q%2w*US0We3;^ijDF
zeN}f?&omCntI$FWF@)*)Ix8zHGb{6}68`JI{d+JvoB!vR%i$md)QAX;e;5D&@N0Yi
zoBd&}ISSpKz0H66se6ByeIIlr!}DP at pJ}(<-hI&D=(<WVGk+%)gv`LK-Bu6<;p9RK
z$w+ef=RZYGE84!l|8W0T-+%UGdn?dUr1>sp#C&-J1y$eq&8RY!iio5XgVVtu|M11p
z at HE_g6m>SFKOD4nAM8DR_~N6F9zNdR>2*S_HS=9+2O5l=*FAYx*2gwj001B%l;ik*
zpyxB3UOssKeRp?928jFJ?yp`x+kd=&HJzP}$B1}0Q^$9wAig8BsxxX%El8>3)3f8t
ziInn_=TE+O at ***@6>&VC3n>)SE*?2s>ng~JH^3>my3%yedvZ+2+(8bJ~`a!?jez4hl
zv2#xX05gP<4zxx at AxI#t(GNGUf;-nR-jN3D)+_=M5g`#0A~1wn`%xqT0GK1zS~DOZ
zA|kA^ATEH~fB#Lo*ws=sc|QFXCc{rguUSW0%Q_RN4K;@DQX^#m04!;%q&>8H8Z`dq
z%6GZe7nw4!Ra~z1W>^*$c!dw7%KN^{KbD0fkug&&8n#yFSFn+Ds9F=RjY+uXT`>+e
zh;wDzY_je#(N0-MRQlroTTn>{GBcalh8VEu-<xO*ulXt75zbvjgwk?hs|5jKX2IWW
zGb$=h#;U>cx-A5HuE{iz*@$br(hs5W2(QnSvGOFNJwDdFz4)z_c^Yy$=5+AJXH at oz
z_+2)j+y`OqgG|k`Ip5_uuV#;oP>E1ASryhr0tNtPw3-fMH3pUK1)G-$a8=X;#*%f$
zrXtN4N<>702+ at poYy?;=T7CXP)|wFji3$&`625 at N44QR}faynE8LTa6=SeYZ4Y>@N
znt8?Cm_US74NWp11)`8rDV6D`T*HY4w=H(9HFJmnLP#QFbL6l-bwNO_br=Q=AcP<i
z>&hi%*cc(=0BkZebI9pGMbnI(G$K(L_~Wy)!TH!$?TFKJw)<iP<+$Bm4*(_?V}H5S
zmFcgmm&KDy2+DEWy&eEeFUJ0Ixib4VEh(E^a2&T|mjNvsBO5}i)!x|NMoPmu8VZt9
z&ZpDAeEEmJeDzg1lU+9xgt+tY(d(anf&hQ{)0bz*A0pOVS`Kv!9{?)|!{ZN0&8|V(
z%nXP&8MKZ+TASx*2)hp-fBeZOC<Rh+iNzKa`2O(Z<YF+`+uQ4QI}BWL-WAg!TzKAi
zIO at 2qjue`CJQ$1zr#rj5oo<JjR}^3B5H4bbo!!nx5ut8zA}%~{JQ{UcsSIbS44vXA
zYBEX#!F35$yDbE9z86a!95Y8+ at 9gZndGqG^!Sg5#*%Yv%BN9SNd3<>IySH!McI$C}
z%MU|I)W5&;>o;$nKYt!YA?wNz3k516RSm*#-aLP9$iQ_at_ngFN}~QwDnnS5p|Zs!
zN=NbTt=n!r>2Lc{=t!yK&IQI%3}ctX4BY8<4_>@@_3`V;eC`LqisGvfLOCkX+G(`}
z(uV6S1rb4~(>XX;iNIeE0?|gxS%yRe?M~<5#fw+3Ur%NR0yabt0x{Cs$b*U&NC<uq
z9$#Et&E|2)w|WB-q?B`beleO(yRI8VQI_%`!ZIu%*qxUkSwvt{hMOUzJ_P}mVR(Fb
zbv2t)Rs^d=zyx7zB5-lDngs?#A;iL)AH9FS at Poge4ld>%rN~w76Oj;dbb4|*ow|<0
zkRW&|!rzJrrQ|10dB{M}0DwsKGFTKuB!nDh2$fO%Z7{f)d4#6hEv)$}Lb)E4$xTE`
zslmzR=kMMr$2pr!Jm1Gki-U{q&G(nH$wcn$#e+~vot|9&{@pw2I70)WHep2c{pEZz
zQG0u_9;8xN>trY)1StZgG7L^Gf1e`EQv_^=pqbIwbjea?4Gat{2zxEJC1rJgQBu%S
zATO7Wl!%xZCj$e^BEkv<Ed|1Isie$=<8?BCO$HMo8^uP;byEavh+ws#I2#UvptrU4
z=`Viy?Afy*2qGP=N`Hu?RL4h$pTB$8A|e1^YyWl#q1HhVY~B<B0ixT<fB at R=g8-OW
zYwf!3!zWLkzkE5HdqEJaC^QN|N;!TQD#y_}N)V#RhJZD3u!O)CgfLjKoogh+H4&iB
zf)Yb!)=@Z{&)=Vot~{^c|GBue6C{;78jOaM=|;O1X&rY=SZf`Hv$>Ze)FiVcNEHw`
zZoK3O!_n2;OQINCnj<8{8X3w6);L&3C at ZKGp;)sYgjb$7p3X!PLa>@EB9T<;YVOUK
zzUwIFyrRXL{UAsXY;DLGNf1e;F6Z9d&k!(22!pG+H=fNzJV~}(kw^$7Yh|z^RARAI
z>S{hWWGHntY*jKu5J-YZVEQSRt9)r2GHErIDj|p%BM=f9UYa2<2vG8qBIKopxV(pg
zP#_W!mC9IX1ZgBfB&!Sn6@<KclOqr&QrMQEtSPo2#&5-Vbe2+e{8`eCtkid6EmQIg
zn)NO=-;wl~5G?@lUJa>Gt3%r>uto+<5z4t(US~s0vm{LZRp+E at n~`Pf#Bzz&C{`k%
zy=-f07_qi!T^6QVovS1aMH$$#Akf+<Gg_v|g=fq(s8Ex};yc&3eX!7FyjE|#j8HXE
zyk_eO^VUpmJ}au373HC|hb^Jn&nOlw0qlzt?S0O2H3{oE4HX2oO?ujnTGzm>$ObE9
zs0U%gKp25(#na7uhG;GJ0Af=kvM$F)2*t1SjXR2UN~F3cn&`fE4|2^PF0T83Ooz}i
z-l7k>Z8!JZ-%YcQK;8-ui=E3G82~r5!TN>`<8{`|HLbs#f?dNd45!a{b5pt%H)%bU
zfSV&&AC-lj7FwcIo&|Abxw287!y-QtZ4+6ciIu;KHW|!X4p)M%iNMBhx%?uwHFvR?
z8Wa$)Sd-2Y2_h1L1d)h00>xE;d6F(ji1>lhl*Ikn7=(xr0rG8Dn#RVYNg;@+lA~K>
zu=duH*HjT8MG!FzB4S+pPcsJ2w!6tFaHS8zRNsgwl~j%+l at dycgz;&sNt2LD2`Q5_
zpYsiblqrIvl8vHucnN|sijD??%48 at Y6moJBQYs;oQI!K=AVQ_2<2Xt=(g{Rjgv<a5
zqb~UiFqT0`M2n{}DvD`F>@B?Gqr)JIj?P9`HT7V#CVh5tyj*zPZe_ceh39=ZJPg9<
zXgIpe5fCd1!UW;NV&V1Lt!x=AJnus+!!VbDZ3sj}F at opyS}j0821EnlES7<?IpmlT
zfm}p5UV0w4TBf5w(}Fl|T_BzhN56afncHd)CsWV&$ylIR+#to9%;mzn7>#!NeN1-n
zI3A5Yf0rQ4eV^(p$}z%X;a!YIyZwH=t1TgvWUy`s7Ypy=e6)M7AHRx>QH&;2&kwL*
zVCBdV%P>A4-S77qFgC6d{e at X;$93=T?=O5`ISv7AIF2I(7L)vPMTKF*b?$9$K7IPs
zb=@e^_aEd4UB^)df{l01z|dWZV9H?QT`@CkxX%3yLF at Yu_PrFLQ<MSfW$15iK701G
z-EPh1v$79j<|qt$+x=HR`pMImub$l7?zwKDBdxg+^9G^aZf|XDOqa`-Km5^?k6wN6
z-u6bz4WpYO{4haq-SCz&Toa+w>E7%2uP!gO)@220t(D{K?C(dK_qKW)u4_<hYSI=?
zHnISyb+lOei%4(p?g=6Gwl+6h$K-;nJJ(`Gu*gtPBVHu~H%_N~=83n6v=&5}f-oZ`
z5|S7Cr&rSv%^Pj4QYxC(k?;GF)=YvC2Un935 at X|B4?#yJ0uP$YU`N2g)nr6;ErfW*
z4klASjJmEslifi?f$yK6o(#^%%-kriHR8H*-A=EE0L$6TUoN9aGc*Q4K&T*S&CJbD
zUEB$R+iv%^`(6+x&9y2&=)eB>#eaYG6?3!PpR-I9cOO0a_-8*yfIolv$Ft+3C_9n&
zEkOVPLfn1y_y?c-TuQl$A2c4E?(OY$I^6~<H(~dj4 at cd0t0M(7kIzoWr>8r+yX|i0
z+lSC{+X9_-OOnVoE;&b$86vHBc6Q&q`Ay8M(X3ZESP~?q`fzyoySJaY?e?SX%^-{<
zQGe(DuYdFA`Lo+0r0kw=7~$demLEor6q*wrL(cACX6BS1^!nrJeC`JUSc`g`>|&JT
zgj&0;mO$(}j!zK*wmaQ}gLMe$R-+c7BtuQbqaXvVL})S!!mi^e5fPG=AC&K?{V+Va
zyqe5Cqp?~(JV%0*;~ZUFj%Ks2<A&);>3G{yM6eSeNC>5zqw(cvI`6tB!gXXw5N2K1
z4Rv!FatkUWaN%7t3vwyD$2)reeh~!!GZ<bL_F`rB8WIU9hbPCElbL(Z(Q!1)_(2K6
zoazsFBE|?gKL`;j2<v1Ja(HrlIh|$vpzFy{M&L?4DA%P>$~iqgiMct$Y!`#p<R`%o
zmVTKZbbR^wySD{|>i#D;6%734Y<eXh>>>dGDMy{A{Gj2qh)~_|AOc|ES7o?JWGEq6
z;u->Cuw2e2S8{I`5t+5o+(l{Ko)A&D<vLO#LXrQ^#bOmMi1c!iadWcWtjG~+nYeLR
zb|FwN7fOmE0*jIidE2;D?xF>uUN{B<=c8~98LSC700J#2mm#XFNo%cxFz9V>efrCP
zPM9 at OR6yh^vqpY6I{N(GTbB?KqDTipJ%YtalT_-%;o;}+-nuEfCkXuB)@A{r_Vi=I
z?#U5i8N#r)z5VGg{$&k6$cg~K%w{>#?9D at z@`DauzMRcHKMb)xxgsHyqx>jRj;mS6
zBw4MaRS3oTPY}Y;aa at iV3hbW88M_CojV~(#>zJID at q-RtzMOfUAA~E4?j(fcIDQy8
zjvGgIT+!9Qgf1P<=HAh0G?_2ZaBn5XGm%hA9S%pM>2#yj(wgI7p|#dgIGuY(qw{GY
z29<qS%!)ib8x5z^UaO at w6CxpLt#uR`GL%b727*vZRuE8Y%~3e>yu;!7#PbXUEb+bt
z38|c;Y!u8nqoSms+>kW~VKA95#<Q5+Q#heiD!E?G7oH!)cgB<urY1M1MnO`kiRUf+
zprvwt5CA|~hROlBT7>j1%t07TJg<aMI_E(olnN$u&+~(XA5<k!L8ZG8b6NyqrI?Kd
zG*bKw=2|q`0T}{iT?sBU4Pu5-OkS}NHDl&VOfs^RYtvnVs7HX62!;#>%c;^>lXYDw
zN{Bybxkw<*oCu3aT#>wFBG|N?9Ah!ezlxABqe?Plji{LTa{~mMoc35GR}xClBw%py
z<a&cvdKsbAqr^275wm at Zb-W4$yb(enIIrof0^IbZ_CK&^o+pa8L|F4xS!)KBzNaPK
zy1S9C;iS}Z(RuxGdbF(_Y}&-9n_CIO*FAgx7k(sKj;N>q&9+TA-e~@BhR{Ttyslul
z`cU6Gc_^ch-1csV+g}UExAs(D1A?qmB4Yl>I`Ie=q9s~_lwm+v;fJ6F7FRMG!FFC4
z?J?R0hfwzj*l4a)94_A6PuxBZ;`P6Z<+Xf65??*3S6X#lyu`wCSi|oBi{H!)q-=v+
zKZg}Qf8nF7je(ZQFEC?mf2=;JoS0P-JXx_-BqAY%aSKC{xPT_JLXe<RGLo`;L_)nW
zi36CPNlEJgBm~+KL`v;R*gaN1pU8le-+d9E#m!`(REC;UYX(Ot<wvbJ4h6tSD3wx<
zqm)uAD4zB#OkaHBSeRWTPL6iQ{2-;2l+vsRBo2r3nzV?YA at dcCNKz{0I8r%E1xdlQ
zc&SH*kZ_dZ?ML3rB&now9pxw)s2Bmcde>Tk<&?ssNo|w)v>^h5H=lnvJPe}f at N6{6
zk3$vdPnZfJ#o2Mn%}K4yi}^u1dY_aU^3h{vK}J=3kRc?WqL;FJ;$j7vCozg=Q4mQ=
zd3Jof at ***@1&qUXh<(1*kG^hlPm(6LY#FCc);2j%eyX*?SJ_U(VTt at inJ=J^3(Z5k6R
zbm4gyqw}49Ki<C+;dnIq?Yqx1gcZ~iL;%DbAvr-q<I%7vL+y=?@xT|};^KU?)89^H
zKpYQ8zkO at UfGf^prZU6`XxXgB><-6uclIAHecy3hLg+XuX4ceDDw66@*D=^VTE`5d
z8U(Ohq*_8q`9T$g`qFQL(0lqU=Lgjw)ZUNLb=1Ah-m|AqTdmf-mLJsbzy9%0o_+M{
zQGaX0bwaIm<2!-d?e^wIZ?;^%`r(hCe)RF<7$LgGrMc~PdvjxBwp_mY(T|_Ldj0r@
zGE at +*BSWXVnjfT``+E<fDB4Z<L5;4J&iFygAY4Xz>;7(Eh~3Rz*L70Izdi at S0>VyT
zh`r5T*L51oP(`?xBQ%1@%sgP8E at FOAx#Wrf%uzI7ERVxb3bN&{SkpUUX4cG+)}huA
z;Bgp=3OyLWdJjla05cIVK|n4kp?GkygcY~WBdx=T5yMypZjg&-qd+1d#BeeTqDTtI
z<OikkfjJDrX&9^^u-CjYzRV^*ehITMv{G}pX5)($gdn-rq+Iwh at 4T{RopBzAi41%#
z1;vSr=lfdcr=TQObKf{Huh{k0A3DP1uB#gL@`_zV0RgaBe!?aQMq54uXtY9Oa#?&2
zFqP`-vfO7(*}1hFA6~!P!CPPJnQP}J=NL`5(xAGLKAGKxT#8~gqBu6YG`#laEv(&D
z!cDK8=4&EwO-+_plrL7)r0=34^X>n!Tz4z&=5wub1lnsfO$zO+&4RH3g6$ZzRjSpP
z$%mDqhh(h*IN!mGYzMz`L0N-P!x^dxW?UI$9j4jCVputCTqC}9H6`blFwP7U1?eyZ
z%|c1#y2^EA7*gG3GBvMkcv)UvQRJo;YP~fN8s4Ul_RPZC)yQfCN;yIb)|%6+sN}|j
zeQdV}r-P**9FEQt!dmrog;_K!<|l;{|Le2^>BC%uzd}KFdUCmdQxTolX9#&CTZrM=
zkUHJgW=}c}A;^b6`;?Z8KYZ~;Fu6LL%`;XR7o#NF=VYDn at amMMe)U#<lXP`$D~gME
zp4Z=gZksKW at 6OCxW2Z~I`#T2*?afUIAiKK{{EPFmlMmr!Duvi;x3X2*AebUsUB&A0
zVvT}Up2}ccX=iMnkKzXFxp<5+(U0aZYHjv*4i5I8Je~yM-_Orw<S#)g=X=lhU%vXm
zqy3$YZlt4{YcN+|+1T)Z#KMjI|C)s7TFtF%BrnV?9jD#foCM)t2g8fGCpn6Mgy?Pc
z?rlH&{);F5tssiD*4N1to5+FJmG#!|x>0I}KmZcp at 5A$px%dA3;(q~#LuX2fffuR(
O0000<MNUMnLSTZaONc!H

literal 0
HcmV?d00001

--
1.8.3.1
Pekka Paalanen
2014-04-25 10:13:30 UTC
Permalink
On Mon, 17 Mar 2014 15:29:56 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - squash Makefile to this patch
>
> Changes for v3 and v4
> - nothing. Version number aligned to the first patch
>
> data/Makefile.am | 14 +++++++++++++-
> data/background.png | Bin 0 -> 245579 bytes

You could use a simpler and smaller placeholder background, I guess.

> data/fullscreen.png | Bin 0 -> 3406 bytes
> data/home.png | Bin 0 -> 4629 bytes
> data/icon_ivi_clickdot.png | Bin 0 -> 39523 bytes
> data/icon_ivi_flower.png | Bin 0 -> 24475 bytes
> data/icon_ivi_simple-egl.png | Bin 0 -> 29316 bytes
> data/icon_ivi_simple-shm.png | Bin 0 -> 71120 bytes
> data/icon_ivi_smoke.png | Bin 0 -> 46577 bytes

These icons seems to be pretty big...

> data/panel.png | Bin 0 -> 41955 bytes
> data/random.png | Bin 0 -> 4891 bytes
> data/sidebyside.png | Bin 0 -> 3929 bytes
> data/tiling.png | Bin 0 -> 5620 bytes
> 13 files changed, 13 insertions(+), 1 deletion(-)
> create mode 100644 data/background.png
> create mode 100644 data/fullscreen.png
> create mode 100644 data/home.png
> create mode 100644 data/icon_ivi_clickdot.png
> create mode 100644 data/icon_ivi_flower.png
> create mode 100644 data/icon_ivi_simple-egl.png
> create mode 100644 data/icon_ivi_simple-shm.png
> create mode 100644 data/icon_ivi_smoke.png
> create mode 100644 data/panel.png
> create mode 100644 data/random.png
> create mode 100644 data/sidebyside.png
> create mode 100644 data/tiling.png
>
> diff --git a/data/Makefile.am b/data/Makefile.am
> index a7cc944..2aa6e5c 100644
> --- a/data/Makefile.am
> +++ b/data/Makefile.am
> @@ -9,7 +9,19 @@ dist_westondata_DATA = \
> icon_window.png \
> sign_close.png \
> sign_maximize.png \
> - sign_minimize.png
> + sign_minimize.png \
> + background.png \
> + tiling.png \
> + fullscreen.png \
> + panel.png \
> + random.png \
> + sidebyside.png \
> + home.png \
> + icon_ivi_clickdot.png \
> + icon_ivi_flower.png \
> + icon_ivi_simple-egl.png \
> + icon_ivi_simple-shm.png \
> + icon_ivi_smoke.png
>
> if HAVE_RSVG_CONVERT
> wayland_icon_png = wayland.png
> diff --git a/data/background.png b/data/background.png
> new file mode 100644
> index 0000000000000000000000000000000000000000..60c317c945ae3a8c9f0875cc59a80fd248692fac
> GIT binary patch
> literal 245579

Hi,

posting binary patches to the mailing list is slightly useless, because
the content cannot really be reviewed by just reading the email. It is
very good, that you separated this into a patch of its own.

In the future, I would suggest you skip sending this patch to the
mailing list or remove all the binary stuff and leave just the plain
text part like I did in this reply, and publish a git branch with the
complete series.

Another benefit of a git branch is that we can easily see your
branching point, when coming back to it much later.


Thanks,
pq
Nobuhiko Tanibata
2014-03-17 06:31:09 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2:
- squash Makefile to this patch

Changes for v3 and v4
- nothing. Version number aligned to the first patch

ivi-shell/Makefile.am | 12 ++++++++
ivi-shell/weston.ini.in | 79 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 91 insertions(+)
create mode 100644 ivi-shell/weston.ini.in

diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
index afaa5e3..333abb7 100644
--- a/ivi-shell/Makefile.am
+++ b/ivi-shell/Makefile.am
@@ -67,3 +67,15 @@ CLEANFILES = $(BUILT_SOURCES)

wayland_protocoldir = $(top_srcdir)/protocol
include $(top_srcdir)/wayland-scanner.mk
+
+
+weston.ini : $(srcdir)/weston.ini.in
+ $(AM_V_GEN)$(SED) \
+ -e 's|@bindir[@]|$(bindir)|g' \
+ -e 's|@abs_top_builddir[@]|$(abs_top_builddir)|g' \
+ -e 's|@libexecdir[@]|$(libexecdir)|g' \
+ $< > $@
+
+all-local : weston.ini
+
+CLEANFILES += weston.ini
diff --git a/ivi-shell/weston.ini.in b/ivi-shell/weston.ini.in
new file mode 100644
index 0000000..c9a6861
--- /dev/null
+++ b/ivi-shell/weston.ini.in
@@ -0,0 +1,79 @@
+[core]
+shell=ivi-shell.so
+modules=hmi-controller.so
+
+[ivi-shell]
+cursor-theme=default
+cursor-size=32
+
+base-layer-id=1000
+workspace-background-layer-id=2000
+workspace-layer-id=3000
+application-layer-id=4000
+
+background-image=@abs_top_builddir@/data/background.png
+background-id=1001
+panel-image=@abs_top_builddir@/data/panel.png
+panel-id=1002
+tiling-image=@abs_top_builddir@/data/tiling.png
+tiling-id=1003
+sidebyside-image=@abs_top_builddir@/data/sidebyside.png
+sidebyside-id=1004
+fullscreen-image=@abs_top_builddir@/data/fullscreen.png
+fullscreen-id=1005
+random-image=@abs_top_builddir@/data/random.png
+random-id=1006
+home-image=@abs_top_builddir@/data/home.png
+home-id=1007
+workspace-background-color=0x99000000
+workspace-background-id=2001
+
+[ivi-launcher]
+workspace-id=0
+icon=@abs_top_builddir@/data/icon_ivi_flower.png
+path=@abs_top_builddir@/clients/weston-flower-ivi
+
+[ivi-launcher]
+workspace-id=0
+icon=@abs_top_builddir@/data/icon_ivi_clickdot.png
+path=@abs_top_builddir@/clients/weston-clickdot-ivi
+
+[ivi-launcher]
+workspace-id=1
+icon=@abs_top_builddir@/data/icon_ivi_simple-egl.png
+path=@abs_top_builddir@/clients/weston-simple-egl-ivi
+
+[ivi-launcher]
+workspace-id=1
+icon=@abs_top_builddir@/data/icon_ivi_simple-shm.png
+path=@abs_top_builddir@/clients/weston-simple-shm-ivi
+
+[ivi-launcher]
+workspace-id=2
+icon=@abs_top_builddir@/data/icon_ivi_smoke.png
+path=@abs_top_builddir@/clients/weston-smoke-ivi
+
+[ivi-launcher]
+workspace-id=3
+icon=@abs_top_builddir@/data/icon_ivi_flower.png
+path=@abs_top_builddir@/clients/weston-flower-ivi
+
+[ivi-launcher]
+workspace-id=3
+icon=@abs_top_builddir@/data/icon_ivi_clickdot.png
+path=@abs_top_builddir@/clients/weston-clickdot-ivi
+
+[ivi-launcher]
+workspace-id=3
+icon=@abs_top_builddir@/data/icon_ivi_simple-egl.png
+path=@abs_top_builddir@/clients/weston-simple-egl-ivi
+
+[ivi-launcher]
+workspace-id=3
+icon=@abs_top_builddir@/data/icon_ivi_simple-shm.png
+path=@abs_top_builddir@/clients/weston-simple-shm-ivi
+
+[ivi-launcher]
+workspace-id=3
+icon=@abs_top_builddir@/data/icon_ivi_smoke.png
+path=@abs_top_builddir@/clients/weston-smoke-ivi
--
1.8.3.1
Pekka Paalanen
2014-04-25 10:41:42 UTC
Permalink
On Mon, 17 Mar 2014 15:31:09 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2:
> - squash Makefile to this patch
>
> Changes for v3 and v4
> - nothing. Version number aligned to the first patch
>
> ivi-shell/Makefile.am | 12 ++++++++
> ivi-shell/weston.ini.in | 79 +++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 91 insertions(+)
> create mode 100644 ivi-shell/weston.ini.in
>
> diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
> index afaa5e3..333abb7 100644
> --- a/ivi-shell/Makefile.am
> +++ b/ivi-shell/Makefile.am
> @@ -67,3 +67,15 @@ CLEANFILES = $(BUILT_SOURCES)
>
> wayland_protocoldir = $(top_srcdir)/protocol
> include $(top_srcdir)/wayland-scanner.mk
> +
> +
> +weston.ini : $(srcdir)/weston.ini.in
> + $(AM_V_GEN)$(SED) \
> + -e 's|@bindir[@]|$(bindir)|g' \
> + -e 's|@abs_top_builddir[@]|$(abs_top_builddir)|g' \
> + -e 's|@libexecdir[@]|$(libexecdir)|g' \
> + $< > $@
> +
> +all-local : weston.ini
> +
> +CLEANFILES += weston.ini
> diff --git a/ivi-shell/weston.ini.in b/ivi-shell/weston.ini.in
> new file mode 100644
> index 0000000..c9a6861
> --- /dev/null
> +++ b/ivi-shell/weston.ini.in
> @@ -0,0 +1,79 @@
> +[core]
> +shell=ivi-shell.so
> +modules=hmi-controller.so

Ooh, I see, this is how you get hmi-controller.so loaded.

Since both ivi-shell.so and hmi-controller.so both link to
libweston-layout.la at build time and both are dlopen'd at runtime, what
guarantees that both use the same instance of the global 'ivilayout'
defined in weston-layout.c?

My knowledge of runtime dynamic linking is a bit weak, but
personally I'd just avoid that global there. It is a bit much of magic.

AFAICS, you might be implicitly depending on the loading order of
ivi-shell.so first, hmi-controller.so next. Weston does do it that way,
but I'd hope the dependency was more obvious than both secretly using
the same global in a yet third library.

What happens, if hmi-controller.so is loaded, but shell is not
ivi-shell.so?

What happens, if ivi-shell.so is the shell, but hmi-controller.so is
not loaded?

Would it be better if ivi-shell.so loaded the whatever hmi-controller
plugin that is appropriate? weston_load_module() is exported, and that
would make the dependency explicit, allowing you to nicely exit weston
with an error if something doesn't load right.

After all, hmi-controller.so seems like a plugin to ivi-shell than
anything else.


Thanks,
pq
Nobuhiko Tanibata
2014-05-20 10:16:44 UTC
Permalink
2014-04-25 19:41 ? Pekka Paalanen ????????:
> On Mon, 17 Mar 2014 15:31:09 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2:
>> - squash Makefile to this patch
>>
>> Changes for v3 and v4
>> - nothing. Version number aligned to the first patch
>>
>> ivi-shell/Makefile.am | 12 ++++++++
>> ivi-shell/weston.ini.in | 79
>> +++++++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 91 insertions(+)
>> create mode 100644 ivi-shell/weston.ini.in
>>
>> diff --git a/ivi-shell/Makefile.am b/ivi-shell/Makefile.am
>> index afaa5e3..333abb7 100644
>> --- a/ivi-shell/Makefile.am
>> +++ b/ivi-shell/Makefile.am
>> @@ -67,3 +67,15 @@ CLEANFILES = $(BUILT_SOURCES)
>>
>> wayland_protocoldir = $(top_srcdir)/protocol
>> include $(top_srcdir)/wayland-scanner.mk
>> +
>> +
>> +weston.ini : $(srcdir)/weston.ini.in
>> + $(AM_V_GEN)$(SED) \
>> + -e 's|@bindir[@]|$(bindir)|g' \
>> + -e 's|@abs_top_builddir[@]|$(abs_top_builddir)|g' \
>> + -e 's|@libexecdir[@]|$(libexecdir)|g' \
>> + $< > $@
>> +
>> +all-local : weston.ini
>> +
>> +CLEANFILES += weston.ini
>> diff --git a/ivi-shell/weston.ini.in b/ivi-shell/weston.ini.in
>> new file mode 100644
>> index 0000000..c9a6861
>> --- /dev/null
>> +++ b/ivi-shell/weston.ini.in
>> @@ -0,0 +1,79 @@
>> +[core]
>> +shell=ivi-shell.so
>> +modules=hmi-controller.so
>
> Ooh, I see, this is how you get hmi-controller.so loaded.
>
> Since both ivi-shell.so and hmi-controller.so both link to
> libweston-layout.la at build time and both are dlopen'd at runtime,
> what
> guarantees that both use the same instance of the global 'ivilayout'
> defined in weston-layout.c?
>
> My knowledge of runtime dynamic linking is a bit weak, but
> personally I'd just avoid that global there. It is a bit much of magic.
>
> AFAICS, you might be implicitly depending on the loading order of
> ivi-shell.so first, hmi-controller.so next. Weston does do it that way,
> but I'd hope the dependency was more obvious than both secretly using
> the same global in a yet third library.
>
> What happens, if hmi-controller.so is loaded, but shell is not
> ivi-shell.so?
>
> What happens, if ivi-shell.so is the shell, but hmi-controller.so is
> not loaded?
>
> Would it be better if ivi-shell.so loaded the whatever hmi-controller
> plugin that is appropriate? weston_load_module() is exported, and that
> would make the dependency explicit, allowing you to nicely exit weston
> with an error if something doesn't load right.

Thank you for comments.
I modified module_init of ivi-shell to explicitly load hmi-controller.so
which depends on ivi-layout.so.
hmi-controller.so is specified by key: ivi-module in weston.ini to avoid
your concerning.

BR,
Nobouhiko


>
> After all, hmi-controller.so seems like a plugin to ivi-shell than
> anything else.
>
>
> Thanks,
> pq
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Nobuhiko Tanibata
2014-03-17 06:31:43 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2, v3 and v4
- nothing. Version number aligned to the first patch

clients/.gitignore | 5 ++++
clients/Makefile.am | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
clients/simple-egl.c | 67 ++++++++++++++++++++++++++++++++++++++++++++--------
clients/simple-shm.c | 50 ++++++++++++++++++++++++++++++++++-----
clients/window.c | 42 ++++++++++++++++++++++++++++++--
5 files changed, 211 insertions(+), 18 deletions(-)

diff --git a/clients/.gitignore b/clients/.gitignore
index d23027c..41b3be3 100644
--- a/clients/.gitignore
+++ b/clients/.gitignore
@@ -20,6 +20,11 @@ weston-stacking
weston-subsurfaces
weston-transformed
weston-view
+weston-clickdot-ivi
+weston-flower-ivi
+weston-simple-egl-ivi
+weston-simple-shm-ivi
+weston-smoke-ivi

desktop-shell-client-protocol.h
desktop-shell-protocol.c
diff --git a/clients/Makefile.am b/clients/Makefile.am
index 4f8d4a6..4bbacb3 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -7,6 +7,11 @@ demo_clients = \
$(simple_clients_programs) \
$(simple_egl_clients_programs)

+if ENABLE_IVI_SHELL
+demo_clients += \
+ $(ivi_shell_clients_programs)
+endif
+
if INSTALL_DEMO_CLIENTS
bin_PROGRAMS += $(demo_clients)
else
@@ -246,6 +251,66 @@ endif

endif

+if ENABLE_IVI_SHELL
+noinst_LTLIBRARIES = libivitoytoolkit.la
+
+libivitoytoolkit_la_SOURCES = \
+ window.c \
+ window.h \
+ text-cursor-position-protocol.c \
+ text-cursor-position-client-protocol.h \
+ scaler-protocol.c \
+ scaler-client-protocol.h \
+ workspaces-protocol.c \
+ workspaces-client-protocol.h
+
+libivitoytoolkit_la_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+
+libivitoytoolkit_la_LIBADD = \
+ $(CLIENT_LIBS) \
+ $(CAIRO_EGL_LIBS) \
+ ../shared/libshared-cairo.la -lrt -lm
+
+ivi_shell_clients_programs = \
+ weston-simple-egl-ivi \
+ weston-simple-shm-ivi \
+ weston-flower-ivi \
+ weston-smoke-ivi \
+ weston-clickdot-ivi
+
+weston_simple_egl_ivi_SOURCES = simple-egl.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_simple_egl_ivi_CPPFLAGS = $(SIMPLE_EGL_CLIENT_CFLAGS) -DENABLE_IVI_CLIENT
+weston_simple_egl_ivi_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
+
+weston_simple_shm_ivi_SOURCES = simple-shm.c \
+ ../shared/os-compatibility.c \
+ ../shared/os-compatibility.h \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_simple_shm_ivi_CPPFLAGS = $(SIMPLE_CLIENT_CFLAGS) -DENABLE_IVI_CLIENT
+weston_simple_shm_ivi_LDADD = $(SIMPLE_CLIENT_LIBS)
+
+weston_flower_ivi_SOURCES = flower.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_flower_ivi_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+weston_flower_ivi_LDADD = libivitoytoolkit.la
+
+weston_smoke_ivi_SOURCES = smoke.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_smoke_ivi_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+weston_smoke_ivi_LDADD = libivitoytoolkit.la
+
+weston_clickdot_ivi_SOURCES = clickdot.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_clickdot_ivi_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+weston_clickdot_ivi_LDADD = libivitoytoolkit.la
+endif
+
wayland_protocoldir = $(top_srcdir)/protocol
include $(top_srcdir)/wayland-scanner.mk

diff --git a/clients/simple-egl.c b/clients/simple-egl.c
index 2c009ee..b06742f 100644
--- a/clients/simple-egl.c
+++ b/clients/simple-egl.c
@@ -38,6 +38,13 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>

+#ifdef ENABLE_IVI_CLIENT
+#include <sys/types.h>
+#include <unistd.h>
+#include "../ivi-shell/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+#endif
+
#ifndef EGL_EXT_swap_buffers_with_damage
#define EGL_EXT_swap_buffers_with_damage 1
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
@@ -70,6 +77,9 @@ struct display {
EGLConfig conf;
} egl;
struct window *window;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_application *ivi_application;
+#endif

PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
};
@@ -91,6 +101,9 @@ struct window {
struct wl_egl_window *native;
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_surface *ivi_surface;
+#endif
EGLSurface egl_surface;
struct wl_callback *callback;
int fullscreen, configured, opaque, buffer_size, frame_sync;
@@ -250,7 +263,7 @@ init_gl(struct window *window)
}

glUseProgram(program);
-
+
window->gl.pos = 0;
window->gl.col = 1;

@@ -318,6 +331,12 @@ set_fullscreen(struct window *window, int fullscreen)
window->fullscreen = fullscreen;
window->configured = 0;

+ if (!window->shell_surface) {
+ handle_configure(window, NULL, 0, 250, 250);
+ window->configured = 1;
+ return;
+ }
+
if (fullscreen) {
wl_shell_surface_set_fullscreen(window->shell_surface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
@@ -341,13 +360,15 @@ create_surface(struct window *window)
{
struct display *display = window->display;
EGLBoolean ret;
-
+
window->surface = wl_compositor_create_surface(display->compositor);
- window->shell_surface = wl_shell_get_shell_surface(display->shell,
- window->surface);
+ if (display->shell)
+ window->shell_surface = wl_shell_get_shell_surface(display->shell,
+ window->surface);

- wl_shell_surface_add_listener(window->shell_surface,
- &shell_surface_listener, window);
+ if (window->shell_surface)
+ wl_shell_surface_add_listener(window->shell_surface,
+ &shell_surface_listener, window);

window->native =
wl_egl_window_create(window->surface,
@@ -357,8 +378,18 @@ create_surface(struct window *window)
eglCreateWindowSurface(display->egl.dpy,
display->egl.conf,
window->native, NULL);
+#ifdef ENABLE_IVI_CLIENT
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ window->ivi_surface = ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ if (window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+#endif

- wl_shell_surface_set_title(window->shell_surface, "simple-egl");
+ if (window->shell_surface)
+ wl_shell_surface_set_title(window->shell_surface, "simple-egl");

ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
window->egl_surface, window->display->egl.ctx);
@@ -381,7 +412,8 @@ destroy_surface(struct window *window)
eglDestroySurface(window->display->egl.dpy, window->egl_surface);
wl_egl_window_destroy(window->native);

- wl_shell_surface_destroy(window->shell_surface);
+ if (window->shell_surface)
+ wl_shell_surface_destroy(window->shell_surface);
wl_surface_destroy(window->surface);

if (window->callback)
@@ -542,7 +574,8 @@ pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
{
struct display *display = data;

- if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
+ if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED &&
+ display->window->shell_surface)
wl_shell_surface_move(display->window->shell_surface,
display->seat, serial);
}
@@ -568,7 +601,8 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
{
struct display *d = (struct display *)data;

- wl_shell_surface_move(d->window->shell_surface, d->seat, serial);
+ if (d->window->shell_surface)
+ wl_shell_surface_move(d->window->shell_surface, d->seat, serial);
}

static void
@@ -709,6 +743,11 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->default_cursor =
wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
}
+#ifdef ENABLE_IVI_CLIENT
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application = wl_registry_bind(registry, name, &ivi_application_interface, 1);
+ }
+#endif
}

static void
@@ -805,6 +844,11 @@ main(int argc, char **argv)

fprintf(stderr, "simple-egl exiting\n");

+#ifdef ENABLE_IVI_CLIENT
+ ivi_surface_destroy(window.ivi_surface);
+ ivi_application_destroy(window.display->ivi_application);
+#endif
+
destroy_surface(&window);
fini_egl(&display);

@@ -819,6 +863,9 @@ main(int argc, char **argv)
wl_compositor_destroy(display.compositor);

wl_registry_destroy(display.registry);
+#ifdef ENABLE_IVI_CLIENT
+ wl_display_roundtrip(display.display);
+#endif
wl_display_flush(display.display);
wl_display_disconnect(display.display);

diff --git a/clients/simple-shm.c b/clients/simple-shm.c
index 81bb54e..10acf5d 100644
--- a/clients/simple-shm.c
+++ b/clients/simple-shm.c
@@ -35,6 +35,12 @@
#include <wayland-client.h>
#include "../shared/os-compatibility.h"

+#ifdef ENABLE_IVI_CLIENT
+#include <sys/types.h>
+#include "../ivi-shell/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+#endif
+
struct display {
struct wl_display *display;
struct wl_registry *registry;
@@ -42,6 +48,9 @@ struct display {
struct wl_shell *shell;
struct wl_shm *shm;
uint32_t formats;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_application *ivi_application;
+#endif
};

struct buffer {
@@ -55,6 +64,9 @@ struct window {
int width, height;
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_surface *ivi_surface;
+#endif
struct buffer buffers[2];
struct buffer *prev_buffer;
struct wl_callback *callback;
@@ -148,16 +160,29 @@ create_window(struct display *display, int width, int height)
window->width = width;
window->height = height;
window->surface = wl_compositor_create_surface(display->compositor);
- window->shell_surface = wl_shell_get_shell_surface(display->shell,
- window->surface);
+ if (display->shell)
+ window->shell_surface = wl_shell_get_shell_surface(display->shell,
+ window->surface);

if (window->shell_surface)
wl_shell_surface_add_listener(window->shell_surface,
&shell_surface_listener, window);

- wl_shell_surface_set_title(window->shell_surface, "simple-shm");
+#ifdef ENABLE_IVI_CLIENT
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ window->ivi_surface = ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ if (window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+#endif

- wl_shell_surface_set_toplevel(window->shell_surface);
+ if (window->shell_surface) {
+ wl_shell_surface_set_title(window->shell_surface, "simple-shm");
+
+ wl_shell_surface_set_toplevel(window->shell_surface);
+ }

return window;
}
@@ -173,7 +198,8 @@ destroy_window(struct window *window)
if (window->buffers[1].buffer)
wl_buffer_destroy(window->buffers[1].buffer);

- wl_shell_surface_destroy(window->shell_surface);
+ if (window->shell_surface)
+ wl_shell_surface_destroy(window->shell_surface);
wl_surface_destroy(window->surface);
free(window);
}
@@ -318,6 +344,11 @@ registry_handle_global(void *data, struct wl_registry *registry,
id, &wl_shm_interface, 1);
wl_shm_add_listener(d->shm, &shm_listener, d);
}
+#ifdef ENABLE_IVI_CLIENT
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application = wl_registry_bind(registry, id, &ivi_application_interface, 1);
+ }
+#endif
}

static void
@@ -362,7 +393,7 @@ create_display(void)
}

wl_display_get_fd(display->display);
-
+
return display;
}

@@ -379,6 +410,9 @@ destroy_display(struct display *display)
wl_compositor_destroy(display->compositor);

wl_registry_destroy(display->registry);
+#ifdef ENABLE_IVI_CLIENT
+ wl_display_roundtrip(display->display);
+#endif
wl_display_flush(display->display);
wl_display_disconnect(display->display);
free(display);
@@ -420,6 +454,10 @@ main(int argc, char **argv)
ret = wl_display_dispatch(display->display);

fprintf(stderr, "simple-shm exiting\n");
+#ifdef ENABLE_IVI_CLIENT
+ ivi_surface_destroy(window->ivi_surface);
+ ivi_application_destroy(window->display->ivi_application);
+#endif
destroy_window(window);
destroy_display(display);

diff --git a/clients/window.c b/clients/window.c
index d8d79d0..928e405 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -71,6 +71,12 @@ typedef void *EGLContext;

#include "window.h"

+#ifdef ENABLE_IVI_CLIENT
+#include <sys/types.h>
+#include "../ivi-shell/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+#endif
+
struct shm_pool;

struct global {
@@ -132,6 +138,9 @@ struct display {

int has_rgb565;
int seat_version;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_application *ivi_application;
+#endif
};

enum {
@@ -252,6 +261,9 @@ struct window {

struct surface *main_surface;
struct wl_shell_surface *shell_surface;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_surface *ivi_surface;
+#endif

struct window_frame *frame;

@@ -1403,6 +1415,18 @@ surface_create_surface(struct surface *surface, int dx, int dy, uint32_t flags)
struct display *display = surface->window->display;
struct rectangle allocation = surface->allocation;

+#ifdef ENABLE_IVI_CLIENT
+ if (!surface->toysurface) {
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ surface->window->ivi_surface = ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, surface->surface);
+ if (surface->window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+ }
+#endif
+
if (!surface->toysurface && display->dpy &&
surface->buffer_type == WINDOW_BUFFER_TYPE_EGL_WINDOW) {
surface->toysurface =
@@ -1518,6 +1542,11 @@ surface_destroy(struct surface *surface)
if (surface->toysurface)
surface->toysurface->destroy(surface->toysurface);

+#ifdef ENABLE_IVI_CLIENT
+ ivi_surface_destroy(surface->window->ivi_surface);
+ ivi_application_destroy(surface->window->display->ivi_application);
+#endif
+
wl_list_remove(&surface->link);
free(surface);
}
@@ -1532,7 +1561,7 @@ window_destroy(struct window *window)

wl_list_remove(&window->redraw_task.link);

- wl_list_for_each(input, &display->input_list, link) {
+ wl_list_for_each(input, &display->input_list, link) {
if (input->touch_focus == window)
input->touch_focus = NULL;
if (input->pointer_focus == window)
@@ -3039,7 +3068,7 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
wl_list_insert(&input->touch_point_list, &tp->link);

if (widget->touch_down_handler)
- (*widget->touch_down_handler)(widget, input,
+ (*widget->touch_down_handler)(widget, input,
serial, time, id,
sx, sy,
widget->user_data);
@@ -5017,6 +5046,11 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
wl_registry_bind(registry, id,
&wl_subcompositor_interface, 1);
}
+#ifdef ENABLE_IVI_CLIENT
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application = wl_registry_bind(registry, id, &ivi_application_interface, 1);
+ }
+#endif

if (d->global_handler)
d->global_handler(d, id, interface, version, d->user_data);
@@ -5326,6 +5360,10 @@ display_destroy(struct display *display)

close(display->epoll_fd);

+#ifdef ENABLE_IVI_CLIENT
+ wl_display_roundtrip(display->display);
+#endif
+
if (!(display->display_fd_events & EPOLLERR) &&
!(display->display_fd_events & EPOLLHUP))
wl_display_flush(display->display);
--
1.8.3.1
Nobuhiko Tanibata
2014-03-18 14:57:32 UTC
Permalink
Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
---

Changes for v2, v3 and v4
- nothing. Version number aligned to the first patch

Changes for v5
- support weston-dnd-ivi to verify wl_pointer::set_cursor and wl_data_device::start_drag

clients/.gitignore | 6 +++++
clients/Makefile.am | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
clients/simple-egl.c | 70 ++++++++++++++++++++++++++++++++++++++++++--------
clients/simple-shm.c | 53 +++++++++++++++++++++++++++++++++-----
clients/window.c | 45 ++++++++++++++++++++++++++++++--
5 files changed, 228 insertions(+), 18 deletions(-)

diff --git a/clients/.gitignore b/clients/.gitignore
index d23027c..b4ff991 100644
--- a/clients/.gitignore
+++ b/clients/.gitignore
@@ -20,6 +20,12 @@ weston-stacking
weston-subsurfaces
weston-transformed
weston-view
+weston-clickdot-ivi
+weston-flower-ivi
+weston-simple-egl-ivi
+weston-simple-shm-ivi
+weston-smoke-ivi
+weston-dnd-ivi

desktop-shell-client-protocol.h
desktop-shell-protocol.c
diff --git a/clients/Makefile.am b/clients/Makefile.am
index 4f8d4a6..c8238a1 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -7,6 +7,11 @@ demo_clients = \
$(simple_clients_programs) \
$(simple_egl_clients_programs)

+if ENABLE_IVI_SHELL
+demo_clients += \
+ $(ivi_shell_clients_programs)
+endif
+
if INSTALL_DEMO_CLIENTS
bin_PROGRAMS += $(demo_clients)
else
@@ -246,6 +251,73 @@ endif

endif

+if ENABLE_IVI_SHELL
+noinst_LTLIBRARIES = libivitoytoolkit.la
+
+libivitoytoolkit_la_SOURCES = \
+ window.c \
+ window.h \
+ text-cursor-position-protocol.c \
+ text-cursor-position-client-protocol.h \
+ scaler-protocol.c \
+ scaler-client-protocol.h \
+ workspaces-protocol.c \
+ workspaces-client-protocol.h
+
+libivitoytoolkit_la_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+
+libivitoytoolkit_la_LIBADD = \
+ $(CLIENT_LIBS) \
+ $(CAIRO_EGL_LIBS) \
+ ../shared/libshared-cairo.la -lrt -lm
+
+ivi_shell_clients_programs = \
+ weston-simple-egl-ivi \
+ weston-simple-shm-ivi \
+ weston-flower-ivi \
+ weston-smoke-ivi \
+ weston-clickdot-ivi \
+ weston-dnd-ivi
+
+weston_simple_egl_ivi_SOURCES = simple-egl.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_simple_egl_ivi_CPPFLAGS = $(SIMPLE_EGL_CLIENT_CFLAGS) -DENABLE_IVI_CLIENT
+weston_simple_egl_ivi_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
+
+weston_simple_shm_ivi_SOURCES = simple-shm.c \
+ ../shared/os-compatibility.c \
+ ../shared/os-compatibility.h \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_simple_shm_ivi_CPPFLAGS = $(SIMPLE_CLIENT_CFLAGS) -DENABLE_IVI_CLIENT
+weston_simple_shm_ivi_LDADD = $(SIMPLE_CLIENT_LIBS)
+
+weston_flower_ivi_SOURCES = flower.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_flower_ivi_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+weston_flower_ivi_LDADD = libivitoytoolkit.la
+
+weston_smoke_ivi_SOURCES = smoke.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_smoke_ivi_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+weston_smoke_ivi_LDADD = libivitoytoolkit.la
+
+weston_clickdot_ivi_SOURCES = clickdot.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_clickdot_ivi_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+weston_clickdot_ivi_LDADD = libivitoytoolkit.la
+
+weston_dnd_ivi_SOURCES = dnd.c \
+ ../ivi-shell/ivi-application-protocol.c \
+ ../ivi-shell/ivi-application-client-protocol.h
+weston_dnd_ivi_CPPFLAGS = $(AM_CPPFLAGS) -DENABLE_IVI_CLIENT
+weston_dnd_ivi_LDADD = libivitoytoolkit.la
+endif
+
wayland_protocoldir = $(top_srcdir)/protocol
include $(top_srcdir)/wayland-scanner.mk

diff --git a/clients/simple-egl.c b/clients/simple-egl.c
index 2c009ee..bc90b91 100644
--- a/clients/simple-egl.c
+++ b/clients/simple-egl.c
@@ -38,6 +38,13 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>

+#ifdef ENABLE_IVI_CLIENT
+#include <sys/types.h>
+#include <unistd.h>
+#include "../ivi-shell/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+#endif
+
#ifndef EGL_EXT_swap_buffers_with_damage
#define EGL_EXT_swap_buffers_with_damage 1
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
@@ -70,6 +77,9 @@ struct display {
EGLConfig conf;
} egl;
struct window *window;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_application *ivi_application;
+#endif

PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
};
@@ -91,6 +101,9 @@ struct window {
struct wl_egl_window *native;
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_surface *ivi_surface;
+#endif
EGLSurface egl_surface;
struct wl_callback *callback;
int fullscreen, configured, opaque, buffer_size, frame_sync;
@@ -250,7 +263,7 @@ init_gl(struct window *window)
}

glUseProgram(program);
-
+
window->gl.pos = 0;
window->gl.col = 1;

@@ -318,6 +331,12 @@ set_fullscreen(struct window *window, int fullscreen)
window->fullscreen = fullscreen;
window->configured = 0;

+ if (!window->shell_surface) {
+ handle_configure(window, NULL, 0, 250, 250);
+ window->configured = 1;
+ return;
+ }
+
if (fullscreen) {
wl_shell_surface_set_fullscreen(window->shell_surface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
@@ -341,13 +360,15 @@ create_surface(struct window *window)
{
struct display *display = window->display;
EGLBoolean ret;
-
+
window->surface = wl_compositor_create_surface(display->compositor);
- window->shell_surface = wl_shell_get_shell_surface(display->shell,
- window->surface);
+ if (display->shell)
+ window->shell_surface = wl_shell_get_shell_surface(display->shell,
+ window->surface);

- wl_shell_surface_add_listener(window->shell_surface,
- &shell_surface_listener, window);
+ if (window->shell_surface)
+ wl_shell_surface_add_listener(window->shell_surface,
+ &shell_surface_listener, window);

window->native =
wl_egl_window_create(window->surface,
@@ -357,8 +378,19 @@ create_surface(struct window *window)
eglCreateWindowSurface(display->egl.dpy,
display->egl.conf,
window->native, NULL);
+#ifdef ENABLE_IVI_CLIENT
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ window->ivi_surface =
+ ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ if (window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+#endif

- wl_shell_surface_set_title(window->shell_surface, "simple-egl");
+ if (window->shell_surface)
+ wl_shell_surface_set_title(window->shell_surface, "simple-egl");

ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
window->egl_surface, window->display->egl.ctx);
@@ -381,7 +413,8 @@ destroy_surface(struct window *window)
eglDestroySurface(window->display->egl.dpy, window->egl_surface);
wl_egl_window_destroy(window->native);

- wl_shell_surface_destroy(window->shell_surface);
+ if (window->shell_surface)
+ wl_shell_surface_destroy(window->shell_surface);
wl_surface_destroy(window->surface);

if (window->callback)
@@ -542,7 +575,8 @@ pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
{
struct display *display = data;

- if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
+ if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED &&
+ display->window->shell_surface)
wl_shell_surface_move(display->window->shell_surface,
display->seat, serial);
}
@@ -568,7 +602,8 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
{
struct display *d = (struct display *)data;

- wl_shell_surface_move(d->window->shell_surface, d->seat, serial);
+ if (d->window->shell_surface)
+ wl_shell_surface_move(d->window->shell_surface, d->seat, serial);
}

static void
@@ -709,6 +744,13 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->default_cursor =
wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
}
+#ifdef ENABLE_IVI_CLIENT
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application =
+ wl_registry_bind(registry, name,
+ &ivi_application_interface, 1);
+ }
+#endif
}

static void
@@ -805,6 +847,11 @@ main(int argc, char **argv)

fprintf(stderr, "simple-egl exiting\n");

+#ifdef ENABLE_IVI_CLIENT
+ ivi_surface_destroy(window.ivi_surface);
+ ivi_application_destroy(window.display->ivi_application);
+#endif
+
destroy_surface(&window);
fini_egl(&display);

@@ -819,6 +866,9 @@ main(int argc, char **argv)
wl_compositor_destroy(display.compositor);

wl_registry_destroy(display.registry);
+#ifdef ENABLE_IVI_CLIENT
+ wl_display_roundtrip(display.display);
+#endif
wl_display_flush(display.display);
wl_display_disconnect(display.display);

diff --git a/clients/simple-shm.c b/clients/simple-shm.c
index 81bb54e..87afbc4 100644
--- a/clients/simple-shm.c
+++ b/clients/simple-shm.c
@@ -35,6 +35,12 @@
#include <wayland-client.h>
#include "../shared/os-compatibility.h"

+#ifdef ENABLE_IVI_CLIENT
+#include <sys/types.h>
+#include "../ivi-shell/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+#endif
+
struct display {
struct wl_display *display;
struct wl_registry *registry;
@@ -42,6 +48,9 @@ struct display {
struct wl_shell *shell;
struct wl_shm *shm;
uint32_t formats;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_application *ivi_application;
+#endif
};

struct buffer {
@@ -55,6 +64,9 @@ struct window {
int width, height;
struct wl_surface *surface;
struct wl_shell_surface *shell_surface;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_surface *ivi_surface;
+#endif
struct buffer buffers[2];
struct buffer *prev_buffer;
struct wl_callback *callback;
@@ -148,16 +160,30 @@ create_window(struct display *display, int width, int height)
window->width = width;
window->height = height;
window->surface = wl_compositor_create_surface(display->compositor);
- window->shell_surface = wl_shell_get_shell_surface(display->shell,
- window->surface);
+ if (display->shell)
+ window->shell_surface = wl_shell_get_shell_surface(display->shell,
+ window->surface);

if (window->shell_surface)
wl_shell_surface_add_listener(window->shell_surface,
&shell_surface_listener, window);

- wl_shell_surface_set_title(window->shell_surface, "simple-shm");
+#ifdef ENABLE_IVI_CLIENT
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ window->ivi_surface =
+ ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, window->surface);
+ if (window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+#endif
+
+ if (window->shell_surface) {
+ wl_shell_surface_set_title(window->shell_surface, "simple-shm");

- wl_shell_surface_set_toplevel(window->shell_surface);
+ wl_shell_surface_set_toplevel(window->shell_surface);
+ }

return window;
}
@@ -173,7 +199,8 @@ destroy_window(struct window *window)
if (window->buffers[1].buffer)
wl_buffer_destroy(window->buffers[1].buffer);

- wl_shell_surface_destroy(window->shell_surface);
+ if (window->shell_surface)
+ wl_shell_surface_destroy(window->shell_surface);
wl_surface_destroy(window->surface);
free(window);
}
@@ -318,6 +345,13 @@ registry_handle_global(void *data, struct wl_registry *registry,
id, &wl_shm_interface, 1);
wl_shm_add_listener(d->shm, &shm_listener, d);
}
+#ifdef ENABLE_IVI_CLIENT
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application =
+ wl_registry_bind(registry, id,
+ &ivi_application_interface, 1);
+ }
+#endif
}

static void
@@ -362,7 +396,7 @@ create_display(void)
}

wl_display_get_fd(display->display);
-
+
return display;
}

@@ -379,6 +413,9 @@ destroy_display(struct display *display)
wl_compositor_destroy(display->compositor);

wl_registry_destroy(display->registry);
+#ifdef ENABLE_IVI_CLIENT
+ wl_display_roundtrip(display->display);
+#endif
wl_display_flush(display->display);
wl_display_disconnect(display->display);
free(display);
@@ -420,6 +457,10 @@ main(int argc, char **argv)
ret = wl_display_dispatch(display->display);

fprintf(stderr, "simple-shm exiting\n");
+#ifdef ENABLE_IVI_CLIENT
+ ivi_surface_destroy(window->ivi_surface);
+ ivi_application_destroy(window->display->ivi_application);
+#endif
destroy_window(window);
destroy_display(display);

diff --git a/clients/window.c b/clients/window.c
index d8d79d0..9718a7d 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -71,6 +71,12 @@ typedef void *EGLContext;

#include "window.h"

+#ifdef ENABLE_IVI_CLIENT
+#include <sys/types.h>
+#include "../ivi-shell/ivi-application-client-protocol.h"
+#define IVI_SURFACE_ID 9000
+#endif
+
struct shm_pool;

struct global {
@@ -132,6 +138,9 @@ struct display {

int has_rgb565;
int seat_version;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_application *ivi_application;
+#endif
};

enum {
@@ -252,6 +261,9 @@ struct window {

struct surface *main_surface;
struct wl_shell_surface *shell_surface;
+#ifdef ENABLE_IVI_CLIENT
+ struct ivi_surface *ivi_surface;
+#endif

struct window_frame *frame;

@@ -1403,6 +1415,19 @@ surface_create_surface(struct surface *surface, int dx, int dy, uint32_t flags)
struct display *display = surface->window->display;
struct rectangle allocation = surface->allocation;

+#ifdef ENABLE_IVI_CLIENT
+ if (!surface->toysurface) {
+ uint32_t id_ivisurf = IVI_SURFACE_ID + (uint32_t)getpid();
+ surface->window->ivi_surface =
+ ivi_application_surface_create(display->ivi_application,
+ id_ivisurf, surface->surface);
+ if (surface->window->ivi_surface == NULL) {
+ fprintf(stderr, "Failed to create ivi_client_surface\n");
+ abort();
+ }
+ }
+#endif
+
if (!surface->toysurface && display->dpy &&
surface->buffer_type == WINDOW_BUFFER_TYPE_EGL_WINDOW) {
surface->toysurface =
@@ -1518,6 +1543,11 @@ surface_destroy(struct surface *surface)
if (surface->toysurface)
surface->toysurface->destroy(surface->toysurface);

+#ifdef ENABLE_IVI_CLIENT
+ ivi_surface_destroy(surface->window->ivi_surface);
+ ivi_application_destroy(surface->window->display->ivi_application);
+#endif
+
wl_list_remove(&surface->link);
free(surface);
}
@@ -1532,7 +1562,7 @@ window_destroy(struct window *window)

wl_list_remove(&window->redraw_task.link);

- wl_list_for_each(input, &display->input_list, link) {
+ wl_list_for_each(input, &display->input_list, link) {
if (input->touch_focus == window)
input->touch_focus = NULL;
if (input->pointer_focus == window)
@@ -3039,7 +3069,7 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
wl_list_insert(&input->touch_point_list, &tp->link);

if (widget->touch_down_handler)
- (*widget->touch_down_handler)(widget, input,
+ (*widget->touch_down_handler)(widget, input,
serial, time, id,
sx, sy,
widget->user_data);
@@ -5017,6 +5047,13 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
wl_registry_bind(registry, id,
&wl_subcompositor_interface, 1);
}
+#ifdef ENABLE_IVI_CLIENT
+ else if (strcmp(interface, "ivi_application") == 0) {
+ d->ivi_application =
+ wl_registry_bind(registry, id,
+ &ivi_application_interface, 1);
+ }
+#endif

if (d->global_handler)
d->global_handler(d, id, interface, version, d->user_data);
@@ -5326,6 +5363,10 @@ display_destroy(struct display *display)

close(display->epoll_fd);

+#ifdef ENABLE_IVI_CLIENT
+ wl_display_roundtrip(display->display);
+#endif
+
if (!(display->display_fd_events & EPOLLERR) &&
!(display->display_fd_events & EPOLLHUP))
wl_display_flush(display->display);
--
1.8.3.1
Pekka Paalanen
2014-04-25 12:43:03 UTC
Permalink
On Tue, 18 Mar 2014 23:57:32 +0900
Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:

> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
> ---
>
> Changes for v2, v3 and v4
> - nothing. Version number aligned to the first patch
>
> Changes for v5
> - support weston-dnd-ivi to verify wl_pointer::set_cursor and wl_data_device::start_drag
>
> clients/.gitignore | 6 +++++
> clients/Makefile.am | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> clients/simple-egl.c | 70 ++++++++++++++++++++++++++++++++++++++++++--------
> clients/simple-shm.c | 53 +++++++++++++++++++++++++++++++++-----
> clients/window.c | 45 ++++++++++++++++++++++++++++++--
> 5 files changed, 228 insertions(+), 18 deletions(-)

I don't like the #ifdeffery, but any other solution to achieve the same
would probably copy a lot of code. There is also the controversial
question of keeping the simple clients simple while still being useful.
If they don't support ivi-shell, they won't be useful on ivi-shell
environment.

But I suppose we have kind of crossed that line already.

What I wonder is, if it would be better to just add ivi-shell support
to these two simple clients and toytoolkit as a first class feature.
Not by #ifdeffing and compiling another set of executables, but by
having the support always built in, and detect the shell at runtime.


Thanks,
pq
Nobuhiko Tanibata
2014-05-20 10:21:51 UTC
Permalink
2014-04-25 21:43 ? Pekka Paalanen ????????:
> On Tue, 18 Mar 2014 23:57:32 +0900
> Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp> wrote:
>
>> Signed-off-by: Nobuhiko Tanibata <NOBUHIKO_TANIBATA at xddp.denso.co.jp>
>> ---
>>
>> Changes for v2, v3 and v4
>> - nothing. Version number aligned to the first patch
>>
>> Changes for v5
>> - support weston-dnd-ivi to verify wl_pointer::set_cursor and
>> wl_data_device::start_drag
>>
>> clients/.gitignore | 6 +++++
>> clients/Makefile.am | 72
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>> clients/simple-egl.c | 70
>> ++++++++++++++++++++++++++++++++++++++++++--------
>> clients/simple-shm.c | 53 +++++++++++++++++++++++++++++++++-----
>> clients/window.c | 45 ++++++++++++++++++++++++++++++--
>> 5 files changed, 228 insertions(+), 18 deletions(-)
>
> I don't like the #ifdeffery, but any other solution to achieve the same
> would probably copy a lot of code. There is also the controversial

Hi pq,

I remove #ifdeffery. I support them by the same way like
fullscreen-shell.

BR,
Nobuhiko


> question of keeping the simple clients simple while still being useful.
> If they don't support ivi-shell, they won't be useful on ivi-shell
> environment.
>
> But I suppose we have kind of crossed that line already.
>
> What I wonder is, if it would be better to just add ivi-shell support
> to these two simple clients and toytoolkit as a first class feature.
> Not by #ifdeffing and compiling another set of executables, but by
> having the support always built in, and detect the shell at runtime.
>
>
> Thanks,
> pq
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Loading...