* @license GNU General Public License, version 2 (GPL-2.0) * * For full copyright and license information, please see * the docs/CREDITS.txt file. * */ /** * @ignore */ if (!defined('IN_PHPBB')) { exit; } /** * @todo [smilies] check regular expressions for special char replacements (stored specialchared in db) */ class acp_icons { var $u_action; function main($id, $mode) { global $db, $user, $template, $cache; global $config, $phpbb_root_path; global $request, $phpbb_container; $user->add_lang('acp/posting'); // Set up general vars $action = $request->variable('action', ''); $action = (isset($_POST['add'])) ? 'add' : $action; $action = (isset($_POST['edit'])) ? 'edit' : $action; $action = (isset($_POST['import'])) ? 'import' : $action; $icon_id = $request->variable('id', 0); $submit = $request->is_set_post('submit', false); $form_key = 'acp_icons'; add_form_key($form_key); $mode = ($mode == 'smilies') ? 'smilies' : 'icons'; $this->tpl_name = 'acp_icons'; // What are we working on? switch ($mode) { case 'smilies': $table = SMILIES_TABLE; $lang = 'SMILIES'; $fields = 'smiley'; $img_path = $config['smilies_path']; break; case 'icons': $table = ICONS_TABLE; $lang = 'ICONS'; $fields = 'icons'; $img_path = $config['icons_path']; break; } $this->page_title = 'ACP_' . $lang; // Clear some arrays $_images = $_paks = array(); $notice = ''; // Grab file list of paks and images if ($action == 'edit' || $action == 'add' || $action == 'import') { $imglist = filelist($phpbb_root_path . $img_path, ''); foreach ($imglist as $path => $img_ary) { if (empty($img_ary)) { continue; } asort($img_ary, SORT_STRING); foreach ($img_ary as $img) { $img_size = getimagesize($phpbb_root_path . $img_path . '/' . $path . $img); if (!$img_size[0] || !$img_size[1] || strlen($img) > 255) { continue; } // adjust the width and height to be lower than 128px while perserving the aspect ratio (for icons) if ($mode == 'icons') { if ($img_size[0] > 127 && $img_size[0] > $img_size[1]) { $img_size[1] = (int) ($img_size[1] * (127 / $img_size[0])); $img_size[0] = 127; } else if ($img_size[1] > 127) { $img_size[0] = (int) ($img_size[0] * (127 / $img_size[1])); $img_size[1] = 127; } } $_images[$path . $img]['file'] = $path . $img; $_images[$path . $img]['width'] = $img_size[0]; $_images[$path . $img]['height'] = $img_size[1]; } } unset($imglist); if ($dir = @opendir($phpbb_root_path . $img_path)) { while (($file = readdir($dir)) !== false) { if (is_file($phpbb_root_path . $img_path . '/' . $file) && preg_match('#\.pak$#i', $file)) { $_paks[] = $file; } } closedir($dir); if (!empty($_paks)) { asort($_paks, SORT_STRING); } } } // What shall we do today? Oops, I believe that's trademarked ... switch ($action) { case 'edit': unset($_images); $_images = array(); // no break; case 'add': $smilies = $default_row = array(); $smiley_options = $order_list = $add_order_list = ''; if ($action == 'add' && $mode == 'smilies') { $sql = 'SELECT * FROM ' . SMILIES_TABLE . ' ORDER BY smiley_order'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { if (empty($smilies[$row['smiley_url']])) { $smilies[$row['smiley_url']] = $row; } } $db->sql_freeresult($result); if (sizeof($smilies)) { foreach ($smilies as $row) { $selected = false; if (!$smiley_options) { $selected = true; $default_row = $row; } $smiley_options .= ''; $template->assign_block_vars('smile', array( 'SMILEY_URL' => addslashes($row['smiley_url']), 'CODE' => addslashes($row['code']), 'EMOTION' => addslashes($row['emotion']), 'WIDTH' => $row['smiley_width'], 'HEIGHT' => $row['smiley_height'], 'ORDER' => $row['smiley_order'] + 1, )); } } } $sql = "SELECT * FROM $table ORDER BY {$fields}_order " . (($icon_id || $action == 'add') ? 'DESC' : 'ASC'); $result = $db->sql_query($sql); $data = array(); $after = false; $order_lists = array('', ''); $add_order_lists = array('', ''); $display_count = 0; while ($row = $db->sql_fetchrow($result)) { if ($action == 'add') { unset($_images[$row[$fields . '_url']]); } if ($row[$fields . '_id'] == $icon_id) { $after = true; $data[$row[$fields . '_url']] = $row; } else { if ($action == 'edit' && !$icon_id) { $data[$row[$fields . '_url']] = $row; } $selected = ''; if (!empty($after)) { $selected = ' selected="selected"'; $after = false; } if ($row['display_on_posting']) { $display_count++; } $after_txt = ($mode == 'smilies') ? $row['code'] : $row['icons_url']; $order_lists[$row['display_on_posting']] = '' . $order_lists[$row['display_on_posting']]; if (!empty($default_row)) { $add_order_lists[$row['display_on_posting']] = '' . $add_order_lists[$row['display_on_posting']]; } } } $db->sql_freeresult($result); $order_list = ''; $add_order_list = ''; if ($action == 'add') { $data = $_images; } $colspan = (($mode == 'smilies') ? 7 : 6); $colspan += ($icon_id) ? 1 : 0; $colspan += ($action == 'add') ? 2 : 0; $template->assign_vars(array( 'S_EDIT' => true, 'S_SMILIES' => ($mode == 'smilies') ? true : false, 'S_ADD' => ($action == 'add') ? true : false, 'S_ORDER_LIST_DISPLAY' => $order_list . $order_lists[1], 'S_ORDER_LIST_UNDISPLAY' => $order_list . $order_lists[0], 'S_ORDER_LIST_DISPLAY_COUNT' => $display_count + 1, 'L_TITLE' => $user->lang['ACP_' . $lang], 'L_EXPLAIN' => $user->lang['ACP_' . $lang . '_EXPLAIN'], 'L_CONFIG' => $user->lang[$lang . '_CONFIG'], 'L_URL' => $user->lang[$lang . '_URL'], 'L_LOCATION' => $user->lang[$lang . '_LOCATION'], 'L_WIDTH' => $user->lang[$lang . '_WIDTH'], 'L_HEIGHT' => $user->lang[$lang . '_HEIGHT'], 'L_ORDER' => $user->lang[$lang . '_ORDER'], 'L_NO_ICONS' => $user->lang['NO_' . $lang . '_' . strtoupper($action)], 'COLSPAN' => $colspan, 'ID' => $icon_id, 'U_BACK' => $this->u_action, 'U_ACTION' => $this->u_action . '&action=' . (($action == 'add') ? 'create' : 'modify'), )); foreach ($data as $img => $img_row) { $template->assign_block_vars('items', array( 'IMG' => $img, 'A_IMG' => addslashes($img), 'IMG_SRC' => $phpbb_root_path . $img_path . '/' . $img, 'CODE' => ($mode == 'smilies' && isset($img_row['code'])) ? $img_row['code'] : '', 'EMOTION' => ($mode == 'smilies' && isset($img_row['emotion'])) ? $img_row['emotion'] : '', 'S_ID' => (isset($img_row[$fields . '_id'])) ? true : false, 'ID' => (isset($img_row[$fields . '_id'])) ? $img_row[$fields . '_id'] : 0, 'WIDTH' => (!empty($img_row[$fields .'_width'])) ? $img_row[$fields .'_width'] : $img_row['width'], 'HEIGHT' => (!empty($img_row[$fields .'_height'])) ? $img_row[$fields .'_height'] : $img_row['height'], 'TEXT_ALT' => ($mode == 'icons' && !empty($img_row['icons_alt'])) ? $img_row['icons_alt'] : $img, 'ALT' => ($mode == 'icons' && !empty($img_row['icons_alt'])) ? $img_row['icons_alt'] : '', 'POSTING_CHECKED' => (!empty($img_row['display_on_posting']) || $action == 'add') ? ' checked="checked"' : '', )); } // Ok, another row for adding an addition code for a pre-existing image... if ($action == 'add' && $mode == 'smilies' && sizeof($smilies)) { $template->assign_vars(array( 'S_ADD_CODE' => true, 'S_IMG_OPTIONS' => $smiley_options, 'S_ADD_ORDER_LIST_DISPLAY' => $add_order_list . $add_order_lists[1], 'S_ADD_ORDER_LIST_UNDISPLAY' => $add_order_list . $add_order_lists[0], 'IMG_SRC' => $phpbb_root_path . $img_path . '/' . $default_row['smiley_url'], 'IMG_PATH' => $img_path, 'CODE' => $default_row['code'], 'EMOTION' => $default_row['emotion'], 'WIDTH' => $default_row['smiley_width'], 'HEIGHT' => $default_row['smiley_height'], )); } return; break; case 'create': case 'modify': if (!check_form_key($form_key)) { trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); } // Get items to create/modify $images = (isset($_POST['image'])) ? array_keys($request->variable('image', array('' => 0))) : array(); // Now really get the items $image_id = (isset($_POST['id'])) ? $request->variable('id', array('' => 0)) : array(); $image_order = (isset($_POST['order'])) ? $request->variable('order', array('' => 0)) : array(); $image_width = (isset($_POST['width'])) ? $request->variable('width', array('' => 0)) : array(); $image_height = (isset($_POST['height'])) ? $request->variable('height', array('' => 0)) : array(); $image_add = (isset($_POST['add_img'])) ? $request->variable('add_img', array('' => 0)) : array(); $image_emotion = $request->variable('emotion', array('' => ''), true); $image_code = $request->variable('code', array('' => ''), true); $image_alt = ($request->is_set_post('alt')) ? $request->variable('alt', array('' => ''), true) : array(); $image_display_on_posting = (isset($_POST['display_on_posting'])) ? $request->variable('display_on_posting', array('' => 0)) : array(); // Ok, add the relevant bits if we are adding new codes to existing emoticons... if ($request->variable('add_additional_code', false, false, \phpbb\request\request_interface::POST)) { $add_image = $request->variable('add_image', ''); $add_code = $request->variable('add_code', '', true); $add_emotion = $request->variable('add_emotion', '', true); if ($add_image && $add_emotion && $add_code) { $images[] = $add_image; $image_add[$add_image] = true; $image_code[$add_image] = $add_code; $image_emotion[$add_image] = $add_emotion; $image_width[$add_image] = $request->variable('add_width', 0); $image_height[$add_image] = $request->variable('add_height', 0); if ($request->variable('add_display_on_posting', false, false, \phpbb\request\request_interface::POST)) { $image_display_on_posting[$add_image] = 1; } $image_order[$add_image] = $request->variable('add_order', 0); } } if ($mode == 'smilies' && $action == 'create') { $smiley_count = $this->item_count($table); $addable_smileys_count = sizeof($images); foreach ($images as $image) { if (!isset($image_add[$image])) { --$addable_smileys_count; } } if ($smiley_count + $addable_smileys_count > SMILEY_LIMIT) { trigger_error($user->lang('TOO_MANY_SMILIES', SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING); } } $icons_updated = 0; $errors = array(); foreach ($images as $image) { if ($mode == 'smilies' && ($image_emotion[$image] == '' || $image_code[$image] == '')) { $errors[$image] = 'SMILIE_NO_' . (($image_emotion[$image] == '') ? 'EMOTION' : 'CODE'); } else if ($action == 'create' && !isset($image_add[$image])) { // skip images where add wasn't checked } else if (!file_exists($phpbb_root_path . $img_path . '/' . $image)) { $errors[$image] = 'SMILIE_NO_FILE'; } else { if ($image_width[$image] == 0 || $image_height[$image] == 0) { $img_size = getimagesize($phpbb_root_path . $img_path . '/' . $image); $image_width[$image] = $img_size[0]; $image_height[$image] = $img_size[1]; } // Adjust image width/height for icons if ($mode == 'icons') { if ($image_width[$image] > 127 && $image_width[$image] > $image_height[$image]) { $image_height[$image] = (int) ($image_height[$image] * (127 / $image_width[$image])); $image_width[$image] = 127; } else if ($image_height[$image] > 127) { $image_width[$image] = (int) ($image_width[$image] * (127 / $image_height[$image])); $image_height[$image] = 127; } } $img_sql = array( $fields . '_url' => $image, $fields . '_width' => $image_width[$image], $fields . '_height' => $image_height[$image], 'display_on_posting' => (isset($image_display_on_posting[$image])) ? 1 : 0, ); if ($mode == 'smilies') { $img_sql = array_merge($img_sql, array( 'emotion' => $image_emotion[$image], 'code' => $image_code[$image]) ); } if ($mode == 'icons') { $img_sql = array_merge($img_sql, array( 'icons_alt' => $image_alt[$image]) ); } // Image_order holds the 'new' order value if (!empty($image_order[$image])) { $img_sql = array_merge($img_sql, array( $fields . '_order' => $image_order[$image]) ); // Since we always add 'after' an item, we just need to increase all following + the current by one $sql = "UPDATE $table SET {$fields}_order = {$fields}_order + 1 WHERE {$fields}_order >= {$image_order[$image]}"; $db->sql_query($sql); // If we adjust the order, we need to adjust all other orders too - they became inaccurate... foreach ($image_order as $_image => $_order) { if ($_image == $image) { continue; } if ($_order >= $image_order[$image]) { $image_order[$_image]++; } } } if ($action == 'modify' && !empty($image_id[$image])) { $sql = "UPDATE $table SET " . $db->sql_build_array('UPDATE', $img_sql) . " WHERE {$fields}_id = " . $image_id[$image]; $db->sql_query($sql); $icons_updated++; } else if ($action !== 'modify') { $sql = "INSERT INTO $table " . $db->sql_build_array('INSERT', $img_sql); $db->sql_query($sql); $icons_updated++; } } } $cache->destroy('_icons'); $cache->destroy('sql', $table); $phpbb_container->get('text_formatter.cache')->invalidate(); $level = ($icons_updated) ? E_USER_NOTICE : E_USER_WARNING; $errormsgs = ''; foreach ($errors as $img => $error) { $errormsgs .= '
' . sprintf($user->lang[$error], $img); } if ($action == 'modify') { trigger_error($user->lang($lang . '_EDITED', $icons_updated) . $errormsgs . adm_back_link($this->u_action), $level); } else { trigger_error($user->lang($lang . '_ADDED', $icons_updated) . $errormsgs . adm_back_link($this->u_action), $level); } break; case 'import': $pak = $request->variable('pak', ''); $current = $request->variable('current', ''); if ($pak != '') { $order = 0; if (!check_form_key($form_key)) { trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); } if (!($pak_ary = @file($phpbb_root_path . $img_path . '/' . $pak))) { trigger_error($user->lang['PAK_FILE_NOT_READABLE'] . adm_back_link($this->u_action), E_USER_WARNING); } // Make sure the pak_ary is valid foreach ($pak_ary as $pak_entry) { if (preg_match_all("#'(.*?)', ?#", $pak_entry, $data)) { if ((sizeof($data[1]) != 4 && $mode == 'icons') || ((sizeof($data[1]) != 6 || (empty($data[1][4]) || empty($data[1][5]))) && $mode == 'smilies' )) { trigger_error($user->lang['WRONG_PAK_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING); } } else { trigger_error($user->lang['WRONG_PAK_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING); } } // The user has already selected a smilies_pak file if ($current == 'delete') { switch ($db->get_sql_layer()) { case 'sqlite3': $db->sql_query('DELETE FROM ' . $table); break; default: $db->sql_query('TRUNCATE TABLE ' . $table); break; } switch ($mode) { case 'smilies': break; case 'icons': // Reset all icon_ids $db->sql_query('UPDATE ' . TOPICS_TABLE . ' SET icon_id = 0'); $db->sql_query('UPDATE ' . POSTS_TABLE . ' SET icon_id = 0'); break; } } else { $cur_img = array(); $field_sql = ($mode == 'smilies') ? 'code' : 'icons_url'; $sql = "SELECT $field_sql FROM $table"; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { ++$order; $cur_img[$row[$field_sql]] = 1; } $db->sql_freeresult($result); } if ($mode == 'smilies') { $smiley_count = $this->item_count($table); if ($smiley_count + sizeof($pak_ary) > SMILEY_LIMIT) { trigger_error($user->lang('TOO_MANY_SMILIES', SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING); } } foreach ($pak_ary as $pak_entry) { $data = array(); if (preg_match_all("#'(.*?)', ?#", $pak_entry, $data)) { if ((sizeof($data[1]) != 4 && $mode == 'icons') || (sizeof($data[1]) != 6 && $mode == 'smilies')) { trigger_error($user->lang['WRONG_PAK_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING); } // Stripslash here because it got addslashed before... (on export) $img = stripslashes($data[1][0]); $width = stripslashes($data[1][1]); $height = stripslashes($data[1][2]); $display_on_posting = stripslashes($data[1][3]); if (isset($data[1][4]) && isset($data[1][5])) { $emotion = stripslashes($data[1][4]); $code = stripslashes($data[1][5]); } if ($current == 'replace' && (($mode == 'smilies' && !empty($cur_img[$code])) || ($mode == 'icons' && !empty($cur_img[$img])))) { $replace_sql = ($mode == 'smilies') ? $code : $img; $sql = array( $fields . '_url' => $img, $fields . '_height' => (int) $height, $fields . '_width' => (int) $width, 'display_on_posting' => (int) $display_on_posting, ); if ($mode == 'smilies') { $sql = array_merge($sql, array( 'emotion' => $emotion, )); } $sql = "UPDATE $table SET " . $db->sql_build_array('UPDATE', $sql) . " WHERE $field_sql = '" . $db->sql_escape($replace_sql) . "'"; $db->sql_query($sql); } else { ++$order; $sql = array( $fields . '_url' => $img, $fields . '_height' => (int) $height, $fields . '_width' => (int) $width, $fields . '_order' => (int) $order, 'display_on_posting'=> (int) $display_on_posting, ); if ($mode == 'smilies') { $sql = array_merge($sql, array( 'code' => $code, 'emotion' => $emotion, )); } $db->sql_query("INSERT INTO $table " . $db->sql_build_array('INSERT', $sql)); } } } $cache->destroy('_icons'); $cache->destroy('sql', $table); $phpbb_container->get('text_formatter.cache')->invalidate(); trigger_error($user->lang[$lang . '_IMPORT_SUCCESS'] . adm_back_link($this->u_action)); } else { $pak_options = ''; foreach ($_paks as $pak) { $pak_options .= ''; } $template->assign_vars(array( 'S_CHOOSE_PAK' => true, 'S_PAK_OPTIONS' => $pak_options, 'L_TITLE' => $user->lang['ACP_' . $lang], 'L_EXPLAIN' => $user->lang['ACP_' . $lang . '_EXPLAIN'], 'L_NO_PAK_OPTIONS' => $user->lang['NO_' . $lang . '_PAK'], 'L_CURRENT' => $user->lang['CURRENT_' . $lang], 'L_CURRENT_EXPLAIN' => $user->lang['CURRENT_' . $lang . '_EXPLAIN'], 'L_IMPORT_SUBMIT' => $user->lang['IMPORT_' . $lang], 'U_BACK' => $this->u_action, 'U_ACTION' => $this->u_action . '&action=import', ) ); } break; case 'export': $this->page_title = 'EXPORT_' . $lang; $this->tpl_name = 'message_body'; $template->assign_vars(array( 'MESSAGE_TITLE' => $user->lang['EXPORT_' . $lang], 'MESSAGE_TEXT' => sprintf($user->lang['EXPORT_' . $lang . '_EXPLAIN'], '', ''), 'S_USER_NOTICE' => true, ) ); return; break; case 'send': if (!check_link_hash($request->variable('hash', ''), 'acp_icons')) { trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = "SELECT * FROM $table ORDER BY {$fields}_order"; $result = $db->sql_query($sql); $pak = ''; while ($row = $db->sql_fetchrow($result)) { $pak .= "'" . addslashes($row[$fields . '_url']) . "', "; $pak .= "'" . addslashes($row[$fields . '_width']) . "', "; $pak .= "'" . addslashes($row[$fields . '_height']) . "', "; $pak .= "'" . addslashes($row['display_on_posting']) . "', "; if ($mode == 'smilies') { $pak .= "'" . addslashes($row['emotion']) . "', "; $pak .= "'" . addslashes($row['code']) . "', "; } $pak .= "\n"; } $db->sql_freeresult($result); if ($pak != '') { garbage_collection(); header('Cache-Control: public'); // Send out the Headers header('Content-Type: text/x-delimtext; name="' . $mode . '.pak"'); header('Content-Disposition: inline; filename="' . $mode . '.pak"'); echo $pak; flush(); exit; } else { trigger_error($user->lang['NO_' . strtoupper($fields) . '_EXPORT'] . adm_back_link($this->u_action), E_USER_WARNING); } break; case 'delete': if (confirm_box(true)) { $sql = "DELETE FROM $table WHERE {$fields}_id = $icon_id"; $db->sql_query($sql); switch ($mode) { case 'smilies': break; case 'icons': // Reset appropriate icon_ids $db->sql_query('UPDATE ' . TOPICS_TABLE . " SET icon_id = 0 WHERE icon_id = $icon_id"); $db->sql_query('UPDATE ' . POSTS_TABLE . " SET icon_id = 0 WHERE icon_id = $icon_id"); break; } $notice = $user->lang[$lang . '_DELETED']; $cache->destroy('_icons'); $cache->destroy('sql', $table); $phpbb_container->get('text_formatter.cache')->invalidate(); if ($request->is_ajax()) { $json_response = new \phpbb\json_response; $json_response->send(array( 'MESSAGE_TITLE' => $user->lang['INFORMATION'], 'MESSAGE_TEXT' => $notice, 'REFRESH_DATA' => array( 'time' => 3 ) )); } } else { confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( 'i' => $id, 'mode' => $mode, 'id' => $icon_id, 'action' => 'delete', ))); } break; case 'move_up': case 'move_down': if (!check_link_hash($request->variable('hash', ''), 'acp_icons')) { trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); } // Get current order id... $sql = "SELECT {$fields}_order as current_order FROM $table WHERE {$fields}_id = $icon_id"; $result = $db->sql_query($sql); $current_order = (int) $db->sql_fetchfield('current_order'); $db->sql_freeresult($result); if ($current_order == 0 && $action == 'move_up') { break; } // on move_down, switch position with next order_id... // on move_up, switch position with previous order_id... $switch_order_id = ($action == 'move_down') ? $current_order + 1 : $current_order - 1; // $sql = "UPDATE $table SET {$fields}_order = $current_order WHERE {$fields}_order = $switch_order_id AND {$fields}_id <> $icon_id"; $db->sql_query($sql); $move_executed = (bool) $db->sql_affectedrows(); // Only update the other entry too if the previous entry got updated if ($move_executed) { $sql = "UPDATE $table SET {$fields}_order = $switch_order_id WHERE {$fields}_order = $current_order AND {$fields}_id = $icon_id"; $db->sql_query($sql); } $cache->destroy('_icons'); $cache->destroy('sql', $table); $phpbb_container->get('text_formatter.cache')->invalidate(); if ($request->is_ajax()) { $json_response = new \phpbb\json_response; $json_response->send(array( 'success' => $move_executed, )); } break; } // By default, check that image_order is valid and fix it if necessary $sql = "SELECT {$fields}_id AS order_id, {$fields}_order AS fields_order FROM $table ORDER BY display_on_posting DESC, {$fields}_order"; $result = $db->sql_query($sql); if ($row = $db->sql_fetchrow($result)) { $order = 0; do { ++$order; if ($row['fields_order'] != $order) { $db->sql_query("UPDATE $table SET {$fields}_order = $order WHERE {$fields}_id = " . $row['order_id']); } } while ($row = $db->sql_fetchrow($result)); } $db->sql_freeresult($result); $template->assign_vars(array( 'L_TITLE' => $user->lang['ACP_' . $lang], 'L_EXPLAIN' => $user->lang['ACP_' . $lang . '_EXPLAIN'], 'L_IMPORT' => $user->lang['IMPORT_' . $lang], 'L_EXPORT' => $user->lang['EXPORT_' . $lang], 'L_NOT_DISPLAYED' => $user->lang[$lang . '_NOT_DISPLAYED'], 'L_ICON_ADD' => $user->lang['ADD_' . $lang], 'L_ICON_EDIT' => $user->lang['EDIT_' . $lang], 'NOTICE' => $notice, 'COLSPAN' => ($mode == 'smilies') ? 5 : 3, 'S_SMILIES' => ($mode == 'smilies') ? true : false, 'U_ACTION' => $this->u_action, 'U_IMPORT' => $this->u_action . '&action=import', 'U_EXPORT' => $this->u_action . '&action=export', ) ); /* @var $pagination \phpbb\pagination */ $pagination = $phpbb_container->get('pagination'); $pagination_start = $request->variable('start', 0); $spacer = false; $item_count = $this->item_count($table); $sql = "SELECT * FROM $table ORDER BY {$fields}_order ASC"; $result = $db->sql_query_limit($sql, $config['smilies_per_page'], $pagination_start); while ($row = $db->sql_fetchrow($result)) { $alt_text = ($mode == 'smilies') ? $row['code'] : (($mode == 'icons' && !empty($row['icons_alt'])) ? $row['icons_alt'] : $row['icons_url']); $template->assign_block_vars('items', array( 'S_SPACER' => (!$spacer && !$row['display_on_posting']) ? true : false, 'ALT_TEXT' => $alt_text, 'IMG_SRC' => $phpbb_root_path . $img_path . '/' . $row[$fields . '_url'], 'WIDTH' => $row[$fields . '_width'], 'HEIGHT' => $row[$fields . '_height'], 'CODE' => (isset($row['code'])) ? $row['code'] : '', 'EMOTION' => (isset($row['emotion'])) ? $row['emotion'] : '', 'U_EDIT' => $this->u_action . '&action=edit&id=' . $row[$fields . '_id'], 'U_DELETE' => $this->u_action . '&action=delete&id=' . $row[$fields . '_id'], 'U_MOVE_UP' => $this->u_action . '&action=move_up&id=' . $row[$fields . '_id'] . '&start=' . $pagination_start . '&hash=' . generate_link_hash('acp_icons'), 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&id=' . $row[$fields . '_id'] . '&start=' . $pagination_start . '&hash=' . generate_link_hash('acp_icons'), )); if (!$spacer && !$row['display_on_posting']) { $spacer = true; } } $db->sql_freeresult($result); $pagination->generate_template_pagination($this->u_action, 'pagination', 'start', $item_count, $config['smilies_per_page'], $pagination_start); } /** * Returns the count of smilies or icons in the database * * @param string $table The table of items to count. * @return int number of items */ /* private */ function item_count($table) { global $db; $sql = "SELECT COUNT(*) AS item_count FROM $table"; $result = $db->sql_query($sql); $item_count = (int) $db->sql_fetchfield('item_count'); $db->sql_freeresult($result); return $item_count; } } 4"6(!J9:Y3 L'pԬܧmPc÷!OlV)g>:ʒ@"8-+'+y-,Y~U(Z`N ~<hOjXg#J[0U7x[ȝA車݅cFAـS! IbѰy͊z:wˣ{Vob|wt5=+"!mFcʡz(N;Wp =фaFa{D J[*CFKZ{aep&1(:>vB=)\dVXA CgzTimv%~`'%?%wgKqBY}jg1xMcˠ5&w tb$@qhĩL2 %F~/o.b.jT-"`Hك #o\ͻrO_"c[wYSޗ<_J^ J}eF(5ՕxL hڨ~yOEbhB>4dé úrshەWJ瘭T$ؑ3.FVx*p Aul DI4yq)[jHedairr!x$},≠vR&,9S_ 3dc>w twLs]:G!b,9Uwz4tl*R {2J]ڷS&(-&#%k8 J:^7X / Md+UPo@TRl7ǣG-‚X/MX q. o7'*ym\8󜪍VR8m@bBc70$P%ON踚H+._+BOwX @Ĭ1$ $ ㊋IyP1w.!9JX$P\ ם QDNJk'p ,դuh, RGR%[Qq11Q eXP,& nBt8V:.BQڋe+֧9؎\/ޱ{g"=iE(i!"I+U`$!gTY$,}:E(6~/)Xֽ>x~}Gy lKyoEL,Eʌ?Oft>KP}Օ1"M;qzJ|_?,LzjDglf&(,pd%D-u ͚<ɈdwN_/b<{-R*kMUI5sD~ë@A>S)BJM8t.%88K|+LwobAz Eh50[I'g͉&ڿn.-%` S;CHU]}P5ARz4 >FN!j>󹿡w1fP0 b /ޮ oD[Ხ1֍TpƠ4zg.\ôdqNO ca_$8}qE3kf;b Ju.z&. BT}yl{ۄbځKixAā7*tx6=kxVs9,5A]ߋcDuڶA/w<'_8Sƒ5/L0H!oPml\s*EI[{*s*G2jMUvoت oyB$ x oBUIzJH5=p,WFe=Eʼnd22$kChs2,X)nq}oDɏs?\uK2_d֊E!6a<$J.j[\{ϯI3IڛP~7SJ[y ywTu&)G 4Ncm44GƂp`]`ueC8qDsv4fogט駄2P,fW ̧}m)0ÖmNܳ'V0v--M< 7|Zw yLƵ |!g bL8_~}(7\ذxZ[6/Qn74 SDi-'bY(\0,mc y^m#MѨB %K~N<H]oR#>oCfنCEEhE*3Q-r^6]tv 6'Oi*:j&!6 ߝ *X(Yd,#xJnO&ōE>,_xlQ7R@/Rw1ǭܓ HAE+O"@lwh[৘xlE3GI](Y}󛯐Xb,OqTc~&`HN?Y ~3$8]^Yj>h'Q!nId*a v.v?.GAtZIF]C.%J3'wn7ZS٧f2;4H!* Ÿu $ *窶B iTa !TL/|}s=vZǿeN:(cov0̲w=9@lCU'4tb?g*׹{wak{ki 3sE-0wxo>/ɵb3\Vh23h`9"U6S^ZRn-H\ ~;嗀WԺɦl^`~j.:+~轕WtO<2Fd%kAV~៞N~d<]ᖛfcz_ƴdQ`=kcL 5$|\04p'zAࣖ|J"w~_ȕKx3]I%Nf~SLs~?`EN/MʲŹVmR("uI F2./07~D9}Wuӎ1 L 0 \$xbc &JUav&`0xPrF[ _j{qĨ8[Ӥ h@a4MSr0_/)UY5 |W='GEiumvju^X+>X#e"04%7x A6=H@93)RH`l`GL(< T!ms3ݲC> A3VNeFG/b:`Ʈ ZwRFE[$zAy߈9FFWMtFjH:הm8`rFBFŢ1wVFPv%b!%N1u(#^(A~x &ܨ:5(dpTXp!ŮGqE rH_oj49^)nbu?л~]Աr?>q_r+qsyձ09)(4} 64eL[فAnizg*۸wE֣aQ >=/D$bxLUִU,{ q*/9-d@7IM🁿 ODv#b+KG54t[ݪ/\PU)4E Ḧ́(TF- Ժţ ˶`MI3=Q R:Zo+m4:O.@PuI<Ǹ}mMNo&|6|.l Z7[FvZ!/sZ0&|4{򸛹\K.1 x74&Ǡ_(Fc-wEG8Rݽ:AѼ~$nLzoc!ք^"i.Z#gy14^/3B`\5:.b 6=lޤFZ%$/')5:%+IIM]&o 3n Тޙdƛ>XOBh{S}U`1aYƞNMw1a/D;їy8ьc?ɳI _(;k Ɂ> $M)ฃ-񉤧U"TJ+GAt۳10*c.9{W'lp=XZ)8$.>l{QIN)Tt/7ﻘ)b9 ɘRܺ i;NMuk .,/ K]qi\+RNm?ؠ,ߑIoHev vxF8wDЎJ'z1Iw.Wǎ73ї9=te{"MP! %5 r5+oH X=,52p#>)H_J[^ 2 X]_dj~CŮoɁk\/` H|kǽm [:{%Ena9;|WoM:[[IIE;rK!chn1^W*W5|9cNz ,maS**ܘUJ?SNBp LzCӎF4=-8zjKd%rh/-rr9@Mհ7M_ZQY@0I0On `r\tbȖ슲U}ɷp%_5P@9FK}ts|^F|zE4g4=y>P[\r x/k :K9$_%K9.saW8mS`tdr:w“ 4F%' ,\el{71hDŽo霯Nl7'_'פүgrqQFg{ѫ` vjԝ .^ l7$ 2CuE/${ԖLp:7fIp?FG=(U)}6ju&Lĥi.CBx (ey௭OL~A!~`hڞXŒ/AЧwP %fA&^iͦZ98|!5?!~%(,ur9 ARP~{pvWiw!PɨJߙTس͔2/ @]7R}Y#~@s_Fk]|Nwz?-2Fӎoу&,yari?'4ko 5$ >x,!>[267+ [iޭoWC/IiKB~3E.<iMA ;p޴aY^|,[CrI)l,A;R:M1­_]%,wf\23sGTm4)owVD1c.٠M9`U+dz8=s]~xoV z9(n?%H)1,$A85 [g'*?6gBi]r#)'&hbUa^ % !|yW,&ɟ%8(Rz'7Ÿk{XckҳAA|" ^G=vdC,o6\5y3م쇋or9aVO e MG@7sF} 0SF܄•s `\5!S=%tSNj8-k8¾ml4Hr/y'2Ӟh67;`NG2Th>Sҽz:"f<+ X)ȋ@P @)ݹt4a^,B yt,]8ªslO]FwatiJ86} 3!{  ^N>o-^cO#5GI,RYc`>7/&h b^ۭ\Eal|j[ "^6\Eu?"Uw:MT-|=w}HֶIYgܻX-jy; mBZ},5n(K7;Tw9rջHm> u%,tvGZ!s MbPYQ)[d"=)pﶅZ㉥Z- $MaiA39 S/AcRkDž>]nJ {HĚJ pfu/+{* $u*XTq\R ִ۽*Ƅۘ*45ȩB0Lp;hj9ɞ@'Ƭ/j a|Y>Ո;nV MxW}W.46.띝Pӎ$hZ0 r d] LH?_ n8Uϻ Oh$۞:8[MMG C\I:LtqrGOӨqW /?hxg<^~wEyYR)oN\[Ia,)=L>N>3hwk][6)4zyGҡSۡM jIHmUϳ!o#v|xHcoQj8n5'Y`He\)Y1$,9>^e *}fbí!Ik$xRPu $NVzP QTny_[h&3 XttVynwPp/TCf eT5ZUԒVEs@\Α΍`ٟWt:&ץe&`wpœ{؍8d6mQ.D x ܸI.zbK<- _{Z_d,tK:z70H0A* dܞ7l@ߪF;7{1NJZ?o\sW]FylXbh ӀmuL)ƹ퍟Օhrէb@b.xYoS;*b?_|hTC5i%ƫA[_,ffHy[y}- Lһhh 76u!ݟޝ *yJnK_ȍ-lӗY XKĻ*ۧ1GjH1;=7sTYRްm +#S/sELgU)'1os ?UM'KI d8SO`nd0`,,_h_59VfgGҳ8 G Kx'qDZAhY\dʰ$Z2×?W7'VCU`O^S% j7j4 Gz?[Fma07x?iR2n 㡴<(yZ҆ -K bw~}Ѿ z#L!ZXp.JKe׎DY5 ,}O[oVEʋ':?N_-P"\ p*&$̅eo)q'IGLo#V!H#8ud{ZWQAGcJkT ma~%o'm Ϣ[J+ ,/up}?rfDT8 D65k\(r@ BPj3J$J_q,>0M%ɜ+&bh I(A6LEĝ]܉c3F۾ 0 7kIH*g>kHS(ch6/2 @pđ:y;ĬWAK9܁X%LDejr6p*э)Q6ldI}=ǁ٨?7f$%H\uxL Z5Cm7$UsQKF7s (e?#Q9#NSp!?Gy2Bж12ܙ`9ZmHWѳZNH#sPXChlf`ǟ f}rD1hakQxHm2D͡9|`hO7]hԺ)=7֋"дVtxs#;=kpx'\ vzy|Nppal]BcS֟yMяk3AsC0T~=ћ[(jJUn]HƬf>g~~ky} iU[uzkSH) I$,{4)7}-oc`-/ |'Q{7Omhls$<Ԙ]:f a'])]$[otM%Р)~J2*c-_Wzr./rb25CҺ-MB*VdX\f"#>yxaPg4B\6of^4phE{Y$M52^򤝲įܘ"q˸Q@t=&q3:N~?Q<]|j4~d?ЖU FD`;'?\p'R$Lpu@JLV:RKjSб xOvU/. E~~d{hhq$Xҩ:E\<MZr9N6Pee _&F9/S9h19V/0΢R'q2Γd,T?ZNq{{.&4@%kW$Sa \MnV?nFpMC)PgQDx2Ik} )Bv*Aޏ~|gzP}{3h=.=%;[-tD\fF$fZ%-YҺ( /rN5-dm#,`fO/tځ8N?c ӗPk|׃ebFTDq<7:o}V siş5^yDq'8~ĕoG!5~7 b-ɺxluxf,X@Cux;3ԋV@$F3ic@?M"/Eym!`_w~h;-w]6 EL0BK+gąAxEBU hYć(.F r^jl?C\Hu&U`))ߴ!$bp]+UlKCf 'FH"9rP勛êu^Ts'd[\ \VbwOk6o|rjGHɉ-!O֔,9Ǿ8X٩HVLh5= 򃬏vhdM6:oԱɹB4aşm;EmE1':m$B\ #7S{)')!G}tg|ec$Q\pSO4@X$VB;6SDK0Z_jwaOH:4G'Qg?L%)>Uq v%Y%NGCȠ!JU?mzJݹpJEF +&v'%oݷ|k 1Ǿ_Q?Rw\MnBe,L ة1KNu)+̂l)۫i Xý?̎\e@V=4m@di&9PgPZE}2>XE $Z\,OG]f]_xj-½7#m =a> Kd+{M˦9bN:i&Tk5{kƎ⹫%>w,{<)ߩ;O8OS EJnǼŽV?OPE,~zMs^`MV>сrb,6 :SDvRF75$Ru} ϔhʇǫw8(t{D5T:j ^-*H/u^ IF.@ѣ،~ V)S.:юUAB?@ 3˜C,/bjac lkhh wM_緆CV`N'1"G0`[D GRL"K|bAg]-=!ňc,aEeہ Ti}?Be#Hw+ڇL R+w"{k19f,s8οnѕ^=Wvp"E$q&rwj$C0.1_H34Kytv.y_ tcR1tߵLj~Os_8=ޗ vgHaHPCWU_'h-.| yܛP6~<$Wr*J^{ڷ*  8qf^S(= %],}A-T]zh=-T"AdNLw15 =EI2޴obmR|o7\ߠfHX4FVZp IF{ÔGm @ؙ(K8X}N!~,@RtzD;;&p0ʸLQ \a#.eUboanӑ!⢊ :Qܮ˵w/ V+;LtIiHa7#P 2o+%q+yJ -웃 *'"ppK콛8`ŕ?JU^)1:uL=:Y3U^7z# tJv(GAK3WEھܑ34 n\jTO-V1m*"nyzadWM@L {[kWJ2laSUC uP`iA$Z |bQeE˒LB%!3N<9nj5DA/2(69d=M7ڗB C劳 iĹD41BeodS(1S{gl]:ٮ_~]EPꍮҋHa"k< )P9/)0&6UڋbP^T5FX)rRE*}.A#4_%5wKX:b#ȞCUnWIl0#wE&քBcy)8h<$9ELՒagY x@(k~ѕZ8BCcD/Vе6؋ߴ(Zlp2+OV/%@1TIyEAB!|-R=nD&=,C7ŭgvl ւC^s5<| r}n#W8W~܄uxg56f1|;k=&B5X>D^'%T"80(A 2>:cIL p Q1vmmߌ]&ǀk=@_G0 z6je24Bu-%Ңy}fy};/tXo m`tC8'FP-˱!]!j7N a7HK-c+/0nx;A~<qǂMMWj!BBl{{0A2pdѸfD΃ MmϘ6q_B` DꌨZA,kfc5_:Ս6 ]8F-w_FaËh$E(L۲~KJ7FA,JXn!+*uXf龣per"'&,lt0HgAO>5+PkS}V1vֈ*TK^ה@rSGurL0Or0jj]|1~< ^45mvm}k*}Ӳţsq[q`k;dDLaXM[>D)](Ur(X3ĒWהvxYEg\I[y` ۢ׵z_dcicle:U@'.*J"Q Ӳ@BN౷cr:LЊW5^DbotE&"KeVaI˿(y1X}06U.TWdTF,:dJR7S5+eCNj5-|Q&t=q>fiu/g G9c|W@ygv+&}ޠZHJ4r3W$a\yM8+q De"(lҩMc;a Q(ҞЕᚦ_$0a}lK0ydWr2Ck{cb-vt@bӚgZ'>׌]l na1**#҈ڵ+gװa,϶@'Ht]ӓ |NL[fw,QM.eG!=`w/+/:4JJ_d*} RZ eoC*LBl*)I}NdXW$QE'iF"4|!|0 EcҀ\W#̴5<S]^.MtWpw!\b[N~cV1S狰sNH@y`ѫvlqvgUϽ#M]'@>y$JӹV"KuIڝƓ3k|tż@;Zߚ4N "qQ1;<s᧑d*Z;5X*&~YQ^v3(Zy:4[Tb԰+i'o =63(%QfK'ͫۖ7z(p?,\3稐p[aŲaa 6DvQ61a . k 4O}PqRJA,ZLJfq8_QٰPo^26,1oH^*{2!)s:Hj&-!\{8yu$M_F b?=IFl4]; H'T%v솝mz;hw;yVYzA· ʎ(-'!{VuȫE QD=_)! |.:ogHtpQ̝Й;j4.$CB,mCd4+2=,h5xaO p5t oO-NB6! bL솁J?}\Wbu-V ʉf ߣl[';Ɖ%AaUתh[mzh*ݞd\%VyB[[+4]Circd"F2`kx[ nR:hyk[[_"S ɉ輝(Rg'a.j1d/6 7$ΘfBPHr5+WP5,HD=% Zf%8Nxd,iJ ֩]wxځ ;dcsޯ63]"eIFB3k8_m$!'3Vԑl>#t4 wZ"܈@fg"84OZ(&@Dgw"xzKQ}p6ۋ|&1z~ e""^3|sϨГ޽Ҭmc &ha,YOH1m=xylg{j߮G ,7Ec5%vc'ΏI&}ytwM.'REd;F Խ&SHZyl,hۣ="Sx&|$J$ x QQpl|C%(HjZCVOяݑs؄&.HTUXB:̠*sYUo. SO-XABjy( 8ᕻ6N55? +ɹCrYE$fwMOw gcB"VA=F{ԪhN*Mea XmR3Xǻ%f`sьN4u\riTc (5d͠3Vhy0{s'hwl M7|]/5Z88QOvI8F 4 jir,.rCo4o.kik u>Ʉ 6-hWC*ZA]{ xy#\-o~uqTi3p ӧD+/h/ձrLnOѡOŤ~ۑJuoi0A)9VZ/$b-rYy H\"A4,ԊFlɯ̋ףzqzͅZ_ròc… B>1DBS}쉕D o.`3>:O2z#zLHLE,?h:B%EkeAaYܺp6u pS \Z }LhHDŦ,H|n5ݯrÔϠ7NtĽVBF8а!pxר!7߄c16Bk`H㖑-Vk`VܾuElDCp)D 1̉)y)O+yY.;tR@ԭaOӶN?b)$YtU#(v8숽 Ck*&u2`1Y րC(K5 Lvw&㕘6oG~zwmo8 j\d/9Q(~*K\F ]+!Ђ( *O GM%I,z:\-{H}p[e,vb̙.A15I 8#L^*.HO7(kd BW wkFVX^V hkC6K7/$w?0$g#[C= /R|^ Qy7AY^'Iu$,C'9XOA (,R)$4d]`<}rU9Z#!ζN٪`x/q`P:r NU4)5e]W0L`ٕW$:Ȅ;t(D7^0֜X=߿#<ߍ'.3rGr<;tb{ױ*xCƝS']6fq ʉ  =K 06vfD+EiKF6bAJ {O*Iֶ@]qGnBN^"fD'rc|DjZe\pg cҀ)}NV%X&@m7# Š1_TP( ߯Bl7/¨_Q-O ;gKWU&\nuz4b4Pmrfzx{uY߼8C GlC0ƺ] bh%RV&r-'d{t'ykg&wř/HCsUf@7f"{;B]̉vZzms99|c+C9'ʵprZ23KZ375QJ[p["7s k0 e+G-M/a6-OF.Xq±$q_ny8>c_Bgd05tt |}Ipg0Dŀz*L *F?#Ԛ>uM=}TO(MZL<`a|Wɐ{jG3Lbʠcc5[|Ř[:E0sH*+Y 'ʳ~\8 oHt>+;+MT[lg%, ȰD1}|f[ lux'N#jlBA`dyQ2e`S /3]7lTAX\pQ&zR&Bo8F c4~eoBe$)#k=2|raI |aVL(6) )Y&+ӑk6h;VP~(gZHVAs6}. /Hg"g]Kd\U2^fC}fw Zyj7 轲pj0_g]JtE`۲ɻ ZC![j\ YF|GYV oQhfD o?-ͅ-gJmFYǘ%vC,;W(SCKKUZ'M ʹ뵸B )5wI!7 CӞϠu? Fq Oͽ~HD&&8D[5߃z 0ÒrdQd~[,{/JV݆/bOy:uo )` fupDFpXBL_fC?QvЩ44.eÚ= #TIpڪ ùD}3*G𨂸ޚw˦U>5w z2s?aKEG/YYW"Y:h*x |JEYak,H3=^ʄkq=(-Xi?4RCQ WfEvp<*7{×>3<>]dqq}A]NᴗW./sYBN rf <[TXfR4tc[@`})p `k8~!tx8<GT`i} k)}`l2L̇v M,ov5ু=L d#n$o,9^o𧰍l/Nx¼uZ!1` Ev(PsEt  "μ/0w)SgZe=Y&*x\c>Rȣ`DQ#C̒n7NHnA`[8\Q/C݄*FHux4tI}탅3ش Snja=:?vT(͠j䌅Hw2}3c:T&Dz8…ڑO!E*?!4dfYJqpM,9(_~ۗ%> D(Y8={N6tխj3y/A6E3a'E# L +T9Xsqcb[ քfgu9Aow qK,C^l(-}x@+Vϓf,v^RuvT_e& ʋQAZ!qB%5ZmgYAAၳpxI8< -LU4SA+I~WØ' dS;kSRUܪSTFN,1Xrnx %ȫތ ;RcE!Q`GJq[cbHH\Z:%@ޓŒ ƃhd4dGUu)d=i'"pK*^ 1଎Kd# Q!?;JWII/YO/l8 ؝_ go#ȿP*bv5fy$lce(*0Tp.ɯű(v2r*Ox2MwPonk8TVnwiTPUagTM^w" Ƽ榊Vz`$̦(8@;=(䫾/oNy3 #Mݲ|fbf)W8nJ{Kif ^@:ɺ}ZKʒ'1yZ0fRM}#6mN<_/5| 5.@%U7dDzہ9`r7ЩCc<7<=aN. HzkGL<\ qKSRkіPOVD O#g9艮 I>,3؆`f ß^ltsKom@]{7 ?XUV+UQw_f~0>4qd8fƤT2ntܡr.۴QG^J/S{[J\kTy^Ƕe^CM.T6Kr#|zmL*(S׊ ykhzgϕqDz[1^WLMOS801D*NtܐinP SBK,C%(~J?e9sfZ#=["jc2|D,7|#qX,ުG"Z`apY\PI<.☏D{/^]F[@`ל{Y[}Kb P^ bMxXs45şb'W#zKjG!ĉP 5'fl >c`۔*ܬ4=I DE'xO$7g/pZ{Q1E'W 4DuX<>O͑Oq(Bb)1)OCpOdzltvxi 'qM\ZѲoN F V9U19v ^s'V7U:;-(梨>dZ̵kxH,bIӀ5"\1f5Yqo%Q2r^_z~!@JɨbRO@D36ˡ"DXy4nQ6N.<#+V+fb1ENjo%j/[ڊ3/NbԸnH --ya0{Ks)gQu:v;WYVŚb8k p *|gĀ~.b?KDo8D(ľ8Qϰjy   O۹i&7n15ۘ=ꬋ)-,e׶MU~W$ .wn#+mr MGcUr*t6UVJ5d'kU?DadwUuf#[seVBLD6$WC H>$GN#m[q:>++[ HĂ*Wݲxy3INwzsF\_kEuv: Ic'Fw̥^h2m/1D,qLGq:G6x՘l %n eIoD]{c!D"g۳;o+ڣmnmxm y܏v=96[ ?eh`74z 8.:/ͧɝ + 14WPYuTHH3S=))\YBwX&ap "AWZ_H ha4lEs k=v % Z4- @,ٺ P!!\&{s\J7}:ƋpӃM 7I5c-O;bWBl hOֺZ>dlC.lB]#ȴj6FLf5@am{KPtdeKҏ?PmNڢD "9R;xZ{"`' ܹO&sIW~Vi4V1:k^9=X7rVz'w`@q-1> fF2P3vC #{cz%;x*Hה2I\r:QIK#w+#%H K':8qu-=ӘZ;c"nLx,` Or 7͍3ian܉>jҵF5\{[5T\|D l Z"x$:J0YCtg0^ ~!4tѷx4|@@yZ ^{~L_N| ٛTsy}?kvpH܎ -ڏoo\QIǐ!3'D [䜷X7qr &W!t[60ǰYB:n&E]aP*hu0 G! KS.~ɋ7\,_ |ij'/f8A-FzjY$UfJdbxNYtqh;cQsS_6GPW9pG0ui{2W<Sd+<~}\osgBls xRJjyոHa/rs4))"$S}+ir=\԰[tPZJWn1fJqoB9_d<;hF11G=>s%b̄20%B͚-G4<*<ƁL5f@<:ǤQi :1kԄ<"0V9<ũڜXz('$O(ȗ)G@@ fNqx<|֚#sY<´7l˗ii$Yk>k4i]DCT'`G $")OJiCo ,U.$0d?`q`7݆fC#ъk;^ivENȏѽƟVF707||bZT=@kY/m6&̭^bd`)6M,ƢAv`q}XKĪF~#ğT7ω̳)M'|YH:D"^۴R>;b ){Eur{贁_ %UEBSlx#Щ&<ui8@tEﴝ5(%@-1I`zᎣ.)/;2 4<R23"0Ӕ҈iDQ1l 9R%hk\JY{bZbE&!>pDm G(~ysDO@ ~pS< Sp,(|kV'ܴd*kk4nN6x>j-=ƼF/+,]&*54UdܑSqQC9 .Pa|^ }dLd#aB}En ]Fu8zoT ׀ٲ0uS*wT)Lm`btS|lK12L߹a&?pLNX~Mj'ZD8 8 OzUN , Ephܚ`ɂTZ~vٜ!_/9Bs:o^T>m,U=g$CWhӹx4۴ XNZO\-? W ]̖.gpQ…7y^ɶ^ĜMVڍkܯ9sDv5=!K*%z Dy*mi+dF:5<^B:}ѫuEp(;>Дȱ짿a^S":phҕ[#]gOOpow?!b~y/K}]9`؊ezl纇7!S#$:uhV*ܿ 7#Q.ġV_E @2imL ~ʃBJPc;#9'r=DryR&_/ʲ]Mvw¬fA}!D]6ߙY;ߙ MEB0ZCQA*NvkDi>@$~DixE,9h 6-( ۅP!eLO^-*7RZt5Z#8\\IK?'02v/صQ`)Ybx*ϿA*FPp; f\p*rC5-=1_~vӷl8~*;syHf\N尳J#>).. t+ /)Rߘ펲[Ȭggǻ)e X+|FS&֒~Dַ-l%ײZZW{S-u~f6*YRHTC.2ԟbW+eE֩Ӯ9)>f53k.%S7 ^+#fQ†EB"B|gzV_> %$l6.8*<-w <|p ?^tm7~ZPAp9:Gt'AJB`=;3"$iʆ=Q3WZ)$v,3- n{kQ/ڠR*}9kt{cgskA*<]@yL 1u~P/0MU'.":)ٟU`oN$^HYe D:gawH6""68(YZ){CcBD;an H=hPA!@{\L &0{X-7b#SW=X-TYJ `ri-*XKYI怑A`3{Jǐ2Rny5 S ݛdZ<A|,Ef[8RǓTdTp}[=N) . >H¾${HmS1OWp2Ů#f<.timޞl9Hrٯ8DN<.ㄍ3Vv۴H(S棨.pǎlIc]AuA~>ΩO`z[h&JύRx[M7&Ԡf(=PxP' ]{aƖߨb~?C%ktml3z"5ˊ@s[]رYwcέWp[= ?LxjDX_kb bM>q5 ubtbOcnNB#u[tvNs#ɩ{;K)O +$Z 06+U=Ne ;_o?]Wh]Gr(%?.7.y? Ν -yE?=ƬaO*.=Vlʴ~ @)g :bˏC[>#>]QǺDdKSLMiP4l-ZDrKZzd }.&>7,PǧR-,*u[dJ(On]/ 46q%lUC<͑~o][9Zis\LC 9~:\R'3}׸&A]\"LBtͤbzv2gO /%Tߠmk$^+t)\I(M$[\)oݺ+#PL^=ƛK3 nz9un R6؊cvnޞj|vw .ګW} Qcl&:I4" 'UgL*;T!N!,WeMe}%kIi |0ۖt(JMQj`4I[vo%A]ڬw>>P@^7꿉_ ]1TF{ KCh_a=8fr%V_d':GíHH%*Zn1}&cFN “ekfC=8j-MFٓSW_M RS++: Ԟ7k~iQ6v~@pRwhGo}vR^@D2*%[⍥ ie2;pv fe]͛?'˂w9q{NDcAۑ?ɰ#&&Oi/DjO/GV}ةYblSoeα~ B Jc|?≯LN'V'm8Q }gߘ`9G,ہb\ $!>\>%! dS"閫9RŭSd6E>hTwB"eG?`>b{XYLCی0\j\j[n7?-O&pҷ> ASM7AxIdCdޱ5i#7r9d+I=Scek((oX#syqQDMJePHQyaGQXB`gm|(F4UhPb/hVzyQgG ^F 9hQ^c6S }}5%_k]+H)Cc=/G0GIZ 72ބwΈ^p%LO\-DL^RzIB~&!%eyN6=v"_w7A}NuSdnӴAFzҎfNGX,%}xR!Ae˵V% 8rl\@Äw/ i/04ܿ0&x,EF Ιvԛ4 Vg#clAui=Wl1v [Ú 6)|5'SVF\ha GysZaleSIMRaQsޓq>N͊bƿ 8eC DCd .t˞IjQw9)\wJ*#"OY7m) 錥gCv!2AقM5 ,nI":4ӚbY4'Qd@4&T%IL{F +X%t*ܳ,:YCoD$z'a"}ۆ=z1꾌8&gn'Iba 4T`/NYto!z3ߛ1HEPbh[_,< 7vc'XvcHij̸ZsG v%adqÿц~Pe06\Jdv>P. {40Pn-d).يP}&I(u J:9g+*6 skI%C/G$'AUԬ:Ó4j@c%`+a] UG}ADSo _9 v+ {!1ibc&̿x C,zg؄L9?uGˌ@ݞ\Dfm3v$=UZp0(^;8N!;8uֹ#nh i:)Y I]w׃@n^a8ѹ!THuG,5>T"v${H޼O^uv.,q^J7~V|fLmmx3׶Ee܎^6/'v 0lq!y[-v-K85z}|zN)5uk'Cp(EҶDHk_ZA^ տ\ x6AS.K@fh3 бH% Fm|h Q}2" [Iɢ0^Gb{WH|Vi;<9p1Цw j|@mEYp4ōiV24wD kܹt fDo`@5GI,sekxTPJ%,aߠZw[ ybwcl@FL-ŖJ;H}{9;KcA49 hLw#pK%:Kaw@/~ߍ!,r^Y5Ƒe櫯nP];gRByGؒaG~ǃ"GSļy p,5n(h+wC4lL{0Acj'5%DžF9skpAA{@rJkO@R 'D^{ڗ1yx(fʣ Iױ8Eч'6񋾎ɟqk O$DXzmRw6Rg db:嶜gҙ',Er.+ibr ȿyt4:o9*fC~O+*(%#iI]JC>RZ/\Zwh^ke_&C o0>ҫ}dBۨ,0zm<uu %tX,kB Ii[Z}]vuT6ل$x ^Xeqp]'\?,.X|c2,gfĀ5]T$=2Y%/9 +r_j[z80()N'KxKo*ihW"o6om047-R; ^zj~םe;kPc?K /+WeTb:o,qhM?6 j%Gj%i+! 0㓯.ru"vA,9`NZe6 Qv>otttqyh6geйAt X1,iv_AUrm syLle aT5U;1RTFO&%F3-pؼ; q|6:8ڨ(MJօߺRt:e[4 aV&mdt~ZOY>9??PʵH-K(ߟ2·coF%fH>nN%}F#if|mI +o7w[yS=^'O墒1^.O ĥQv0$}'.B#F.f9IԲXYu7$JBul4ݰ}θ@}XR qg#i2`;I%.xzq`B/i;,}-u_ >[ ak $WC [=i!jaÈk!sO.)je$w׶?صݐU9eN{+sԴe :7,{RfM#DmamFls[Uad~HQ K*iQy~@],>k_7@;篳t$^4t6m<'ű;M= t>)-:. MoҪ|\5$>ȶܯ튾~8cCyS+zmp+iJWa&6-D3#K*Cd/y95MM٤Mیtz(L틾.^N춈vdnOz\_l)er` kӺ h󫴚7gn!#:,c|_{l&gقMfb1I_i8$ly;pl.ry`lTtoWa{ΦV*x~b y\$ 1@7o1X'XYHkTC~H~*7<`SH ._b{si%&&壪J565'65'!< 9BDfY,MIrL^WvmRyq7`f^U$ߜ%KcȺP!XM [D[ qIQQQ*"ފF46;wCb|FK7&"t`Lze#^._֟3 !s.iq>v # m3}[XdpF_4PC= CK f|1~ݩp ,"0]{Ut>mUv4o9$D 6G%)9| >54 /! ^cu ZptOrL 40ϛd󑏌{q.`4~JZ4ÐX~ع Jgp:$w|@%lݜO՘\h;+Ff+P͈y]E4ہL\ԡj⸫/9)e܎=}8SL=Ul[". FOW|^d+\tudc adܜ%䋂F (6acvvz Fk;ʊ9%9%$"yT)h.; cs5vl у@(z+[K Zw/Q {nIxUҧ) Lg9q]36GQm㉙ucH]Vn)(D)-j8 ؞5D ' 1aM^8ͧv̈\y;  59AbI%5H"I*a|To`[r*~ib!7PDR,%O 1{Y&J!A\ B; : G#=嫿C+~*e]w|pH  T(KN6ꝃ{f@Hĭfr?Ȁ_?ۓIm[ArKv#b3sxz >D!ۭHqL;_0 1kgyVvYԙ'rQz7oe4.&I}лYC™zqa&Z~|EE}eQ|ZÉrkx5xl|4`˂5FqD<+f셷P|jBWd;n9&u4u~TўMV^cٻ3AK^pLucii/jLy@! ~.f1b6"1l{[_'Ѓo $]ǐEthdm'4FN^V "jq"GSȣqh62!W0`IkUE4Q,JS}\҅QOJEw-}bC P*~.vfweI>>LQt$XkCrzQ_Ԙ["m7 &?6Ԯ &Lj]4 h-/ \evѵg?q,캶04`Rh/ūX'65ֱӌ"֩_[5Ԍ|iB};z !:콸8$ YR1K(BOhUCbb 륡;؃rlvZփV `x@.iU=#st R/zNjqH29gJ! wa|r̸ZԬaԯ'MW\'f0H:&rx3X #3SAVƁ ~ϼƄmb>֛EP,'^ 8+d*B!_@vY+!rPRE IІ+a,ⱀ% "k҂9n))qCxqzWs)m#I 2F=M&Lae}،@)nX."Y6~W'EdųU9FRn ̠˜ܜyXX_ s~ OXQ4 8'Gu֞ѨH[i$`iy5=\]W؂RXL/?j̄dgE@Ku_\炫.YgEKtЯҩ`B]6Ofd{x$f=ۃ 8GRD `8U'4ź2Ž޵TOrXiaAϫ`h UuCZٝ$!80oK9+q3S% Z[Dݣ?M %r99߇oXzJ6=> I%"_;U^$ɩQфy4dOၩׁ[Rsj _B2t<_a!/h)# sp2Q4fg|ҁK)uTVRUzTro- zv;9^#::l}ER*VaB!BSJ;gJJ:NJ^AbRl+g4oTPn` nb!]+$.[^P>GIYT)߫HvNFSe#޽=vOH~PtN;XFR]%45jNCXVOe\U/TI(h_.1)+/%m!78j7riV&